More branch merging

This commit is contained in:
Anuken
2021-10-14 20:58:03 -04:00
parent ad1c75d050
commit 6b59c1cd83
108 changed files with 1018 additions and 380 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 712 B

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1295,6 +1295,7 @@ block.plated-conduit.name = Plated Conduit
block.phase-conduit.name = Phase Conduit block.phase-conduit.name = Phase Conduit
block.liquid-router.name = Liquid Router block.liquid-router.name = Liquid Router
block.liquid-tank.name = Liquid Tank block.liquid-tank.name = Liquid Tank
block.liquid-container.name = Liquid Container
block.liquid-junction.name = Liquid Junction block.liquid-junction.name = Liquid Junction
block.bridge-conduit.name = Bridge Conduit block.bridge-conduit.name = Bridge Conduit
block.rotary-pump.name = Rotary Pump block.rotary-pump.name = Rotary Pump
@@ -1506,6 +1507,7 @@ block.conduit.description = Moves liquids forward. Used in conjunction with pump
block.pulse-conduit.description = Moves liquids forward. Transports faster and stores more than standard conduits. block.pulse-conduit.description = Moves liquids forward. Transports faster and stores more than standard conduits.
block.plated-conduit.description = Moves liquids forward. Does not accept input from the sides. Does not leak. block.plated-conduit.description = Moves liquids forward. Does not accept input from the sides. Does not leak.
block.liquid-router.description = Accepts liquids from one direction and outputs them to up to 3 other directions equally. Can also store a certain amount of liquid. block.liquid-router.description = Accepts liquids from one direction and outputs them to up to 3 other directions equally. Can also store a certain amount of liquid.
block.liquid-container.description = Stores a sizeable amount of liquid. Outputs to all sides, similarly to a liquid router.
block.liquid-tank.description = Stores a large amount of liquid. Outputs to all sides, similarly to a liquid router. block.liquid-tank.description = Stores a large amount of liquid. Outputs to all sides, similarly to a liquid router.
block.liquid-junction.description = Acts as a bridge for two crossing conduits. block.liquid-junction.description = Acts as a bridge for two crossing conduits.
block.bridge-conduit.description = Transports liquids over terrain or buildings. block.bridge-conduit.description = Transports liquids over terrain or buildings.

View File

@@ -361,3 +361,10 @@
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 63345=pooled-cryofluid|block-pooled-cryofluid-ui
63344=empty|block-empty-ui
63343=liquid-container|block-liquid-container-ui
63342=deconstructor|block-deconstructor-ui
63341=constructor|block-constructor-ui
63340=large-constructor|block-large-constructor-ui
63339=payload-loader|block-payload-loader-ui
63338=payload-unloader|block-payload-unloader-ui

Binary file not shown.

20
core/assets/shaders/clouds.vert Executable file
View File

@@ -0,0 +1,20 @@
attribute vec4 a_position;
attribute vec3 a_normal;
attribute vec4 a_color;
uniform mat4 u_proj;
uniform mat4 u_trans;
uniform vec3 u_lightdir;
uniform vec3 u_ambientColor;
uniform float u_alpha;
varying vec4 v_col;
const vec3 diffuse = vec3(0.01);
void main(){
vec3 norc = u_ambientColor * (diffuse + vec3(clamp((dot(a_normal, u_lightdir) + 1.0) / 2.0, 0.0, 1.0)));
v_col = a_color * vec4(norc, u_alpha);
gl_Position = u_proj * u_trans * a_position;
}

View File

@@ -380,7 +380,7 @@ public class Vars implements Loadable{
log.log(level, text); log.log(level, text);
try{ try{
writer.write("[" + Character.toUpperCase(level.name().charAt(0)) +"] " + Log.removeColors(text) + "\n"); writer.write("[" + Character.toUpperCase(level.name().charAt(0)) + "] " + Log.removeColors(text) + "\n");
writer.flush(); writer.flush();
}catch(IOException e){ }catch(IOException e){
e.printStackTrace(); e.printStackTrace();

View File

@@ -50,6 +50,7 @@ public class Pathfinder implements Runnable{
//legs //legs
(team, tile) -> PathTile.legSolid(tile) ? impassable : 1 + (team, tile) -> PathTile.legSolid(tile) ? impassable : 1 +
(PathTile.deep(tile) ? 6000 : 0) + //leg units can now drown
(PathTile.solid(tile) ? 5 : 0), (PathTile.solid(tile) ? 5 : 0),
//water //water

View File

@@ -203,6 +203,7 @@ public class WaveSpawner{
unit.apply(StatusEffects.unmoving, 30f); unit.apply(StatusEffects.unmoving, 30f);
unit.apply(StatusEffects.invincible, 60f); unit.apply(StatusEffects.invincible, 60f);
unit.add(); unit.add();
unit.unloaded();
Events.fire(new UnitSpawnEvent(unit)); Events.fire(new UnitSpawnEvent(unit));
Call.spawnEffect(unit.x, unit.y, unit.rotation, unit.type); Call.spawnEffect(unit.x, unit.y, unit.rotation, unit.type);

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, cryofluid, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater, space, air, spawn, cliff, deepwater, water, taintedWater, deepTaintedWater, tar, slag, cryofluid, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater, space, empty,
dacite, dacite,
stoneWall, dirtWall, sporeWall, iceWall, daciteWall, sporePine, snowPine, pine, shrubs, whiteTree, whiteTreeDead, sporeCluster, stoneWall, dirtWall, sporeWall, iceWall, daciteWall, sporePine, snowPine, pine, shrubs, whiteTree, whiteTreeDead, sporeCluster,
iceSnow, sandWater, darksandWater, duneWall, sandWall, moss, sporeMoss, shale, shaleWall, shaleBoulder, sandBoulder, daciteBoulder, boulder, snowBoulder, basaltBoulder, grass, salt, iceSnow, sandWater, darksandWater, duneWall, sandWall, moss, sporeMoss, shale, shaleWall, shaleBoulder, sandBoulder, daciteBoulder, boulder, snowBoulder, basaltBoulder, grass, salt,
@@ -435,18 +435,6 @@ public class Blocks implements ContentList{
basalt.asFloor().decoration = hotrock.asFloor().decoration = darksand.asFloor().decoration = magmarock.asFloor().decoration = this; basalt.asFloor().decoration = hotrock.asFloor().decoration = darksand.asFloor().decoration = magmarock.asFloor().decoration = this;
}}; }};
moss = new Floor("moss"){{
variants = 3;
attributes.set(Attribute.spores, 0.15f);
wall = sporePine;
}};
sporeMoss = new Floor("spore-moss"){{
variants = 3;
attributes.set(Attribute.spores, 0.3f);
wall = sporeWall;
}};
metalFloor = new Floor("metal-floor", 0); metalFloor = new Floor("metal-floor", 0);
metalFloorDamaged = new Floor("metal-floor-damaged", 3); metalFloorDamaged = new Floor("metal-floor-damaged", 3);
@@ -2105,14 +2093,15 @@ public class Blocks implements ContentList{
}}; }};
constructor = new Constructor("constructor"){{ constructor = new Constructor("constructor"){{
requirements(Category.units, with(Items.thorium, 100)); requirements(Category.units, with(Items.silicon, 50, Items.thorium, 70, Items.graphite, 50));
hasPower = true; hasPower = true;
consumes.power(2f); consumes.power(2f);
size = 3; size = 3;
}}; }};
//yes this block is pretty much useless
largeConstructor = new Constructor("large-constructor"){{ largeConstructor = new Constructor("large-constructor"){{
requirements(Category.units, with(Items.thorium, 100)); requirements(Category.units, with(Items.silicon, 100, Items.thorium, 150, Items.graphite, 50, Items.phaseFabric, 40));
hasPower = true; hasPower = true;
consumes.power(2f); consumes.power(2f);
maxBlockSize = 4; maxBlockSize = 4;
@@ -2121,20 +2110,20 @@ public class Blocks implements ContentList{
}}; }};
payloadLoader = new PayloadLoader("payload-loader"){{ payloadLoader = new PayloadLoader("payload-loader"){{
requirements(Category.units, with(Items.thorium, 100)); requirements(Category.units, with(Items.graphite, 50, Items.silicon, 50, Items.copper, 100));
hasPower = true; hasPower = true;
consumes.power(2f); consumes.power(2f);
size = 3; size = 3;
}}; }};
payloadUnloader = new PayloadUnloader("payload-unloader"){{ payloadUnloader = new PayloadUnloader("payload-unloader"){{
requirements(Category.units, with(Items.thorium, 100)); requirements(Category.units, with(Items.graphite, 50, Items.silicon, 50, Items.copper, 100));
hasPower = true; hasPower = true;
consumes.power(2f); consumes.power(2f);
size = 3; size = 3;
}}; }};
//TODO deprecated //deprecated, will be removed.
blockForge = constructor; blockForge = constructor;
blockLoader = payloadLoader; blockLoader = payloadLoader;
blockUnloader = payloadUnloader; blockUnloader = payloadUnloader;

View File

@@ -14,7 +14,7 @@ public class Planets implements ContentList{
@Override @Override
public void load(){ public void load(){
sun = new Planet("sun", null, 0, 2){{ sun = new Planet("sun", null, 4){{
bloom = true; bloom = true;
accessible = false; accessible = false;
@@ -31,9 +31,13 @@ public class Planets implements ContentList{
); );
}}; }};
serpulo = new Planet("serpulo", sun, 3, 1){{ serpulo = new Planet("serpulo", sun, 1, 3){{
generator = new SerpuloPlanetGenerator(); generator = new SerpuloPlanetGenerator();
meshLoader = () -> new HexMesh(this, 6); meshLoader = () -> new HexMesh(this, 6);
cloudMeshLoader = () -> new MultiMesh(
new HexSkyMesh(this, 11, 0.15f, 0.13f, 5, new Color().set(Pal.spore).mul(0.9f).a(0.75f), 2, 0.45f, 0.9f, 0.38f),
new HexSkyMesh(this, 1, 0.6f, 0.16f, 5, Color.white.cpy().lerp(Pal.spore, 0.55f).a(0.75f), 2, 0.45f, 1f, 0.41f)
);
atmosphereColor = Color.valueOf("3c1b8f"); atmosphereColor = Color.valueOf("3c1b8f");
atmosphereRadIn = 0.02f; atmosphereRadIn = 0.02f;
atmosphereRadOut = 0.3f; atmosphereRadOut = 0.3f;

View File

@@ -157,13 +157,13 @@ public class UnitTypes implements ContentList{
rotateSpeed = 2.1f; rotateSpeed = 2.1f;
health = 9000; health = 9000;
armor = 10f; armor = 10f;
canDrown = false;
mechFrontSway = 1f; mechFrontSway = 1f;
ammoType = new ItemAmmoType(Items.thorium); ammoType = new ItemAmmoType(Items.thorium);
mechStepParticles = true; mechStepParticles = true;
mechStepShake = 0.15f; mechStepShake = 0.15f;
singleTarget = true; singleTarget = true;
drownTimeMultiplier = 4f;
weapons.add( weapons.add(
new Weapon("scepter-weapon"){{ new Weapon("scepter-weapon"){{
@@ -221,7 +221,7 @@ public class UnitTypes implements ContentList{
armor = 14f; armor = 14f;
mechStepParticles = true; mechStepParticles = true;
mechStepShake = 0.75f; mechStepShake = 0.75f;
canDrown = false; drownTimeMultiplier = 6f;
mechFrontSway = 1.9f; mechFrontSway = 1.9f;
mechSideSway = 0.6f; mechSideSway = 0.6f;
ammoType = new ItemAmmoType(Items.thorium); ammoType = new ItemAmmoType(Items.thorium);
@@ -414,13 +414,13 @@ public class UnitTypes implements ContentList{
hitSize = 24f; hitSize = 24f;
rotateSpeed = 1.8f; rotateSpeed = 1.8f;
canDrown = false;
mechFrontSway = 1f; mechFrontSway = 1f;
buildSpeed = 3f; buildSpeed = 3f;
mechStepParticles = true; mechStepParticles = true;
mechStepShake = 0.15f; mechStepShake = 0.15f;
ammoType = new PowerAmmoType(2500); ammoType = new PowerAmmoType(2500);
drownTimeMultiplier = 4f;
speed = 0.44f; speed = 0.44f;
boostMultiplier = 2.4f; boostMultiplier = 2.4f;
@@ -501,6 +501,7 @@ public class UnitTypes implements ContentList{
armor = 9f; armor = 9f;
landShake = 1.5f; landShake = 1.5f;
rotateSpeed = 1.5f; rotateSpeed = 1.5f;
drownTimeMultiplier = 6f;
commandLimit = 8; commandLimit = 8;
@@ -511,7 +512,6 @@ public class UnitTypes implements ContentList{
legTrns = 0.58f; legTrns = 0.58f;
hovering = true; hovering = true;
visualElevation = 0.2f; visualElevation = 0.2f;
allowLegStep = true;
ammoType = new PowerAmmoType(4000); ammoType = new PowerAmmoType(4000);
groundLayer = Layer.legUnit; groundLayer = Layer.legUnit;
@@ -602,7 +602,7 @@ public class UnitTypes implements ContentList{
}}; }};
atrax = new UnitType("atrax"){{ atrax = new UnitType("atrax"){{
speed = 0.54f; speed = 0.57f;
drag = 0.4f; drag = 0.4f;
hitSize = 13f; hitSize = 13f;
rotateSpeed = 3f; rotateSpeed = 3f;
@@ -618,7 +618,6 @@ public class UnitTypes implements ContentList{
armor = 3f; armor = 3f;
ammoType = new ItemAmmoType(Items.coal); ammoType = new ItemAmmoType(Items.coal);
allowLegStep = true;
visualElevation = 0.2f; visualElevation = 0.2f;
groundLayer = Layer.legUnit - 1f; groundLayer = Layer.legUnit - 1f;
@@ -632,8 +631,8 @@ public class UnitTypes implements ContentList{
shootSound = Sounds.flame; shootSound = Sounds.flame;
bullet = new LiquidBulletType(Liquids.slag){{ bullet = new LiquidBulletType(Liquids.slag){{
damage = 11; damage = 13;
speed = 2.4f; speed = 2.5f;
drag = 0.009f; drag = 0.009f;
shootEffect = Fx.shootSmall; shootEffect = Fx.shootSmall;
lifetime = 57f; lifetime = 57f;
@@ -643,11 +642,11 @@ public class UnitTypes implements ContentList{
}}; }};
spiroct = new UnitType("spiroct"){{ spiroct = new UnitType("spiroct"){{
speed = 0.48f; speed = 0.52f;
drag = 0.4f; drag = 0.4f;
hitSize = 15f; hitSize = 15f;
rotateSpeed = 3f; rotateSpeed = 3f;
health = 910; health = 940;
immunities = ObjectSet.with(StatusEffects.burning, StatusEffects.melting); immunities = ObjectSet.with(StatusEffects.burning, StatusEffects.melting);
legCount = 6; legCount = 6;
legLength = 13f; legLength = 13f;
@@ -660,7 +659,6 @@ public class UnitTypes implements ContentList{
buildSpeed = 0.75f; buildSpeed = 0.75f;
allowLegStep = true;
visualElevation = 0.3f; visualElevation = 0.3f;
groundLayer = Layer.legUnit; groundLayer = Layer.legUnit;
@@ -678,7 +676,7 @@ public class UnitTypes implements ContentList{
bullet = new SapBulletType(){{ bullet = new SapBulletType(){{
sapStrength = 0.5f; sapStrength = 0.5f;
length = 75f; length = 75f;
damage = 20; damage = 23;
shootEffect = Fx.shootSmall; shootEffect = Fx.shootSmall;
hitColor = color = Color.valueOf("bf92f9"); hitColor = color = Color.valueOf("bf92f9");
despawnEffect = Fx.none; despawnEffect = Fx.none;
@@ -698,7 +696,7 @@ public class UnitTypes implements ContentList{
bullet = new SapBulletType(){{ bullet = new SapBulletType(){{
sapStrength = 0.8f; sapStrength = 0.8f;
length = 40f; length = 40f;
damage = 16; damage = 18;
shootEffect = Fx.shootSmall; shootEffect = Fx.shootSmall;
hitColor = color = Color.valueOf("bf92f9"); hitColor = color = Color.valueOf("bf92f9");
despawnEffect = Fx.none; despawnEffect = Fx.none;
@@ -711,7 +709,7 @@ public class UnitTypes implements ContentList{
arkyid = new UnitType("arkyid"){{ arkyid = new UnitType("arkyid"){{
drag = 0.1f; drag = 0.1f;
speed = 0.6f; speed = 0.62f;
hitSize = 23f; hitSize = 23f;
health = 8000; health = 8000;
armor = 6f; armor = 6f;
@@ -733,16 +731,16 @@ public class UnitTypes implements ContentList{
legSplashDamage = 32; legSplashDamage = 32;
legSplashRange = 30; legSplashRange = 30;
drownTimeMultiplier = 2f;
hovering = true; hovering = true;
allowLegStep = true;
visualElevation = 0.65f; visualElevation = 0.65f;
groundLayer = Layer.legUnit; groundLayer = Layer.legUnit;
BulletType sapper = new SapBulletType(){{ BulletType sapper = new SapBulletType(){{
sapStrength = 0.85f; sapStrength = 0.85f;
length = 55f; length = 55f;
damage = 37; damage = 40;
shootEffect = Fx.shootSmall; shootEffect = Fx.shootSmall;
hitColor = color = Color.valueOf("bf92f9"); hitColor = color = Color.valueOf("bf92f9");
despawnEffect = Fx.none; despawnEffect = Fx.none;
@@ -820,6 +818,7 @@ public class UnitTypes implements ContentList{
lightRadius = 140f; lightRadius = 140f;
rotateSpeed = 1.9f; rotateSpeed = 1.9f;
drownTimeMultiplier = 3f;
legCount = 8; legCount = 8;
legMoveSpace = 0.8f; legMoveSpace = 0.8f;
@@ -828,7 +827,6 @@ public class UnitTypes implements ContentList{
legExtension = -20; legExtension = -20;
legBaseOffset = 8f; legBaseOffset = 8f;
landShake = 1f; landShake = 1f;
legSpeed = 0.1f;
legLengthScl = 0.93f; legLengthScl = 0.93f;
rippleScale = 3f; rippleScale = 3f;
legSpeed = 0.19f; legSpeed = 0.19f;
@@ -839,7 +837,6 @@ public class UnitTypes implements ContentList{
legSplashRange = 60; legSplashRange = 60;
hovering = true; hovering = true;
allowLegStep = true;
visualElevation = 0.95f; visualElevation = 0.95f;
groundLayer = Layer.legUnit; groundLayer = Layer.legUnit;
@@ -2287,6 +2284,7 @@ public class UnitTypes implements ContentList{
defaultController = BuilderAI::new; defaultController = BuilderAI::new;
isCounted = false; isCounted = false;
lowAltitude = true;
flying = true; flying = true;
mineSpeed = 6.5f; mineSpeed = 6.5f;
mineTier = 1; mineTier = 1;
@@ -2366,6 +2364,7 @@ public class UnitTypes implements ContentList{
defaultController = BuilderAI::new; defaultController = BuilderAI::new;
isCounted = false; isCounted = false;
lowAltitude = true;
flying = true; flying = true;
mineSpeed = 8f; mineSpeed = 8f;
mineTier = 2; mineTier = 2;

View File

@@ -151,11 +151,6 @@ public class ContentLoader{
ColorMapper.load(); ColorMapper.load();
} }
public void dispose(){
initialize(Content::dispose);
clear();
}
/** Get last piece of content created for error-handling purposes. */ /** Get last piece of content created for error-handling purposes. */
public @Nullable Content getLastAdded(){ public @Nullable Content getLastAdded(){
return lastAdded; return lastAdded;

View File

@@ -1,6 +1,7 @@
package mindustry.core; package mindustry.core;
import arc.*; import arc.*;
import arc.assets.loaders.TextureLoader.*;
import arc.files.*; import arc.files.*;
import arc.graphics.*; import arc.graphics.*;
import arc.graphics.Texture.*; import arc.graphics.Texture.*;
@@ -42,12 +43,14 @@ public class Renderer implements ApplicationListener{
public PlanetRenderer planets; public PlanetRenderer planets;
public @Nullable Bloom bloom; public @Nullable Bloom bloom;
public @Nullable FrameBuffer backgroundBuffer;
public FrameBuffer effectBuffer = new FrameBuffer(); public FrameBuffer effectBuffer = new FrameBuffer();
public boolean animateShields, drawWeather = true, drawStatus; public boolean animateShields, drawWeather = true, drawStatus;
public float weatherAlpha; public float weatherAlpha;
/** minZoom = zooming out, maxZoom = zooming in */ /** minZoom = zooming out, maxZoom = zooming in */
public float minZoom = 1.5f, maxZoom = 6f; public float minZoom = 1.5f, maxZoom = 6f;
public Seq<EnvRenderer> envRenderers = new Seq<>(); public Seq<EnvRenderer> envRenderers = new Seq<>();
public ObjectMap<String, Runnable> customBackgrounds = new ObjectMap<>();
public TextureRegion[] bubbles = new TextureRegion[16], splashes = new TextureRegion[12]; public TextureRegion[] bubbles = new TextureRegion[16], splashes = new TextureRegion[12];
private @Nullable CoreBuild landCore; private @Nullable CoreBuild landCore;
@@ -88,6 +91,10 @@ public class Renderer implements ApplicationListener{
envRenderers.add(new EnvRenderer(mask, render)); envRenderers.add(new EnvRenderer(mask, render));
} }
public void addCustomBackground(String name, Runnable render){
customBackgrounds.put(name, render);
}
@Override @Override
public void init(){ public void init(){
planets = new PlanetRenderer(); planets = new PlanetRenderer();
@@ -108,6 +115,14 @@ public class Renderer implements ApplicationListener{
t.setWrap(TextureWrap.repeat); t.setWrap(TextureWrap.repeat);
t.setFilter(TextureFilter.linear); t.setFilter(TextureFilter.linear);
}; };
Events.on(WorldLoadEvent.class, e -> {
//reset background buffer on every world load, so it can be re-cached first render
if(backgroundBuffer != null){
backgroundBuffer.dispose();
backgroundBuffer = null;
}
});
} }
@Override @Override
@@ -311,8 +326,81 @@ public class Renderer implements ApplicationListener{
Events.fire(Trigger.postDraw); Events.fire(Trigger.postDraw);
} }
private void drawBackground(){ protected void drawBackground(){
//nothing to draw currently //draw background only if there is no planet background with a skybox
if(state.rules.backgroundTexture != null && (state.rules.planetBackground == null || !state.rules.planetBackground.drawSkybox)){
if(!assets.isLoaded(state.rules.backgroundTexture, Texture.class)){
var file = assets.getFileHandleResolver().resolve(state.rules.backgroundTexture);
//don't draw invalid/non-existent backgrounds.
if(!file.exists() || !file.extEquals("png")){
return;
}
var desc = assets.load(state.rules.backgroundTexture, Texture.class, new TextureParameter(){{
wrapU = wrapV = TextureWrap.mirroredRepeat;
magFilter = minFilter = TextureFilter.linear;
}});
assets.finishLoadingAsset(desc);
}
Texture tex = assets.get(state.rules.backgroundTexture, Texture.class);
Tmp.tr1.set(tex);
Tmp.tr1.u = 0f;
Tmp.tr1.v = 0f;
float ratio = camera.width / camera.height;
float size = state.rules.backgroundScl;
Tmp.tr1.u2 = size;
Tmp.tr1.v2 = size / ratio;
float sx = 0f, sy = 0f;
if(!Mathf.zero(state.rules.backgroundSpeed)){
sx = (camera.position.x) / state.rules.backgroundSpeed;
sy = (camera.position.y) / state.rules.backgroundSpeed;
}
Tmp.tr1.scroll(sx + state.rules.backgroundOffsetX, -sy + state.rules.backgroundOffsetY);
Draw.rect(Tmp.tr1, camera.position.x, camera.position.y, camera.width, camera.height);
}
if(state.rules.planetBackground != null){
int size = Math.max(graphics.getWidth(), graphics.getHeight());
boolean resized = false;
if(backgroundBuffer == null){
resized = true;
backgroundBuffer = new FrameBuffer(size, size);
}
if(resized || backgroundBuffer.resizeCheck(size, size)){
backgroundBuffer.begin(Color.clear);
var params = state.rules.planetBackground;
//override some values
params.viewW = size;
params.viewH = size;
params.alwaysDrawAtmosphere = true;
params.drawUi = false;
planets.render(params);
backgroundBuffer.end();
}
float drawSize = Math.max(camera.width, camera.height);
Draw.rect(Draw.wrap(backgroundBuffer.getTexture()), camera.position.x, camera.position.y, drawSize, -drawSize);
}
if(state.rules.customBackgroundCallback != null && customBackgrounds.containsKey(state.rules.customBackgroundCallback)){
customBackgrounds.get(state.rules.customBackgroundCallback).run();
}
} }
void updateLandParticles(){ void updateLandParticles(){

View File

@@ -588,7 +588,7 @@ public class UI implements ApplicationListener, Loadable{
if(mag >= 1_000_000_000){ if(mag >= 1_000_000_000){
return sign + Strings.fixed(mag / 1_000_000_000f, 1) + "[gray]" + billions+ "[]"; return sign + Strings.fixed(mag / 1_000_000_000f, 1) + "[gray]" + billions+ "[]";
}else if(mag >= 1_000_000){ }else if(mag >= 1_000_000){
return sign + Strings.fixed(mag / 1_000_000f, 1) + "[gray]" +millions + "[]"; return sign + Strings.fixed(mag / 1_000_000f, 1) + "[gray]" + millions + "[]";
}else if(mag >= 10_000){ }else if(mag >= 10_000){
return number / 1000 + "[gray]" + thousands + "[]"; return number / 1000 + "[gray]" + thousands + "[]";
}else if(mag >= 1000){ }else if(mag >= 1000){

View File

@@ -8,6 +8,7 @@ import arc.math.geom.Geometry.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
import arc.util.noise.*; import arc.util.noise.*;
import mindustry.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.core.GameState.*; import mindustry.core.GameState.*;
import mindustry.ctype.*; import mindustry.ctype.*;
@@ -246,15 +247,17 @@ public class World{
if(sector.preset != null){ if(sector.preset != null){
sector.preset.generator.generate(tiles); sector.preset.generator.generate(tiles);
sector.preset.rules.get(state.rules); //apply extra rules sector.preset.rules.get(state.rules); //apply extra rules
}else{ }else if(sector.planet.generator != null){
sector.planet.generator.generate(tiles, sector); sector.planet.generator.generate(tiles, sector);
}else{
throw new RuntimeException("Sector " + sector.id + " on planet " + sector.planet.name + " has no generator or preset defined. Provide a planet generator or preset map.");
} }
//just in case //just in case
state.rules.sector = sector; state.rules.sector = sector;
}); });
//postgenerate for bases //postgenerate for bases
if(sector.preset == null){ if(sector.preset == null && sector.planet.generator != null){
sector.planet.generator.postGenerate(tiles); sector.planet.generator.postGenerate(tiles);
} }
@@ -477,12 +480,14 @@ public class World{
//TODO optimize; this is very slow and called too often! //TODO optimize; this is very slow and called too often!
public float getDarkness(int x, int y){ public float getDarkness(int x, int y){
int edgeBlend = 2;
float dark = 0; float dark = 0;
int edgeDst = Math.min(x, Math.min(y, Math.min(Math.abs(x - (tiles.width - 1)), Math.abs(y - (tiles.height - 1)))));
if(edgeDst <= edgeBlend){ if(Vars.state.rules.borderDarkness){
dark = Math.max((edgeBlend - edgeDst) * (4f / edgeBlend), dark); int edgeBlend = 2;
int edgeDst = Math.min(x, Math.min(y, Math.min(Math.abs(x - (tiles.width - 1)), Math.abs(y - (tiles.height - 1)))));
if(edgeDst <= edgeBlend){
dark = Math.max((edgeBlend - edgeDst) * (4f / edgeBlend), dark);
}
} }
if(state.hasSector() && state.getSector().preset == null){ if(state.hasSector() && state.getSector().preset == null){

View File

@@ -6,7 +6,7 @@ import mindustry.*;
import mindustry.mod.Mods.*; import mindustry.mod.Mods.*;
/** Base class for a content type that is loaded in {@link mindustry.core.ContentLoader}. */ /** Base class for a content type that is loaded in {@link mindustry.core.ContentLoader}. */
public abstract class Content implements Comparable<Content>, Disposable{ public abstract class Content implements Comparable<Content>{
public short id; public short id;
/** Info on which mod this content was loaded from. */ /** Info on which mod this content was loaded from. */
public ModContentInfo minfo = new ModContentInfo(); public ModContentInfo minfo = new ModContentInfo();
@@ -39,11 +39,6 @@ public abstract class Content implements Comparable<Content>, Disposable{
return minfo.error != null; return minfo.error != null;
} }
@Override
public void dispose(){
//does nothing by default
}
@Override @Override
public int compareTo(Content c){ public int compareTo(Content c){
return Integer.compare(id, c.id); return Integer.compare(id, c.id);

View File

@@ -129,7 +129,7 @@ public class Units{
nearby(x, y, width, height, unit -> { nearby(x, y, width, height, unit -> {
if(boolResult) return; if(boolResult) return;
if((unit.isGrounded() && !unit.type.hovering) == ground){ if((unit.isGrounded() && !unit.hovering) == ground){
unit.hitboxTile(hitrect); unit.hitboxTile(hitrect);
if(hitrect.overlaps(x, y, width, height)){ if(hitrect.overlaps(x, y, width, height)){

View File

@@ -7,6 +7,7 @@ import mindustry.gen.*;
public abstract class Ability implements Cloneable{ public abstract class Ability implements Cloneable{
public void update(Unit unit){} public void update(Unit unit){}
public void draw(Unit unit){} public void draw(Unit unit){}
public void death(Unit unit){}
public Ability copy(){ public Ability copy(){
try{ try{

View File

@@ -1,6 +1,5 @@
package mindustry.entities.comp; package mindustry.entities.comp;
import arc.func.*;
import arc.util.io.*; import arc.util.io.*;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;
import mindustry.entities.*; import mindustry.entities.*;

View File

@@ -8,6 +8,7 @@ import mindustry.annotations.Annotations.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.game.EventType.*; import mindustry.game.EventType.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.type.*;
import mindustry.world.blocks.environment.*; import mindustry.world.blocks.environment.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
@@ -16,14 +17,16 @@ import static mindustry.Vars.*;
abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
private static final Vec2 tmp1 = new Vec2(), tmp2 = new Vec2(); private static final Vec2 tmp1 = new Vec2(), tmp2 = new Vec2();
@Import float x, y, speedMultiplier; @Import float x, y, speedMultiplier, hitSize;
@Import Vec2 vel; @Import Vec2 vel;
@Import UnitType type;
@SyncLocal float elevation; @SyncLocal float elevation;
private transient boolean wasFlying; private transient boolean wasFlying;
transient boolean hovering; transient boolean hovering;
transient float drownTime; transient float drownTime;
transient float splashTimer; transient float splashTimer;
transient @Nullable Floor lastDrownFloor;
boolean checkTarget(boolean targetAir, boolean targetGround){ boolean checkTarget(boolean targetAir, boolean targetGround){
return (isGrounded() && targetGround) || (isFlying() && targetAir); return (isGrounded() && targetGround) || (isFlying() && targetAir);
@@ -41,6 +44,10 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
return isGrounded() && !hovering; return isGrounded() && !hovering;
} }
@Nullable Floor drownFloor(){
return canDrown() ? floorOn() : null;
}
boolean emitWalkSound(){ boolean emitWalkSound(){
return true; return true;
} }
@@ -90,20 +97,27 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
} }
} }
if(canDrown() && floor.isLiquid && floor.drownTime > 0){ updateDrowning();
drownTime += Time.delta / floor.drownTime; }
drownTime = Mathf.clamp(drownTime);
public void updateDrowning(){
Floor floor = drownFloor();
if(floor != null && floor.isLiquid && floor.drownTime > 0){
lastDrownFloor = floor;
drownTime += Time.delta / floor.drownTime / type.drownTimeMultiplier;
if(Mathf.chanceDelta(0.05f)){ if(Mathf.chanceDelta(0.05f)){
floor.drownUpdateEffect.at(x, y, 1f, floor.mapColor); floor.drownUpdateEffect.at(x, y, hitSize, floor.mapColor);
} }
//TODO is the netClient check necessary?
if(drownTime >= 0.999f && !net.client()){ if(drownTime >= 0.999f && !net.client()){
kill(); kill();
Events.fire(new UnitDrownEvent(self())); Events.fire(new UnitDrownEvent(self()));
} }
}else{ }else{
drownTime = Mathf.lerpDelta(drownTime, 0f, 0.03f); drownTime -= Time.delta / 50f;
} }
drownTime = Mathf.clamp(drownTime);
} }
} }

View File

@@ -7,7 +7,6 @@ import mindustry.annotations.Annotations.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.ui.*;
import mindustry.world.*; import mindustry.world.*;
@EntityDef(value = LaunchCorec.class, serialize = false) @EntityDef(value = LaunchCorec.class, serialize = false)

View File

@@ -9,6 +9,7 @@ import mindustry.annotations.Annotations.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.entities.*; import mindustry.entities.*;
import mindustry.entities.EntityCollisions.*; import mindustry.entities.EntityCollisions.*;
import mindustry.game.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.type.*; import mindustry.type.*;
@@ -18,22 +19,30 @@ import mindustry.world.blocks.environment.*;
abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{
@Import float x, y; @Import float x, y;
@Import UnitType type; @Import UnitType type;
@Import Team team;
transient Leg[] legs = {}; transient Leg[] legs = {};
transient float totalLength; transient float totalLength;
transient float moveSpace; transient float moveSpace;
transient float baseRotation; transient float baseRotation;
transient Floor lastDeepFloor;
@Replace @Replace
@Override @Override
public SolidPred solidity(){ public SolidPred solidity(){
return !type.allowLegStep ? EntityCollisions::solid : EntityCollisions::legsSolid; return type.allowLegStep ? EntityCollisions::legsSolid : EntityCollisions::solid;
} }
@Override @Override
@Replace @Replace
public int pathType(){ public int pathType(){
return Pathfinder.costLegs; return type.allowLegStep ? Pathfinder.costGround : Pathfinder.costLegs;
}
@Override
@Replace
public Floor drownFloor(){
return lastDeepFloor;
} }
@Override @Override
@@ -41,10 +50,18 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{
resetLegs(); resetLegs();
} }
@Override
public void unloaded(){
resetLegs(1f);
}
public void resetLegs(){ public void resetLegs(){
resetLegs(type.legLength);
}
public void resetLegs(float legLength){
float rot = baseRotation; float rot = baseRotation;
int count = type.legCount; int count = type.legCount;
float legLength = type.legLength;
this.legs = new Leg[count]; this.legs = new Leg[count];
@@ -85,6 +102,9 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{
Vec2 moveOffset = Tmp.v4.trns(rot, trns); Vec2 moveOffset = Tmp.v4.trns(rot, trns);
boolean moving = moving(); boolean moving = moving();
lastDeepFloor = null;
int deeps = 0;
for(int i = 0; i < legs.length; i++){ for(int i = 0; i < legs.length; i++){
float dstRot = legAngle(rot, i); float dstRot = legAngle(rot, i);
Vec2 baseOffset = Tmp.v5.trns(dstRot, type.legBaseOffset).add(x, y); Vec2 baseOffset = Tmp.v5.trns(dstRot, type.legBaseOffset).add(x, y);
@@ -105,11 +125,16 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{
l.moving = move; l.moving = move;
l.stage = moving ? stageF % 1f : Mathf.lerpDelta(l.stage, 0f, 0.1f); l.stage = moving ? stageF % 1f : Mathf.lerpDelta(l.stage, 0f, 0.1f);
Floor floor = Vars.world.floorWorld(l.base.x, l.base.y);
if(floor.isDeep()){
deeps ++;
lastDeepFloor = floor;
}
if(l.group != group){ if(l.group != group){
//create effect when transitioning to a group it can't move in //create effect when transitioning to a group it can't move in
if(!move && i % div == l.group){ if(!move && i % div == l.group){
Floor floor = Vars.world.floorWorld(l.base.x, l.base.y);
if(floor.isLiquid){ if(floor.isLiquid){
floor.walkEffect.at(l.base.x, l.base.y, type.rippleScale, floor.mapColor); floor.walkEffect.at(l.base.x, l.base.y, type.rippleScale, floor.mapColor);
floor.walkSound.at(x, y, 1f, floor.walkSoundVolume); floor.walkSound.at(x, y, 1f, floor.walkSoundVolume);
@@ -123,7 +148,7 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{
} }
if(type.legSplashDamage > 0){ if(type.legSplashDamage > 0){
Damage.damage(team(), l.base.x, l.base.y, type.legSplashRange, type.legSplashDamage, false, true); Damage.damage(team, l.base.x, l.base.y, type.legSplashRange, type.legSplashDamage, false, true);
} }
} }
@@ -148,6 +173,11 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{
l.joint.lerpDelta(jointDest, moveSpeed / 4f); l.joint.lerpDelta(jointDest, moveSpeed / 4f);
} }
//when at least 1 leg is touching land, it can't drown
if(deeps != legs.length){
lastDeepFloor = null;
}
} }
/** @return outwards facing angle of leg at the specified index. */ /** @return outwards facing angle of leg at the specified index. */

View File

@@ -10,6 +10,7 @@ import mindustry.entities.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.blocks.environment.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
@@ -62,6 +63,21 @@ abstract class MechComp implements Posc, Flyingc, Hitboxc, Unitc, Mechc, Elevati
walkExtension = extendScl; walkExtension = extendScl;
} }
@Replace
@Override
public @Nullable Floor drownFloor(){
//large mechs can only drown when all the nearby floors are deep
if(hitSize >= 12 && canDrown()){
for(Point2 p : Geometry.d8){
Floor f = world.floorWorld(x + p.x * tilesize, y + p.y * tilesize);
if(!f.isDeep()){
return null;
}
}
}
return canDrown() ? floorOn() : null;
}
public float walkExtend(boolean scaled){ public float walkExtend(boolean scaled){
//now ranges from -maxExtension to maxExtension*3 //now ranges from -maxExtension to maxExtension*3

View File

@@ -13,7 +13,6 @@ import mindustry.entities.*;
import mindustry.game.EventType.*; import mindustry.game.EventType.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.blocks.payloads.*; import mindustry.world.blocks.payloads.*;
@@ -123,6 +122,7 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{
//decrement count to prevent double increment //decrement count to prevent double increment
if(!u.isAdded()) u.team.data().updateCount(u.type, -1); if(!u.isAdded()) u.team.data().updateCount(u.type, -1);
u.add(); u.add();
u.unloaded();
return true; return true;
} }

View File

@@ -45,12 +45,18 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
boolean spawnedByCore; boolean spawnedByCore;
double flag; double flag;
transient float shadowAlpha = -1f;
transient Seq<Ability> abilities = new Seq<>(0); transient Seq<Ability> abilities = new Seq<>(0);
transient float healTime; transient float healTime;
private transient float resupplyTime = Mathf.random(10f); private transient float resupplyTime = Mathf.random(10f);
private transient boolean wasPlayer; private transient boolean wasPlayer;
private transient boolean wasHealed; private transient boolean wasHealed;
/** Called when this unit was unloaded from a factory or spawn point. */
public void unloaded(){
}
/** Move based on preferred unit movement type. */ /** Move based on preferred unit movement type. */
public void movePref(Vec2 movement){ public void movePref(Vec2 movement){
if(type.omniMovement){ if(type.omniMovement){
@@ -520,6 +526,12 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
} }
} }
if(abilities.size > 0){
for(Ability a : abilities){
a.death(self());
}
}
remove(); remove();
} }

View File

@@ -6,6 +6,7 @@ import arc.util.*;
import arc.util.serialization.*; import arc.util.serialization.*;
import arc.util.serialization.Json.*; import arc.util.serialization.Json.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.graphics.g3d.*;
import mindustry.io.*; import mindustry.io.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.type.Weather.*; import mindustry.type.Weather.*;
@@ -117,8 +118,22 @@ public class Rules{
public @Nullable String modeName; public @Nullable String modeName;
/** Whether cores incinerate items when full, just like in the campaign. */ /** Whether cores incinerate items when full, just like in the campaign. */
public boolean coreIncinerates = false; public boolean coreIncinerates = false;
/** If false, borders fade out into darkness. Only use with custom backgrounds!*/
public boolean borderDarkness = true;
/** special tags for additional info. */ /** special tags for additional info. */
public StringMap tags = new StringMap(); public StringMap tags = new StringMap();
/** Name of callback to call for background rendering in mods; see Renderer#addCustomBackground. Runs last. */
public @Nullable String customBackgroundCallback;
/** path to background texture with extension (e.g. "sprites/space.png")*/
public @Nullable String backgroundTexture;
/** background texture move speed scaling - bigger numbers mean slower movement. 0 to disable. */
public float backgroundSpeed = 27000f;
/** background texture scaling factor */
public float backgroundScl = 1f;
/** background UV offsets */
public float backgroundOffsetX = 0.1f, backgroundOffsetY = 0.1f;
/** Parameters for planet rendered in the background. Cannot be changed once a map is loaded. */
public @Nullable PlanetParams planetBackground;
/** Copies this ruleset exactly. Not efficient at all, do not use often. */ /** Copies this ruleset exactly. Not efficient at all, do not use often. */
public Rules copy(){ public Rules copy(){
@@ -140,6 +155,10 @@ public class Rules{
} }
} }
public boolean hasEnv(int env){
return (environment & env) != 0;
}
public float unitBuildSpeed(Team team){ public float unitBuildSpeed(Team team){
return unitBuildSpeedMultiplier * teams.get(team).unitBuildSpeedMultiplier; return unitBuildSpeedMultiplier * teams.get(team).unitBuildSpeedMultiplier;
} }

View File

@@ -82,10 +82,11 @@ public class Universe{
} }
} }
if(state.hasSector()){ if(state.hasSector() && state.getSector().planet.updateLighting){
var planet = state.getSector().planet;
//update sector light //update sector light
float light = state.getSector().getLight(); float light = state.getSector().getLight();
float alpha = Mathf.clamp(Mathf.map(light, 0f, 0.8f, 0.3f, 1f)); float alpha = Mathf.clamp(Mathf.map(light, planet.lightSrcFrom, planet.lightSrcTo, planet.lightDstFrom, planet.lightDstTo));
//assign and map so darkness is not 100% dark //assign and map so darkness is not 100% dark
state.rules.ambientLight.a = 1f - alpha; state.rules.ambientLight.a = 1f - alpha;

View File

@@ -10,27 +10,29 @@ public class IndexedRenderer implements Disposable{
private static final int vsize = 5; private static final int vsize = 5;
private final Shader program = new Shader( private final Shader program = new Shader(
"attribute vec4 a_position;\n" + """
"attribute vec4 a_color;\n" + attribute vec4 a_position;
"attribute vec2 a_texCoord0;\n" + attribute vec4 a_color;
"uniform mat4 u_projTrans;\n" + attribute vec2 a_texCoord0;
"varying vec4 v_color;\n" + uniform mat4 u_projTrans;
"varying vec2 v_texCoords;\n" + varying vec4 v_color;
varying vec2 v_texCoords;
void main(){
v_color = a_color;
v_color.a = v_color.a * (255.0/254.0);
v_texCoords = a_texCoord0;
gl_Position = u_projTrans * a_position;
}
""",
"void main(){\n" + """
" v_color = a_color;\n" + varying lowp vec4 v_color;
" v_color.a = v_color.a * (255.0/254.0);\n" + varying vec2 v_texCoords;
" v_texCoords = a_texCoord0;\n" + uniform sampler2D u_texture;
" gl_Position = u_projTrans * a_position;\n" + void main(){
"}", gl_FragColor = v_color * texture2D(u_texture, v_texCoords);
}
"varying lowp vec4 v_color;\n" + """
"varying vec2 v_texCoords;\n" +
"uniform sampler2D u_texture;\n" +
"void main(){\n" +
" gl_FragColor = v_color * texture2D(u_texture, v_texCoords);\n" +
"}"
); );
private Mesh mesh; private Mesh mesh;
private float[] tmpVerts = new float[vsize * 6]; private float[] tmpVerts = new float[vsize * 6];

View File

@@ -191,7 +191,10 @@ public class LightRenderer{
Draw.color(); Draw.color();
buffer.begin(Color.clear); buffer.begin(Color.clear);
Draw.sort(false);
Gl.blendEquationSeparate(Gl.funcAdd, Gl.max); Gl.blendEquationSeparate(Gl.funcAdd, Gl.max);
//apparently necessary
Blending.normal.apply();
for(Runnable run : lights){ for(Runnable run : lights){
run.run(); run.run();
@@ -202,6 +205,7 @@ public class LightRenderer{
Draw.rect(circleRegion, cir.x, cir.y, cir.radius * 2, cir.radius * 2); Draw.rect(circleRegion, cir.x, cir.y, cir.radius * 2, cir.radius * 2);
} }
Draw.reset(); Draw.reset();
Draw.sort(true);
buffer.end(); buffer.end();
Gl.blendEquationSeparate(Gl.funcAdd, Gl.funcAdd); Gl.blendEquationSeparate(Gl.funcAdd, Gl.funcAdd);

View File

@@ -23,6 +23,7 @@ public class Shaders{
public static LightShader light; public static LightShader light;
public static SurfaceShader water, mud, tar, slag, cryofluid, 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 PlanetGridShader planetGrid; public static PlanetGridShader planetGrid;
public static AtmosphereShader atmosphere; public static AtmosphereShader atmosphere;
public static MeshShader mesh; public static MeshShader mesh;
@@ -56,6 +57,7 @@ public class Shaders{
// } // }
//}; //};
planet = new PlanetShader(); planet = new PlanetShader();
clouds = new CloudShader();
planetGrid = new PlanetGridShader(); planetGrid = new PlanetGridShader();
atmosphere = new AtmosphereShader(); atmosphere = new AtmosphereShader();
unlit = new LoadShader("planet", "unlit"); unlit = new LoadShader("planet", "unlit");
@@ -94,6 +96,7 @@ public class Shaders{
public Vec3 lightDir = new Vec3(1, 1, 1).nor(); public Vec3 lightDir = new Vec3(1, 1, 1).nor();
public Color ambientColor = Color.white.cpy(); public Color ambientColor = Color.white.cpy();
public Vec3 camDir = new Vec3(); public Vec3 camDir = new Vec3();
public Planet planet;
public PlanetShader(){ public PlanetShader(){
super("planet", "planet"); super("planet", "planet");
@@ -101,7 +104,7 @@ public class Shaders{
@Override @Override
public void apply(){ public void apply(){
camDir.set(renderer.planets.cam.direction).rotate(Vec3.Y, renderer.planets.planet.getRotation()); camDir.set(renderer.planets.cam.direction).rotate(Vec3.Y, planet.getRotation());
setUniformf("u_lightdir", lightDir); setUniformf("u_lightdir", lightDir);
setUniformf("u_ambientColor", ambientColor.r, ambientColor.g, ambientColor.b); setUniformf("u_ambientColor", ambientColor.r, ambientColor.g, ambientColor.b);
@@ -109,6 +112,27 @@ public class Shaders{
} }
} }
public static class CloudShader extends LoadShader{
public Vec3 lightDir = new Vec3(1, 1, 1).nor();
public Color ambientColor = Color.white.cpy();
public Vec3 camDir = new Vec3();
public float alpha = 1f;
public Planet planet;
public CloudShader(){
super("planet", "clouds");
}
@Override
public void apply(){
camDir.set(renderer.planets.cam.direction).rotate(Vec3.Y, planet.getRotation());
setUniformf("u_alpha", alpha);
setUniformf("u_lightdir", lightDir);
setUniformf("u_ambientColor", ambientColor.r, ambientColor.g, ambientColor.b);
}
}
public static class MeshShader extends LoadShader{ public static class MeshShader extends LoadShader{
public MeshShader(){ public MeshShader(){
@@ -176,6 +200,7 @@ public class Shaders{
public static class BlockBuildShader extends LoadShader{ public static class BlockBuildShader extends LoadShader{
public float progress; public float progress;
public TextureRegion region = new TextureRegion(); public TextureRegion region = new TextureRegion();
public float time;
public BlockBuildShader(){ public BlockBuildShader(){
super("blockbuild", "default"); super("blockbuild", "default");
@@ -186,7 +211,7 @@ public class Shaders{
setUniformf("u_progress", progress); setUniformf("u_progress", progress);
setUniformf("u_uv", region.u, region.v); setUniformf("u_uv", region.u, region.v);
setUniformf("u_uv2", region.u2, region.v2); setUniformf("u_uv2", region.u2, region.v2);
setUniformf("u_time", Time.time); setUniformf("u_time", time);
setUniformf("u_texsize", region.texture.width, region.texture.height); setUniformf("u_texsize", region.texture.width, region.texture.height);
} }
} }

View File

@@ -396,7 +396,7 @@ public class Voronoi{
private void clipLine(Edge e){ private void clipLine(Edge e){
float pxmin, pxmax, pymin, pymax; float pxmin, pxmax, pymin, pymax;
Site s1, s2; Site s1, s2;
float x1 = 0, x2 = 0, y1 = 0, y2 = 0; float x1, x2, y1, y2;
x1 = e.reg[0].coord.x; x1 = e.reg[0].coord.x;
x2 = e.reg[1].coord.x; x2 = e.reg[1].coord.x;

View File

@@ -0,0 +1,7 @@
package mindustry.graphics.g3d;
import arc.math.geom.*;
public interface GenericMesh{
void render(PlanetParams params, Mat3D projection, Mat3D transform);
}

View File

@@ -15,8 +15,12 @@ public class HexMesh extends PlanetMesh{
super(planet, MeshBuilder.buildHex(mesher, divisions, false, planet.radius, 0.2f), shader); super(planet, MeshBuilder.buildHex(mesher, divisions, false, planet.radius, 0.2f), shader);
} }
public HexMesh(){
}
@Override @Override
public void preRender(){ public void preRender(PlanetParams params){
Shaders.planet.planet = planet;
Shaders.planet.lightDir.set(planet.solarSystem.position).sub(planet.position).rotate(Vec3.Y, planet.getRotation()).nor(); Shaders.planet.lightDir.set(planet.solarSystem.position).sub(planet.position).rotate(Vec3.Y, planet.getRotation()).nor();
Shaders.planet.ambientColor.set(planet.solarSystem.lightColor); Shaders.planet.ambientColor.set(planet.solarSystem.lightColor);
} }

View File

@@ -0,0 +1,60 @@
package mindustry.graphics.g3d;
import arc.graphics.*;
import arc.math.geom.*;
import arc.util.*;
import arc.util.noise.*;
import mindustry.graphics.*;
import mindustry.type.*;
public class HexSkyMesh extends PlanetMesh{
static Mat3D mat = new Mat3D();
public float speed = 0f;
public HexSkyMesh(Planet planet, int seed, float speed, float radius, int divisions, Color color, int octaves, float persistence, float scl, float thresh){
super(planet, MeshBuilder.buildHex(new HexMesher(){
@Override
public float getHeight(Vec3 position){
return 1f;
}
@Override
public Color getColor(Vec3 position){
return color;
}
@Override
public boolean skip(Vec3 position){
return Simplex.noise3d(planet.id + seed, octaves, persistence, scl, position.x, position.y * 3f, position.z) >= thresh;
}
}, divisions, false, planet.radius, radius), Shaders.clouds);
this.speed = speed;
}
public HexSkyMesh(){
}
public float relRot(){
return Time.globalTime * speed / 40f;
}
@Override
public void render(PlanetParams params, Mat3D projection, Mat3D transform){
preRender(params);
shader.bind();
shader.setUniformMatrix4("u_proj", projection.val);
shader.setUniformMatrix4("u_trans", mat.setToTranslation(planet.position).rotate(Vec3.Y, planet.getRotation() + relRot()).val);
shader.apply();
mesh.render(shader, Gl.triangles);
}
@Override
public void preRender(PlanetParams params){
Shaders.clouds.planet = planet;
Shaders.clouds.lightDir.set(planet.solarSystem.position).sub(planet.position).rotate(Vec3.Y, planet.getRotation() + relRot()).nor();
Shaders.clouds.ambientColor.set(planet.solarSystem.lightColor);
Shaders.clouds.alpha = 1f - params.uiAlpha;
}
}

View File

@@ -0,0 +1,22 @@
package mindustry.graphics.g3d;
import arc.math.geom.*;
//TODO maybe this is a bad idea
/** A GenericMesh that wraps and applies an additional transform to a generic mesh. */
public class MatMesh implements GenericMesh{
private static final Mat3D tmp = new Mat3D();
GenericMesh mesh;
Mat3D mat;
public MatMesh(GenericMesh mesh, Mat3D mat){
this.mesh = mesh;
this.mat = mat;
}
@Override
public void render(PlanetParams params, Mat3D projection, Mat3D transform){
mesh.render(params, projection, tmp.set(transform).mul(mat));
}
}

View File

@@ -0,0 +1,18 @@
package mindustry.graphics.g3d;
import arc.math.geom.*;
public class MultiMesh implements GenericMesh{
GenericMesh[] meshes;
public MultiMesh(GenericMesh... meshes){
this.meshes = meshes;
}
@Override
public void render(PlanetParams params, Mat3D projection, Mat3D transform){
for(var v : meshes){
v.render(params, projection, transform);
}
}
}

View File

@@ -0,0 +1,43 @@
package mindustry.graphics.g3d;
import arc.graphics.*;
import arc.math.geom.*;
import arc.util.noise.*;
import mindustry.graphics.*;
import mindustry.type.*;
public class NoiseMesh extends HexMesh{
public NoiseMesh(Planet planet, int seed, int divisions, Color color, float radius, int octaves, float persistence, float scale, float mag){
this.planet = planet;
this.shader = Shaders.planet;
this.mesh = MeshBuilder.buildHex(new HexMesher(){
@Override
public float getHeight(Vec3 position){
return Simplex.noise3d(planet.id + seed, octaves, persistence, scale, 5f + position.x, 5f + position.y, 5f + position.z) * mag;
}
@Override
public Color getColor(Vec3 position){
return color;
}
}, divisions, false, radius, 0.2f);
}
/** Two-color variant. */
public NoiseMesh(Planet planet, int seed, int divisions, float radius, int octaves, float persistence, float scale, float mag, Color color1, Color color2, int coct, float cper, float cscl, float cthresh){
this.planet = planet;
this.shader = Shaders.planet;
this.mesh = MeshBuilder.buildHex(new HexMesher(){
@Override
public float getHeight(Vec3 position){
return Simplex.noise3d(planet.id + seed, octaves, persistence, scale, 5f + position.x, 5f + position.y, 5f + position.z) * mag;
}
@Override
public Color getColor(Vec3 position){
return Simplex.noise3d(planet.id + seed + 1, coct, cper, cscl, 5f + position.x, 5f + position.y, 5f + position.z) > cthresh ? color2 : color1;
}
}, divisions, false, radius, 0.2f);
}
}

View File

@@ -221,6 +221,8 @@ public class PlanetGrid{
} }
public static class Ptile{ public static class Ptile{
public static final Ptile empty = new Ptile(0, 0);
public int id; public int id;
public int edgeCount; public int edgeCount;

View File

@@ -3,14 +3,13 @@ package mindustry.graphics.g3d;
import arc.graphics.*; import arc.graphics.*;
import arc.graphics.gl.*; import arc.graphics.gl.*;
import arc.math.geom.*; import arc.math.geom.*;
import arc.util.*;
import mindustry.type.*; import mindustry.type.*;
/** Defines a mesh that is rendered for a planet. Subclasses provide a mesh and a shader. */ /** Defines a mesh that is rendered for a planet. Subclasses provide a mesh and a shader. */
public abstract class PlanetMesh implements Disposable{ public abstract class PlanetMesh implements GenericMesh{
protected final Mesh mesh; protected Mesh mesh;
protected final Planet planet; protected Planet planet;
protected final Shader shader; protected Shader shader;
public PlanetMesh(Planet planet, Mesh mesh, Shader shader){ public PlanetMesh(Planet planet, Mesh mesh, Shader shader){
this.planet = planet; this.planet = planet;
@@ -18,20 +17,21 @@ public abstract class PlanetMesh implements Disposable{
this.shader = shader; this.shader = shader;
} }
/** Should be overridden to set up any shader parameters such as planet position, normals, etc. */ public PlanetMesh(){}
public abstract void preRender();
public void render(Mat3D projection, Mat3D transform){ /** Should be overridden to set up any shader parameters such as planet position, normals, etc.
preRender(); * @param params*/
public void preRender(PlanetParams params){
}
@Override
public void render(PlanetParams params, Mat3D projection, Mat3D transform){
preRender(params);
shader.bind(); shader.bind();
shader.setUniformMatrix4("u_proj", projection.val); shader.setUniformMatrix4("u_proj", projection.val);
shader.setUniformMatrix4("u_trans", transform.val); shader.setUniformMatrix4("u_trans", transform.val);
shader.apply(); shader.apply();
mesh.render(shader, Gl.triangles); mesh.render(shader, Gl.triangles);
} }
@Override
public void dispose(){
mesh.dispose();
}
} }

View File

@@ -0,0 +1,40 @@
package mindustry.graphics.g3d;
import arc.math.geom.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.graphics.g3d.PlanetRenderer.*;
import mindustry.type.*;
/** Parameters for rendering a solar system. */
public class PlanetParams{
/** Camera direction relative to the planet. Length is determined by zoom. */
public Vec3 camPos = new Vec3(0f, 0f, 4f);
/** Camera up vector. */
public Vec3 camUp = new Vec3(0f, 1f, 0f);
/** the unit length direction vector of the camera **/
public Vec3 camDir = new Vec3(0, 0, -1);
/** The sun/main planet of the solar system from which everything is rendered. */
public Planet solarSystem = Planets.sun;
/** Planet being looked at. */
public Planet planet = Planets.serpulo;
/** Zoom relative to planet. */
public float zoom = 1f;
/** Alpha of orbit rings and other UI elements. */
public float uiAlpha = 1f;
/** If false, orbit and sector grid are not drawn. */
public boolean drawUi = false;
/** If true, a space skybox is drawn. */
public boolean drawSkybox = true;
/** Handles drawing details. */
public @Nullable transient PlanetInterfaceRenderer renderer;
/** Viewport size. <=0 to use screen size. Do not change in rules. */
public transient int viewW = -1, viewH = -1;
/** If true, atmosphere will be drawn regardless of player options. */
public transient boolean alwaysDrawAtmosphere = false;
//TODO:
//- blur
//- darken
}

View File

@@ -9,7 +9,6 @@ import arc.math.*;
import arc.math.geom.*; import arc.math.geom.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
import mindustry.content.*;
import mindustry.game.EventType.*; import mindustry.game.EventType.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.graphics.g3d.PlanetGrid.*; import mindustry.graphics.g3d.PlanetGrid.*;
@@ -25,25 +24,15 @@ public class PlanetRenderer implements Disposable{
private static final Seq<Vec3> points = new Seq<>(); private static final Seq<Vec3> points = new Seq<>();
/** Camera direction relative to the planet. Length is determined by zoom. */
public final Vec3 camPos = new Vec3();
/** The sun/main planet of the solar system from which everything is rendered. */
public final Planet solarSystem = Planets.sun;
/** Planet being looked at. */
public Planet planet = Planets.serpulo;
/** Camera used for rendering. */ /** Camera used for rendering. */
public Camera3D cam = new Camera3D(); public final Camera3D cam = new Camera3D();
/** Raw vertex batch. */ /** Raw vertex batch. */
public final VertexBatch3D batch = new VertexBatch3D(20000, false, true, 0); public final VertexBatch3D batch = new VertexBatch3D(20000, false, true, 0);
public float zoom = 1f;
public float orbitAlpha = 1f;
private final Mesh[] outlines = new Mesh[10]; private final Mesh[] outlines = new Mesh[10];
public final PlaneBatch3D projector = new PlaneBatch3D(); public final PlaneBatch3D projector = new PlaneBatch3D();
public final Mat3D mat = new Mat3D(); public final Mat3D mat = new Mat3D();
public final FrameBuffer buffer = new FrameBuffer(2, 2, true); public final FrameBuffer buffer = new FrameBuffer(2, 2, true);
public PlanetInterfaceRenderer irenderer;
public final Bloom bloom = new Bloom(Core.graphics.getWidth()/4, Core.graphics.getHeight()/4, true, false){{ public final Bloom bloom = new Bloom(Core.graphics.getWidth()/4, Core.graphics.getHeight()/4, true, false){{
setThreshold(0.8f); setThreshold(0.8f);
@@ -55,16 +44,13 @@ public class PlanetRenderer implements Disposable{
public final CubemapMesh skybox = new CubemapMesh(new Cubemap("cubemaps/stars/")); public final CubemapMesh skybox = new CubemapMesh(new Cubemap("cubemaps/stars/"));
public PlanetRenderer(){ public PlanetRenderer(){
camPos.set(0, 0f, camLength);
projector.setScaling(1f / 150f); projector.setScaling(1f / 150f);
cam.fov = 60f; cam.fov = 60f;
cam.far = 150f; cam.far = 150f;
} }
/** Render the entire planet scene to the screen. */ /** Render the entire planet scene to the screen. */
public void render(PlanetInterfaceRenderer irenderer){ public void render(PlanetParams params){
this.irenderer = irenderer;
Draw.flush(); Draw.flush();
Gl.clear(Gl.depthBufferBit); Gl.clear(Gl.depthBufferBit);
Gl.enable(Gl.depthTest); Gl.enable(Gl.depthTest);
@@ -73,49 +59,63 @@ public class PlanetRenderer implements Disposable{
Gl.enable(Gl.cullFace); Gl.enable(Gl.cullFace);
Gl.cullFace(Gl.back); Gl.cullFace(Gl.back);
int w = params.viewW <= 0 ? Core.graphics.getWidth() : params.viewW;
int h = params.viewH <= 0 ? Core.graphics.getHeight() : params.viewH;
bloom.blending = !params.drawSkybox;
//lock to up vector so it doesn't get confusing //lock to up vector so it doesn't get confusing
cam.up.set(Vec3.Y); cam.up.set(Vec3.Y);
cam.resize(Core.graphics.getWidth(), Core.graphics.getHeight()); cam.resize(w, h);
camPos.setLength(planet.radius * camLength + (zoom-1f) * planet.radius * 2); params.camPos.setLength((params.planet.radius + params.planet.camRadius) * camLength + (params.zoom-1f) * (params.planet.radius + params.planet.camRadius) * 2);
cam.position.set(planet.position).add(camPos); cam.position.set(params.planet.position).add(params.camPos);
cam.lookAt(planet.position); //cam.up.set(params.camUp); //TODO broken
cam.lookAt(params.planet.position);
cam.update(); cam.update();
//write back once it changes.
params.camUp.set(cam.up);
params.camDir.set(cam.direction);
projector.proj(cam.combined); projector.proj(cam.combined);
batch.proj(cam.combined); batch.proj(cam.combined);
Events.fire(Trigger.universeDrawBegin); Events.fire(Trigger.universeDrawBegin);
beginBloom(); //begin bloom
bloom.resize(w, h);
bloom.capture();
//render skybox at 0,0,0 if(params.drawSkybox){
Vec3 lastPos = Tmp.v31.set(cam.position); //render skybox at 0,0,0
cam.position.setZero(); Vec3 lastPos = Tmp.v31.set(cam.position);
cam.update(); cam.position.setZero();
cam.update();
Gl.depthMask(false); Gl.depthMask(false);
skybox.render(cam.combined); skybox.render(cam.combined);
Gl.depthMask(true); Gl.depthMask(true);
cam.position.set(lastPos); cam.position.set(lastPos);
cam.update(); cam.update();
}
Events.fire(Trigger.universeDraw); Events.fire(Trigger.universeDraw);
renderPlanet(solarSystem); renderPlanet(params.solarSystem, params);
renderTransparent(params.solarSystem, params);
renderTransparent(solarSystem); bloom.render();
endBloom();
Events.fire(Trigger.universeDrawEnd); Events.fire(Trigger.universeDrawEnd);
Gl.enable(Gl.blend); Gl.enable(Gl.blend);
irenderer.renderProjections(planet); if(params.renderer != null){
params.renderer.renderProjections(params.planet);
}
Gl.disable(Gl.cullFace); Gl.disable(Gl.cullFace);
Gl.disable(Gl.depthTest); Gl.disable(Gl.depthTest);
@@ -123,68 +123,64 @@ public class PlanetRenderer implements Disposable{
cam.update(); cam.update();
} }
public void beginBloom(){ public void renderPlanet(Planet planet, PlanetParams params){
bloom.resize(Core.graphics.getWidth(), Core.graphics.getHeight());
bloom.capture();
}
public void endBloom(){
bloom.render();
}
public void renderPlanet(Planet planet){
if(!planet.visible()) return; if(!planet.visible()) return;
cam.update(); cam.update();
if(cam.frustum.containsSphere(planet.position, planet.clipRadius)){ if(cam.frustum.containsSphere(planet.position, planet.clipRadius)){
//render planet at offsetted position in the world //render planet at offsetted position in the world
planet.draw(cam.combined, planet.getTransform(mat)); planet.draw(params, cam.combined, planet.getTransform(mat));
} }
renderOrbit(planet);
for(Planet child : planet.children){ for(Planet child : planet.children){
renderPlanet(child); renderPlanet(child, params);
} }
} }
public void renderTransparent(Planet planet){ public void renderTransparent(Planet planet, PlanetParams params){
if(!planet.visible()) return; if(!planet.visible()) return;
if(planet.hasGrid() && planet == this.planet){ planet.drawClouds(params, cam.combined, planet.getTransform(mat));
renderSectors(planet);
if(planet.hasGrid() && planet == params.planet && params.drawUi){
renderSectors(planet, params);
} }
if(cam.frustum.containsSphere(planet.position, planet.clipRadius) && planet.parent != null && planet.hasAtmosphere && Core.settings.getBool("atmosphere")){ if(cam.frustum.containsSphere(planet.position, planet.clipRadius) && planet.parent != null && planet.hasAtmosphere && (params.alwaysDrawAtmosphere || Core.settings.getBool("atmosphere"))){
planet.drawAtmosphere(atmosphere, cam); planet.drawAtmosphere(atmosphere, cam);
} }
planet.drawClouds(cam.combined, planet.getTransform(mat));
for(Planet child : planet.children){ for(Planet child : planet.children){
renderTransparent(child); renderTransparent(child, params);
}
batch.proj(cam.combined);
if(params.drawUi){
renderOrbit(planet, params);
} }
} }
public void renderOrbit(Planet planet){ public void renderOrbit(Planet planet, PlanetParams params){
if(planet.parent == null || !planet.visible() || orbitAlpha <= 0.02f) return; if(planet.parent == null || !planet.visible() || params.uiAlpha <= 0.02f || !planet.drawOrbit) return;
Vec3 center = planet.parent.position; Vec3 center = planet.parent.position;
float radius = planet.orbitRadius; float radius = planet.orbitRadius;
int points = (int)(radius * 10); int points = (int)(radius * 10);
Angles.circleVectors(points, radius, (cx, cy) -> batch.vertex(Tmp.v32.set(center).add(cx, 0, cy), Pal.gray.write(Tmp.c1).a(orbitAlpha))); Angles.circleVectors(points, radius, (cx, cy) -> batch.vertex(Tmp.v32.set(center).add(cx, 0, cy), Pal.gray.write(Tmp.c1).a(params.uiAlpha)));
batch.flush(Gl.lineLoop); batch.flush(Gl.lineLoop);
} }
public void renderSectors(Planet planet){ public void renderSectors(Planet planet, PlanetParams params){
if(orbitAlpha <= 0.02f) return; if(params.uiAlpha <= 0.02f) return;
//apply transformed position //apply transformed position
batch.proj().mul(planet.getTransform(mat)); batch.proj().mul(planet.getTransform(mat));
irenderer.renderSectors(planet); if(params.renderer != null){
params.renderer.renderSectors(planet);
}
//render sector grid //render sector grid
Mesh mesh = outline(planet.grid.size); Mesh mesh = outline(planet.grid.size);
@@ -262,12 +258,12 @@ public class PlanetRenderer implements Disposable{
} }
public void setPlane(Sector sector){ public void setPlane(Sector sector){
float rotation = -planet.getRotation(); float rotation = -sector.planet.getRotation();
float length = 0.01f; float length = 0.01f;
projector.setPlane( projector.setPlane(
//origin on sector position //origin on sector position
Tmp.v33.set(sector.tile.v).setLength(outlineRad + length).rotate(Vec3.Y, rotation).add(planet.position), Tmp.v33.set(sector.tile.v).setLength(outlineRad + length).rotate(Vec3.Y, rotation).add(sector.planet.position),
//face up //face up
sector.plane.project(Tmp.v32.set(sector.tile.v).add(Vec3.Y)).sub(sector.tile.v).rotate(Vec3.Y, rotation).nor(), sector.plane.project(Tmp.v32.set(sector.tile.v).add(Vec3.Y)).sub(sector.tile.v).rotate(Vec3.Y, rotation).nor(),
//right vector //right vector

View File

@@ -8,9 +8,4 @@ public class ShaderSphereMesh extends PlanetMesh{
public ShaderSphereMesh(Planet planet, Shader shader, int divisions){ public ShaderSphereMesh(Planet planet, Shader shader, int divisions){
super(planet, MeshBuilder.buildIcosphere(divisions, planet.radius), shader); super(planet, MeshBuilder.buildIcosphere(divisions, planet.radius), shader);
} }
@Override
public void preRender(){
}
} }

View File

@@ -25,9 +25,4 @@ public class SunMesh extends HexMesh{
} }
}, divisions, Shaders.unlit); }, divisions, Shaders.unlit);
} }
@Override
public void preRender(){
//do absolutely nothing
}
} }

View File

@@ -163,6 +163,19 @@ public class JsonIO{
} }
}); });
json.setSerializer(Planet.class, new Serializer<>(){
@Override
public void write(Json json, Planet object, Class knownType){
json.writeValue(object.name);
}
@Override
public Planet read(Json json, JsonValue jsonData, Class type){
Planet block = Vars.content.getByName(ContentType.planet, jsonData.asString());
return block == null ? Planets.serpulo : block;
}
});
json.setSerializer(Weather.class, new Serializer<>(){ json.setSerializer(Weather.class, new Serializer<>(){
@Override @Override
public void write(Json json, Weather object, Class knownType){ public void write(Json json, Weather object, Class knownType){

View File

@@ -56,7 +56,10 @@ public abstract class SaveFileReader{
"water", "shallow-water", "water", "shallow-water",
"slag", "molten-slag", "slag", "molten-slag",
"cryofluidmixer", "cryofluid-mixer" "cryofluidmixer", "cryofluid-mixer",
"block-forge", "constructor",
"block-unloader", "payload-unloader",
"block-loader", "payload-loader"
); );
public static final ObjectMap<String, String> modContentNameMap = ObjectMap.of( public static final ObjectMap<String, String> modContentNameMap = ObjectMap.of(

View File

@@ -123,6 +123,11 @@ public abstract class PlanetGenerator extends BasicGenerator implements HexMeshe
return 3200; return 3200;
} }
public int getSectorSize(Sector sector){
int res = (int)(sector.rect.radius * getSizeScl());
return res % 2 == 0 ? res : res + 1;
}
public void generate(Tiles tiles, Sector sec){ public void generate(Tiles tiles, Sector sec){
this.tiles = tiles; this.tiles = tiles;
this.sector = sec; this.sector = sec;

View File

@@ -218,14 +218,8 @@ public class ClassMap{
classes.put("SwitchBuild", mindustry.world.blocks.logic.SwitchBlock.SwitchBuild.class); classes.put("SwitchBuild", mindustry.world.blocks.logic.SwitchBlock.SwitchBuild.class);
classes.put("BallisticSilo", mindustry.world.blocks.payloads.BallisticSilo.class); classes.put("BallisticSilo", mindustry.world.blocks.payloads.BallisticSilo.class);
classes.put("BallisticSiloBuild", mindustry.world.blocks.payloads.BallisticSilo.BallisticSiloBuild.class); classes.put("BallisticSiloBuild", mindustry.world.blocks.payloads.BallisticSilo.BallisticSiloBuild.class);
classes.put("BlockForge", mindustry.world.blocks.payloads.BlockForge.class);
classes.put("BlockForgeBuild", mindustry.world.blocks.payloads.BlockForge.BlockForgeBuild.class);
classes.put("BlockLoader", mindustry.world.blocks.payloads.BlockLoader.class);
classes.put("BlockLoaderBuild", mindustry.world.blocks.payloads.BlockLoader.BlockLoaderBuild.class);
classes.put("BlockProducer", mindustry.world.blocks.payloads.BlockProducer.class); classes.put("BlockProducer", mindustry.world.blocks.payloads.BlockProducer.class);
classes.put("BlockProducerBuild", mindustry.world.blocks.payloads.BlockProducer.BlockProducerBuild.class); classes.put("BlockProducerBuild", mindustry.world.blocks.payloads.BlockProducer.BlockProducerBuild.class);
classes.put("BlockUnloader", mindustry.world.blocks.payloads.BlockUnloader.class);
classes.put("BlockUnloaderBuild", mindustry.world.blocks.payloads.BlockUnloader.BlockUnloaderBuild.class);
classes.put("BuildPayload", mindustry.world.blocks.payloads.BuildPayload.class); classes.put("BuildPayload", mindustry.world.blocks.payloads.BuildPayload.class);
classes.put("NuclearWarhead", mindustry.world.blocks.payloads.NuclearWarhead.class); classes.put("NuclearWarhead", mindustry.world.blocks.payloads.NuclearWarhead.class);
classes.put("NuclearWarheadBuild", mindustry.world.blocks.payloads.NuclearWarhead.NuclearWarheadBuild.class); classes.put("NuclearWarheadBuild", mindustry.world.blocks.payloads.NuclearWarhead.NuclearWarheadBuild.class);

View File

@@ -55,6 +55,21 @@ public class ItemSeq implements Iterable<ItemStack>, JsonSerializable{
return out; return out;
} }
public ItemStack[] toArray(){
int count = 0;
for(int value : values){
if(value != 0) count++;
}
ItemStack[] result = new ItemStack[count];
int index = 0;
for(int i = 0; i < values.length; i++){
if(values[i] != 0){
result[index ++] = new ItemStack(Vars.content.item(i), values[i]);
}
}
return result;
}
public void min(int number){ public void min(int number){
for(Item item : Vars.content.items()){ for(Item item : Vars.content.items()){
set(item, Math.min(get(item), number)); set(item, Math.min(get(item), number));
@@ -90,6 +105,12 @@ public class ItemSeq implements Iterable<ItemStack>, JsonSerializable{
itemModule.each(this::add); itemModule.each(this::add);
} }
public void add(ItemStack[] stacks){
for(var s : stacks){
add(s);
}
}
public void add(ItemSeq seq){ public void add(ItemSeq seq){
seq.each(this::add); seq.each(this::add);
} }

View File

@@ -18,14 +18,12 @@ import mindustry.maps.generators.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
public class Planet extends UnlockableContent{ public class Planet extends UnlockableContent{
/** Default spacing between planet orbits in world units. */
private static final float orbitSpacing = 11f;
/** intersect() temp var. */ /** intersect() temp var. */
private static final Vec3 intersectResult = new Vec3(); private static final Vec3 intersectResult = new Vec3();
/** Mesh used for rendering. Created on load() - will be null on the server! */ /** Mesh used for rendering. Created on load() - will be null on the server! */
public @Nullable PlanetMesh mesh; public @Nullable GenericMesh mesh;
/** Mesh used for rendering planet clouds. Null if no clouds are present. */ /** Mesh used for rendering planet clouds. Null if no clouds are present. */
public @Nullable PlanetMesh cloudMesh; public @Nullable GenericMesh cloudMesh;
/** Position in global coordinates. Will be 0,0,0 until the Universe updates it. */ /** Position in global coordinates. Will be 0,0,0 until the Universe updates it. */
public Vec3 position = new Vec3(); public Vec3 position = new Vec3();
/** Grid used for the sectors on the planet. Null if this planet can't be landed on. */ /** Grid used for the sectors on the planet. Null if this planet can't be landed on. */
@@ -33,9 +31,17 @@ public class Planet extends UnlockableContent{
/** Generator that will make the planet. Can be null for planets that don't need to be landed on. */ /** Generator that will make the planet. Can be null for planets that don't need to be landed on. */
public @Nullable PlanetGenerator generator; public @Nullable PlanetGenerator generator;
/** Array of sectors; directly maps to tiles in the grid. */ /** Array of sectors; directly maps to tiles in the grid. */
public Seq<Sector> sectors; public Seq<Sector> sectors = new Seq<>();
/** Default spacing between planet orbits in world units. This is defined per-parent! */
public float orbitSpacing = 12f;
/** Radius of this planet's sphere. Does not take into account satellites. */ /** Radius of this planet's sphere. Does not take into account satellites. */
public float radius; public float radius;
/** Camera radius offset. */
public float camRadius;
/** Minimum camera zoom value. */
public float minZoom = 0.5f;
/** Whether to draw the orbital circle. */
public boolean drawOrbit = true;
/** Atmosphere radius adjustment parameters. */ /** Atmosphere radius adjustment parameters. */
public float atmosphereRadIn = 0, atmosphereRadOut = 0.3f; public float atmosphereRadIn = 0, atmosphereRadOut = 0.3f;
/** Frustrum sphere clip radius. */ /** Frustrum sphere clip radius. */
@@ -48,12 +54,18 @@ public class Planet extends UnlockableContent{
public float orbitTime; public float orbitTime;
/** Time for the planet to perform a full revolution, in seconds. One day. */ /** Time for the planet to perform a full revolution, in seconds. One day. */
public float rotateTime = 24f * 60f; public float rotateTime = 24f * 60f;
/** Random orbit angle offset to prevent planets from starting out in a line. */
public float orbitOffset;
/** Approx. radius of one sector. */ /** Approx. radius of one sector. */
public float sectorApproxRadius; public float sectorApproxRadius;
/** Whether this planet is tidally locked relative to its parent - see https://en.wikipedia.org/wiki/Tidal_locking */ /** Whether this planet is tidally locked relative to its parent - see https://en.wikipedia.org/wiki/Tidal_locking */
public boolean tidalLock = false; public boolean tidalLock = false;
/** Whether this planet is listed in the planet access UI. **/ /** Whether this planet is listed in the planet access UI. **/
public boolean accessible = true; public boolean accessible = true;
/** If true, a day/night cycle is simulated. */
public boolean updateLighting = true;
/** Day/night cycle parameters. */
public float lightSrcFrom = 0f, lightSrcTo = 0.8f, lightDstFrom = 0.2f, lightDstTo = 1f;
/** The default starting sector displayed to the map dialog. */ /** The default starting sector displayed to the map dialog. */
public int startSector = 0; public int startSector = 0;
/** Whether the bloom render effect is enabled. */ /** Whether the bloom render effect is enabled. */
@@ -77,32 +89,20 @@ public class Planet extends UnlockableContent{
/** Satellites orbiting this planet. */ /** Satellites orbiting this planet. */
public Seq<Satellite> satellites = new Seq<>(); public Seq<Satellite> satellites = new Seq<>();
/** Loads the mesh. Clientside only. Defaults to a boring sphere mesh. */ /** Loads the mesh. Clientside only. Defaults to a boring sphere mesh. */
protected Prov<PlanetMesh> meshLoader = () -> new ShaderSphereMesh(this, Shaders.unlit, 2), cloudMeshLoader = () -> null; protected Prov<GenericMesh> meshLoader = () -> new ShaderSphereMesh(this, Shaders.unlit, 2), cloudMeshLoader = () -> null;
public Planet(String name, Planet parent, int sectorSize, float radius){ public Planet(String name, Planet parent, float radius){
super(name); super(name);
this.radius = radius; this.radius = radius;
this.parent = parent; this.parent = parent;
this.orbitOffset = Mathf.randomSeed(id, 360);
if(sectorSize > 0){
grid = PlanetGrid.create(sectorSize);
sectors = new Seq<>(grid.tiles.length);
for(int i = 0; i < grid.tiles.length; i++){
sectors.add(new Sector(this, grid.tiles[i]));
}
sectorApproxRadius = sectors.first().tile.v.dst(sectors.first().tile.corners[0].v);
}else{
sectors = new Seq<>();
}
//total radius is initially just the radius //total radius is initially just the radius
totalRadius += radius; totalRadius = radius;
//get orbit radius by extending past the parent's total radius //get orbit radius by extending past the parent's total radius
orbitRadius = parent == null ? 0f : (parent.totalRadius + orbitSpacing + totalRadius); orbitRadius = parent == null ? 0f : (parent.totalRadius + parent.orbitSpacing + totalRadius);
//orbit time is based on radius [kepler's third law] //orbit time is based on radius [kepler's third law]
orbitTime = Mathf.pow(orbitRadius, 1.5f) * 1000; orbitTime = Mathf.pow(orbitRadius, 1.5f) * 1000;
@@ -117,6 +117,21 @@ public class Planet extends UnlockableContent{
for(solarSystem = this; solarSystem.parent != null; solarSystem = solarSystem.parent); for(solarSystem = this; solarSystem.parent != null; solarSystem = solarSystem.parent);
} }
public Planet(String name, Planet parent, float radius, int sectorSize){
this(name, parent, radius);
if(sectorSize > 0){
grid = PlanetGrid.create(sectorSize);
sectors.ensureCapacity(grid.tiles.length);
for(int i = 0; i < grid.tiles.length; i++){
sectors.add(new Sector(this, grid.tiles[i]));
}
sectorApproxRadius = sectors.first().tile.v.dst(sectors.first().tile.corners[0].v);
}
}
public @Nullable Sector getLastSector(){ public @Nullable Sector getLastSector(){
if(sectors.isEmpty()){ if(sectors.isEmpty()){
return null; return null;
@@ -137,6 +152,11 @@ public class Planet extends UnlockableContent{
return grid != null && generator != null && sectors.size > 0; return grid != null && generator != null && sectors.size > 0;
} }
/** @return whether this planet has any sectors to land on. */
public boolean isLandable(){
return sectors.size > 0;
}
public void updateTotalRadius(){ public void updateTotalRadius(){
totalRadius = radius; totalRadius = radius;
for(Planet planet : children){ for(Planet planet : children){
@@ -151,9 +171,7 @@ public class Planet extends UnlockableContent{
/** Calculates orbital rotation based on universe time.*/ /** Calculates orbital rotation based on universe time.*/
public float getOrbitAngle(){ public float getOrbitAngle(){
//applies random offset to prevent planets from starting out in a line return (orbitOffset + universe.secondsf() / (orbitTime / 360f)) % 360f;
float offset = Mathf.randomSeed(id, 360);
return (offset + universe.secondsf() / (orbitTime / 360f)) % 360f;
} }
/** Calulates rotation on own axis based on universe time.*/ /** Calulates rotation on own axis based on universe time.*/
@@ -212,9 +230,6 @@ public class Planet extends UnlockableContent{
/** Regenerates the planet mesh. For debugging only. */ /** Regenerates the planet mesh. For debugging only. */
public void reloadMesh(){ public void reloadMesh(){
if(mesh != null){
mesh.dispose();
}
mesh = meshLoader.get(); mesh = meshLoader.get();
} }
@@ -246,14 +261,6 @@ public class Planet extends UnlockableContent{
clipRadius = Math.max(clipRadius, radius + atmosphereRadOut + 0.5f); clipRadius = Math.max(clipRadius, radius + atmosphereRadOut + 0.5f);
} }
@Override
public void dispose(){
if(mesh != null){
mesh.dispose();
mesh = null;
}
}
/** Gets a sector a tile position. */ /** Gets a sector a tile position. */
public Sector getSector(Ptile tile){ public Sector getSector(Ptile tile){
return sectors.get(tile.id); return sectors.get(tile.id);
@@ -294,8 +301,8 @@ public class Planet extends UnlockableContent{
return visible; return visible;
} }
public void draw(Mat3D projection, Mat3D transform){ public void draw(PlanetParams params, Mat3D projection, Mat3D transform){
mesh.render(projection, transform); mesh.render(params, projection, transform);
} }
public void drawAtmosphere(Mesh atmosphere, Camera3D cam){ public void drawAtmosphere(Mesh atmosphere, Camera3D cam){
@@ -316,9 +323,9 @@ public class Planet extends UnlockableContent{
Gl.depthMask(true); Gl.depthMask(true);
} }
public void drawClouds(Mat3D projection, Mat3D transform){ public void drawClouds(PlanetParams params, Mat3D projection, Mat3D transform){
if(cloudMesh != null){ if(cloudMesh != null){
cloudMesh.render(projection, transform); cloudMesh.render(params, projection, transform);
} }
} }
} }

View File

@@ -40,7 +40,12 @@ public class Sector{
this.planet = planet; this.planet = planet;
this.tile = tile; this.tile = tile;
this.plane = new Plane(); this.plane = new Plane();
this.rect = makeRect(); //empty sector tile needs a special rect
if(tile.corners.length == 0){
rect = new SectorRect(1f, Vec3.Zero.cpy(), Vec3.Y.cpy(), Vec3.X.cpy(), 0f);
}else{
this.rect = makeRect();
}
this.id = tile.id; this.id = tile.id;
} }
@@ -156,9 +161,7 @@ public class Sector{
/** @return the sector size, in tiles */ /** @return the sector size, in tiles */
public int getSize(){ public int getSize(){
if(planet.generator == null) return 1; return planet.generator == null ? 1 : planet.generator.getSectorSize(this);
int res = (int)(rect.radius * planet.generator.getSizeScl());
return res % 2 == 0 ? res : res + 1;
} }
public void removeItems(ItemSeq items){ public void removeItems(ItemSeq items){

View File

@@ -71,9 +71,13 @@ public class UnitType extends UnlockableContent{
public int commandLimit = 8; public int commandLimit = 8;
public float commandRadius = 150f; public float commandRadius = 150f;
public float visualElevation = -1f; public float visualElevation = -1f;
/** If true and this is a legged unit, this unit can walk over blocks. */
public boolean allowLegStep = false; public boolean allowLegStep = false;
/** If true, this unit cannot drown, and will not be affected by the floor under it. */
public boolean hovering = false; public boolean hovering = false;
public boolean omniMovement = true; public boolean omniMovement = true;
public boolean showHeal = true;
public Color healColor = Pal.heal;
public Effect fallEffect = Fx.fallSmoke; public Effect fallEffect = Fx.fallSmoke;
public Effect fallThrusterEffect = Fx.fallSmoke; public Effect fallThrusterEffect = Fx.fallSmoke;
public Effect deathExplosionEffect = Fx.dynamicExplosion; public Effect deathExplosionEffect = Fx.dynamicExplosion;
@@ -112,13 +116,14 @@ public class UnitType extends UnlockableContent{
public float dpsEstimate = -1; public float dpsEstimate = -1;
public float clipSize = -1; public float clipSize = -1;
public boolean canDrown = true, naval = false; public boolean canDrown = true, naval = false;
public float drownTimeMultiplier = 1f;
public float engineOffset = 5f, engineSize = 2.5f; public float engineOffset = 5f, engineSize = 2.5f;
public float strafePenalty = 0.5f; public float strafePenalty = 0.5f;
public float hitSize = 6f; public float hitSize = 6f;
public float itemOffsetY = 3f; public float itemOffsetY = 3f;
public float lightRadius = -1f, lightOpacity = 0.6f; public float lightRadius = -1f, lightOpacity = 0.6f;
public Color lightColor = Pal.powerLight; public Color lightColor = Pal.powerLight;
public boolean drawCell = true, drawItems = true, drawShields = true; public boolean drawCell = true, drawItems = true, drawShields = true, drawBody = true;
public int trailLength = 3; public int trailLength = 3;
public float trailX = 4f, trailY = -3f, trailScl = 1f; public float trailX = 4f, trailY = -3f, trailScl = 1f;
/** Whether the unit can heal blocks. Initialized in init() */ /** Whether the unit can heal blocks. Initialized in init() */
@@ -135,7 +140,9 @@ public class UnitType extends UnlockableContent{
softShadowRegion, jointRegion, footRegion, legBaseRegion, baseJointRegion, outlineRegion; softShadowRegion, jointRegion, footRegion, legBaseRegion, baseJointRegion, outlineRegion;
public TextureRegion[] wreckRegions; public TextureRegion[] wreckRegions;
protected float buildTime = -1f;
protected @Nullable ItemStack[] cachedRequirements; protected @Nullable ItemStack[] cachedRequirements;
protected @Nullable ItemStack[] totalRequirements;
public UnitType(String name){ public UnitType(String name){
super(name); super(name);
@@ -312,6 +319,8 @@ public class UnitType extends UnlockableContent{
Unit example = constructor.get(); Unit example = constructor.get();
allowLegStep = example instanceof Legsc;
//water preset //water preset
if(example instanceof WaterMovec){ if(example instanceof WaterMovec){
naval = true; naval = true;
@@ -323,6 +332,10 @@ public class UnitType extends UnlockableContent{
} }
} }
if(flying){
envEnabled |= Env.space;
}
if(lightRadius == -1){ if(lightRadius == -1){
lightRadius = Math.max(60f, hitSize * 2.3f); lightRadius = Math.max(60f, hitSize * 2.3f);
} }
@@ -475,25 +488,72 @@ public class UnitType extends UnlockableContent{
} }
} }
/** @return the time required to build this unit, as a value that takes into account reconstructors */
public float getBuildTime(){
getTotalRequirements();
return buildTime;
}
/** @return all items needed to build this unit, including reconstructor steps. */
public ItemStack[] getTotalRequirements(){
if(totalRequirements == null){
UnitType[] ret = {null};
float[] timeret = {0f};
ItemStack[] result = getRequirements(ret, timeret);
//prevents stack overflow if requirements are circular and result != null
totalRequirements = ItemStack.empty;
if(result != null){
ItemSeq total = new ItemSeq();
total.add(result);
if(ret[0] != null){
total.add(ret[0].getTotalRequirements());
}
totalRequirements = total.toArray();
}
for(var stack : totalRequirements){
buildTime += stack.item.cost * stack.amount;
}
}
return totalRequirements;
}
/** @return item requirements based on reconstructors or factories found; returns previous unit in array if provided */
public @Nullable ItemStack[] getRequirements(@Nullable UnitType[] prevReturn, @Nullable float[] timeReturn){
var rec = (Reconstructor)content.blocks().find(b -> b instanceof Reconstructor re && re.upgrades.contains(u -> u[1] == this));
if(rec != null && rec.consumes.has(ConsumeType.item) && rec.consumes.get(ConsumeType.item) instanceof ConsumeItems ci){
if(prevReturn != null){
prevReturn[0] = rec.upgrades.find(u -> u[1] == this)[0];
}
if(timeReturn != null){
timeReturn[0] = rec.constructTime;
}
return ci.items;
}else{
var factory = (UnitFactory)content.blocks().find(u -> u instanceof UnitFactory uf && uf.plans.contains(p -> p.unit == this));
if(factory != null){
var plan = factory.plans.find(p -> p.unit == this);
if(timeReturn != null){
timeReturn[0] = plan.time;
}
return plan.requirements;
}
}
return null;
}
@Override @Override
public ItemStack[] researchRequirements(){ public ItemStack[] researchRequirements(){
if(cachedRequirements != null){ if(cachedRequirements != null){
return cachedRequirements; return cachedRequirements;
} }
ItemStack[] stacks = null; ItemStack[] stacks = getRequirements(null, null);
//calculate costs based on reconstructors or factories found
Block rec = content.blocks().find(b -> b instanceof Reconstructor re && re.upgrades.contains(u -> u[1] == this));
if(rec != null && rec.consumes.has(ConsumeType.item) && rec.consumes.get(ConsumeType.item) instanceof ConsumeItems ci){
stacks = ci.items;
}else{
UnitFactory factory = (UnitFactory)content.blocks().find(u -> u instanceof UnitFactory uf && uf.plans.contains(p -> p.unit == this));
if(factory != null){
stacks = factory.plans.find(p -> p.unit == this).requirements;
}
}
if(stacks != null){ if(stacks != null){
ItemStack[] out = new ItemStack[stacks.length]; ItemStack[] out = new ItemStack[stacks.length];
@@ -557,10 +617,10 @@ public class UnitType extends UnlockableContent{
Draw.z(z); Draw.z(z);
drawOutline(unit); if(drawBody) drawOutline(unit);
drawWeaponOutlines(unit); drawWeaponOutlines(unit);
if(engineSize > 0) drawEngine(unit); if(engineSize > 0) drawEngine(unit);
drawBody(unit); if(drawBody) drawBody(unit);
if(drawCell) drawCell(unit); if(drawCell) drawCell(unit);
drawWeapons(unit); drawWeapons(unit);
if(drawItems) drawItems(unit); if(drawItems) drawItems(unit);
@@ -623,14 +683,25 @@ public class UnitType extends UnlockableContent{
} }
public void drawShadow(Unit unit){ public void drawShadow(Unit unit){
Draw.color(Pal.shadow); float e = Math.max(unit.elevation, visualElevation) * (1f - unit.drownTime);
float e = Math.max(unit.elevation, visualElevation); float x = unit.x + shadowTX * e, y = unit.y + shadowTY * e;
Floor floor = world.floorWorld(x, y);
float dest = floor.canShadow ? 1f : 0f;
//yes, this updates state in draw()... which isn't a problem, because I don't want it to be obvious anyway
unit.shadowAlpha = unit.shadowAlpha < 0 ? dest : Mathf.approachDelta(unit.shadowAlpha, dest, 0.11f);
Draw.color(Pal.shadow, Pal.shadow.a * unit.shadowAlpha);
Draw.rect(shadowRegion, unit.x + shadowTX * e, unit.y + shadowTY * e, unit.rotation - 90); Draw.rect(shadowRegion, unit.x + shadowTX * e, unit.y + shadowTY * e, unit.rotation - 90);
Draw.color(); Draw.color();
} }
public void drawSoftShadow(Unit unit){ public void drawSoftShadow(Unit unit){
Draw.color(0, 0, 0, 0.4f); drawSoftShadow(unit, 1f);
}
public void drawSoftShadow(Unit unit, float alpha){
Draw.color(0, 0, 0, 0.4f * alpha);
float rad = 1.6f; float rad = 1.6f;
float size = Math.max(region.width, region.height) * Draw.scl; float size = Math.max(region.width, region.height) * Draw.scl;
Draw.rect(softShadowRegion, unit, size * rad * Draw.xscl, size * rad * Draw.yscl, unit.rotation - 90); Draw.rect(softShadowRegion, unit, size * rad * Draw.xscl, size * rad * Draw.yscl, unit.rotation - 90);
@@ -719,16 +790,11 @@ public class UnitType extends UnlockableContent{
Draw.reset(); Draw.reset();
} }
public void applyOutlineColor(Unit unit){
if(unit.isBoss()){
Draw.mixcol(unit.team.color, Mathf.absin(7f, 1f));
}
}
public void drawOutline(Unit unit){ public void drawOutline(Unit unit){
Draw.reset(); Draw.reset();
if(Core.atlas.isFound(outlineRegion)){ if(Core.atlas.isFound(outlineRegion)){
applyColor(unit);
applyOutlineColor(unit); applyOutlineColor(unit);
Draw.rect(outlineRegion, unit.x, unit.y, unit.rotation - 90); Draw.rect(outlineRegion, unit.x, unit.y, unit.rotation - 90);
Draw.reset(); Draw.reset();
@@ -764,14 +830,16 @@ public class UnitType extends UnlockableContent{
public <T extends Unit & Legsc> void drawLegs(T unit){ public <T extends Unit & Legsc> void drawLegs(T unit){
applyColor(unit); applyColor(unit);
Tmp.c3.set(Draw.getMixColor());
Leg[] legs = unit.legs(); Leg[] legs = unit.legs();
float ssize = footRegion.width * Draw.scl * 1.5f; float ssize = footRegion.width * Draw.scl * 1.5f;
float rotation = unit.baseRotation(); float rotation = unit.baseRotation();
float invDrown = 1f - unit.drownTime;
for(Leg leg : legs){ for(Leg leg : legs){
Drawf.shadow(leg.base.x, leg.base.y, ssize); Drawf.shadow(leg.base.x, leg.base.y, ssize, invDrown);
} }
//legs are drawn front first //legs are drawn front first
@@ -787,13 +855,15 @@ public class UnitType extends UnlockableContent{
Tmp.v1.set(leg.base).sub(leg.joint).inv().setLength(legExtension); Tmp.v1.set(leg.base).sub(leg.joint).inv().setLength(legExtension);
if(leg.moving && visualElevation > 0){ if(leg.moving && visualElevation > 0){
float scl = visualElevation; float scl = visualElevation * invDrown;
float elev = Mathf.slope(1f - leg.stage) * scl; float elev = Mathf.slope(1f - leg.stage) * scl;
Draw.color(Pal.shadow); Draw.color(Pal.shadow);
Draw.rect(footRegion, leg.base.x + shadowTX * elev, leg.base.y + shadowTY * elev, position.angleTo(leg.base)); Draw.rect(footRegion, leg.base.x + shadowTX * elev, leg.base.y + shadowTY * elev, position.angleTo(leg.base));
Draw.color(); Draw.color();
} }
Draw.mixcol(Tmp.c3, Tmp.c3.a);
Draw.rect(footRegion, leg.base.x, leg.base.y, position.angleTo(leg.base)); Draw.rect(footRegion, leg.base.x, leg.base.y, position.angleTo(leg.base));
Lines.stroke(legRegion.height * Draw.scl * flips); Lines.stroke(legRegion.height * Draw.scl * flips);
@@ -848,8 +918,8 @@ public class UnitType extends UnlockableContent{
Draw.mixcol(Color.white, unit.hitTime); Draw.mixcol(Color.white, unit.hitTime);
if(floor.isLiquid){ if(unit.lastDrownFloor != null){
Draw.color(Color.white, floor.mapColor, unit.drownTime() * 0.4f); Draw.color(Color.white, Tmp.c1.set(unit.lastDrownFloor.mapColor).mul(0.83f), unit.drownTime * 0.9f);
}else{ }else{
Draw.color(Color.white); Draw.color(Color.white);
} }
@@ -859,13 +929,25 @@ public class UnitType extends UnlockableContent{
Draw.mixcol(); Draw.mixcol();
} }
public void applyOutlineColor(Unit unit){
if(unit.isBoss()){
Draw.mixcol(unit.team.color, Mathf.absin(7f, 1f));
}
if(unit.drownTime > 0 && unit.lastDrownFloor != null){
Draw.color(Color.white, Tmp.c1.set(unit.lastDrownFloor.mapColor).mul(0.8f), unit.drownTime * 0.9f);
}
}
public void applyColor(Unit unit){ public void applyColor(Unit unit){
Draw.color(); Draw.color();
Tmp.c1.set(Color.white).lerp(Pal.heal, Mathf.clamp(unit.healTime - unit.hitTime)); if(showHeal){
Tmp.c1.set(Color.white).lerp(healColor, Mathf.clamp(unit.healTime - unit.hitTime));
}
Draw.mixcol(Tmp.c1, Math.max(unit.hitTime, Mathf.clamp(unit.healTime))); Draw.mixcol(Tmp.c1, Math.max(unit.hitTime, Mathf.clamp(unit.healTime)));
if(unit.drownTime > 0 && unit.floorOn().isDeep()){ if(unit.drownTime > 0 && unit.lastDrownFloor != null){
Draw.mixcol(unit.floorOn().mapColor, unit.drownTime * 0.8f); Draw.mixcol(Tmp.c1.set(unit.lastDrownFloor.mapColor).mul(0.83f), unit.drownTime * 0.9f);
} }
} }

View File

@@ -26,7 +26,7 @@ public class Weapon implements Cloneable{
static int sequenceNum = 0; static int sequenceNum = 0;
/** displayed weapon region */ /** displayed weapon region */
public String name = ""; public String name;
/** bullet shot */ /** bullet shot */
public BulletType bullet = Bullets.standardCopper; public BulletType bullet = Bullets.standardCopper;
/** shell ejection effect */ /** shell ejection effect */

View File

@@ -148,6 +148,8 @@ public class Weather extends UnlockableContent{
Draw.rect(region, x, y, size, size, rotation); Draw.rect(region, x, y, size, size, rotation);
} }
} }
Draw.reset();
} }
public static void drawRain(float sizeMin, float sizeMax, float xspeed, float yspeed, float density, float intensity, float stroke, Color color){ public static void drawRain(float sizeMin, float sizeMax, float xspeed, float yspeed, float density, float intensity, float stroke, Color color){

View File

@@ -11,11 +11,12 @@ import static mindustry.Vars.*;
/** Class for handling menus and notifications across the network. Unstable API! */ /** Class for handling menus and notifications across the network. Unstable API! */
public class Menus{ public class Menus{
private static IntMap<MenuListener> menuListeners = new IntMap<>(); private static final Seq<MenuListener> menuListeners = new Seq<>();
/** Register a *global* menu listener. If no option is chosen, the option is returned as -1. */ /** Register a *global* menu listener. If no option is chosen, the option is returned as -1. */
public static void registerMenu(int id, MenuListener listener){ public static int registerMenu(MenuListener listener){
menuListeners.put(id, listener); menuListeners.add(listener);
return menuListeners.size - 1;
} }
//do not invoke any of the methods below directly, use Call //do not invoke any of the methods below directly, use Call
@@ -30,7 +31,7 @@ public class Menus{
@Remote(targets = Loc.both, called = Loc.both) @Remote(targets = Loc.both, called = Loc.both)
public static void menuChoose(@Nullable Player player, int menuId, int option){ public static void menuChoose(@Nullable Player player, int menuId, int option){
if(player != null && menuListeners.containsKey(menuId)){ if(player != null && menuId >= 0 && menuId < menuListeners.size){
Events.fire(new MenuOptionChooseEvent(player, menuId, option)); Events.fire(new MenuOptionChooseEvent(player, menuId, option));
menuListeners.get(menuId).get(player, option); menuListeners.get(menuId).get(player, option);
} }

View File

@@ -512,7 +512,7 @@ public class JoinDialog extends BaseDialog{
void safeConnect(String ip, int port, int version){ void safeConnect(String ip, int port, int version){
if(version != Version.build && Version.build != -1 && version != -1){ if(version != Version.build && Version.build != -1 && version != -1){
ui.showInfo("[scarlet]" + (version > Version.build ? KickReason.clientOutdated : KickReason.serverOutdated).toString() + "\n[]" + ui.showInfo("[scarlet]" + (version > Version.build ? KickReason.clientOutdated : KickReason.serverOutdated) + "\n[]" +
Core.bundle.format("server.versions", Version.build, version)); Core.bundle.format("server.versions", Version.build, version));
}else{ }else{
connect(ip, port); connect(ip, port);

View File

@@ -97,7 +97,7 @@ public class MapPlayDialog extends BaseDialog{
table.row(); table.row();
for(Gamemode mode : Gamemode.values()){ for(Gamemode mode : Gamemode.values()){
if(mode.hidden) continue; if(mode.hidden) continue;
table.labelWrap("[accent]" + mode.toString() + ":[] [lightgray]" + mode.description()).width(400f); table.labelWrap("[accent]" + mode + ":[] [lightgray]" + mode.description()).width(400f);
table.row(); table.row();
} }

View File

@@ -15,6 +15,7 @@ import arc.scene.ui.*;
import arc.scene.ui.layout.*; import arc.scene.ui.layout.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
import mindustry.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.content.TechTree.*; import mindustry.content.TechTree.*;
import mindustry.core.*; import mindustry.core.*;
@@ -24,6 +25,7 @@ import mindustry.game.SectorInfo.*;
import mindustry.game.*; import mindustry.game.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.graphics.g3d.PlanetGrid.*;
import mindustry.graphics.g3d.*; import mindustry.graphics.g3d.*;
import mindustry.input.*; import mindustry.input.*;
import mindustry.maps.*; import mindustry.maps.*;
@@ -49,10 +51,11 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
public static float sectorShowDuration = 60f * 2.4f; public static float sectorShowDuration = 60f * 2.4f;
public final FrameBuffer buffer = new FrameBuffer(2, 2, true); public final FrameBuffer buffer = new FrameBuffer(2, 2, true);
public final PlanetRenderer planets = renderer.planets;
public final LaunchLoadoutDialog loadouts = new LaunchLoadoutDialog(); public final LaunchLoadoutDialog loadouts = new LaunchLoadoutDialog();
public final PlanetRenderer planets = renderer.planets;
public float zoom = 1f, selectAlpha = 1f; public PlanetParams state = new PlanetParams();
public float zoom = 1f;
public @Nullable Sector selected, hovered, launchSector; public @Nullable Sector selected, hovered, launchSector;
public Mode mode = look; public Mode mode = look;
public boolean launching; public boolean launching;
@@ -68,10 +71,13 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
public PlanetDialog(){ public PlanetDialog(){
super("", Styles.fullDialog); super("", Styles.fullDialog);
state.renderer = this;
state.drawUi = true;
shouldPause = true; shouldPause = true;
planets.planet = content.getByName(ContentType.planet, Core.settings.getString("lastplanet", "serpulo")); state.planet = content.getByName(ContentType.planet, Core.settings.getString("lastplanet", "serpulo"));
if(planets.planet == null) planets.planet = Planets.serpulo; if(state.planet == null) state.planet = Planets.serpulo;
addListener(new InputListener(){ addListener(new InputListener(){
@Override @Override
@@ -107,7 +113,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
newPresets.clear(); newPresets.clear();
} }
Vec3 pos = planets.camPos; Vec3 pos = state.camPos;
float upV = pos.angle(Vec3.Y); float upV = pos.angle(Vec3.Y);
float xscale = 9f, yscale = 10f; float xscale = 9f, yscale = 10f;
@@ -116,20 +122,20 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
//scale X speed depending on polar coordinate //scale X speed depending on polar coordinate
float speed = 1f - Math.abs(upV - 90) / 90f; float speed = 1f - Math.abs(upV - 90) / 90f;
pos.rotate(planets.cam.up, cx / xscale * speed); pos.rotate(state.camUp, cx / xscale * speed);
//prevent user from scrolling all the way up and glitching it out //prevent user from scrolling all the way up and glitching it out
float amount = cy / yscale; float amount = cy / yscale;
amount = Mathf.clamp(upV + amount, margin, 180f - margin) - upV; amount = Mathf.clamp(upV + amount, margin, 180f - margin) - upV;
pos.rotate(Tmp.v31.set(planets.cam.up).rotate(planets.cam.direction, 90), amount); pos.rotate(Tmp.v31.set(state.camUp).rotate(state.camDir, 90), amount);
}); });
addListener(new InputListener(){ addListener(new InputListener(){
@Override @Override
public boolean scrolled(InputEvent event, float x, float y, float amountX, float amountY){ public boolean scrolled(InputEvent event, float x, float y, float amountX, float amountY){
if(event.targetActor == PlanetDialog.this){ if(event.targetActor == PlanetDialog.this){
zoom = Mathf.clamp(zoom + amountY / 10f, 0.5f, 2f); zoom = Mathf.clamp(zoom + amountY / 10f, state.planet.minZoom, 2f);
} }
return true; return true;
} }
@@ -144,7 +150,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
lastZoom = zoom; lastZoom = zoom;
} }
zoom = (Mathf.clamp(initialDistance / distance * lastZoom, 0.5f, 2f)); zoom = (Mathf.clamp(initialDistance / distance * lastZoom, state.planet.minZoom, 2f));
} }
@Override @Override
@@ -170,9 +176,9 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
launching = false; launching = false;
zoom = 1f; zoom = 1f;
planets.zoom = 1f; state.zoom = 1f;
selectAlpha = 0f; state.uiAlpha = 0f;
launchSector = state.getSector(); launchSector = Vars.state.getSector();
presetShow = 0f; presetShow = 0f;
showed = false; showed = false;
listener = s -> {}; listener = s -> {};
@@ -181,7 +187,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
//announce new presets //announce new presets
for(SectorPreset preset : content.sectors()){ for(SectorPreset preset : content.sectors()){
if(preset.unlocked() && !preset.alwaysUnlocked && !preset.sector.info.shown && !preset.sector.hasBase() && preset.planet == planets.planet){ if(preset.unlocked() && !preset.alwaysUnlocked && !preset.sector.info.shown && !preset.sector.hasBase() && preset.planet == state.planet){
newPresets.add(preset.sector); newPresets.add(preset.sector);
preset.sector.info.shown = true; preset.sector.info.shown = true;
preset.sector.saveInfo(); preset.sector.saveInfo();
@@ -189,14 +195,14 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
} }
if(newPresets.any()){ if(newPresets.any()){
newPresets.add(planets.planet.getLastSector()); newPresets.add(state.planet.getLastSector());
} }
newPresets.reverse(); newPresets.reverse();
updateSelected(); updateSelected();
if(planets.planet.getLastSector() != null){ if(state.planet.getLastSector() != null){
lookAt(planets.planet.getLastSector()); lookAt(state.planet.getLastSector());
} }
return super.show(); return super.show();
@@ -252,8 +258,8 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
//update view to sector //update view to sector
zoom = 1f; zoom = 1f;
planets.zoom = 1f; state.zoom = 1f;
selectAlpha = 0f; state.uiAlpha = 0f;
mode = planetLaunch; mode = planetLaunch;
@@ -269,8 +275,8 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
//update view to sector //update view to sector
lookAt(sector); lookAt(sector);
zoom = 1f; zoom = 1f;
planets.zoom = 1f; state.zoom = 1f;
selectAlpha = 0f; state.uiAlpha = 0f;
launchSector = sector; launchSector = sector;
mode = select; mode = select;
@@ -279,7 +285,9 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
} }
void lookAt(Sector sector){ void lookAt(Sector sector){
planets.camPos.set(Tmp.v33.set(sector.tile.v).rotate(Vec3.Y, -sector.planet.getRotation())); if(sector.tile == Ptile.empty) return;
state.camPos.set(Tmp.v33.set(sector.tile.v).rotate(Vec3.Y, -sector.planet.getRotation()));
} }
boolean canSelect(Sector sector){ boolean canSelect(Sector sector){
@@ -307,7 +315,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
launchFrom = to.near().find(Sector::hasBase); launchFrom = to.near().find(Sector::hasBase);
if(launchFrom == null && to.preset != null){ if(launchFrom == null && to.preset != null){
if(launchSector != null) return launchSector; if(launchSector != null) return launchSector;
launchFrom = planets.planet.sectors.min(s -> !s.hasBase() ? Float.MAX_VALUE : s.tile.v.dst2(to.tile.v)); launchFrom = state.planet.sectors.min(s -> !s.hasBase() ? Float.MAX_VALUE : s.tile.v.dst2(to.tile.v));
if(!launchFrom.hasBase()) launchFrom = null; if(!launchFrom.hasBase()) launchFrom = null;
} }
} }
@@ -323,7 +331,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
public void renderSectors(Planet planet){ public void renderSectors(Planet planet){
//draw all sector stuff //draw all sector stuff
if(selectAlpha > 0.01f){ if(state.uiAlpha > 0.01f){
for(Sector sec : planet.sectors){ for(Sector sec : planet.sectors){
if(canSelect(sec) || sec.unlocked() || debugSelect){ if(canSelect(sec) || sec.unlocked() || debugSelect){
@@ -336,15 +344,15 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
null; null;
if(color != null){ if(color != null){
planets.drawSelection(sec, Tmp.c1.set(color).mul(0.8f).a(selectAlpha), 0.026f, -0.001f); planets.drawSelection(sec, Tmp.c1.set(color).mul(0.8f).a(state.uiAlpha), 0.026f, -0.001f);
} }
}else{ }else{
planets.fill(sec, Tmp.c1.set(shadowColor).mul(1, 1, 1, selectAlpha), -0.001f); planets.fill(sec, Tmp.c1.set(shadowColor).mul(1, 1, 1, state.uiAlpha), -0.001f);
} }
} }
} }
Sector current = state.getSector() != null && state.getSector().isBeingPlayed() && state.getSector().planet == planets.planet ? state.getSector() : null; Sector current = Vars.state.getSector() != null && Vars.state.getSector().isBeingPlayed() && Vars.state.getSector().planet == state.planet ? Vars.state.getSector() : null;
if(current != null){ if(current != null){
planets.fill(current, hoverColor, -0.001f); planets.fill(current, hoverColor, -0.001f);
@@ -371,12 +379,12 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
} }
} }
if(selectAlpha > 0.001f){ if(state.uiAlpha > 0.001f){
for(Sector sec : planet.sectors){ for(Sector sec : planet.sectors){
if(sec.hasBase()){ if(sec.hasBase()){
for(Sector enemy : sec.near()){ for(Sector enemy : sec.near()){
if(enemy.hasEnemyBase()){ if(enemy.hasEnemyBase()){
planets.drawArc(planet, enemy.tile.v, sec.tile.v, Team.crux.color.write(Tmp.c2).a(selectAlpha), Color.clear, 0.24f, 110f, 25); planets.drawArc(planet, enemy.tile.v, sec.tile.v, Team.crux.color.write(Tmp.c2).a(state.uiAlpha), Color.clear, 0.24f, 110f, 25);
} }
} }
@@ -384,11 +392,11 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
if(selected != null && selected != sec && selected.hasBase()){ if(selected != null && selected != sec && selected.hasBase()){
//imports //imports
if(sec.info.getRealDestination() == selected && sec.info.anyExports()){ if(sec.info.getRealDestination() == selected && sec.info.anyExports()){
planets.drawArc(planet, sec.tile.v, selected.tile.v, Color.gray.write(Tmp.c2).a(selectAlpha), Pal.accent.write(Tmp.c3).a(selectAlpha), 0.4f, 90f, 25); planets.drawArc(planet, sec.tile.v, selected.tile.v, Color.gray.write(Tmp.c2).a(state.uiAlpha), Pal.accent.write(Tmp.c3).a(state.uiAlpha), 0.4f, 90f, 25);
} }
//exports //exports
if(selected.info.getRealDestination() == sec && selected.info.anyExports()){ if(selected.info.getRealDestination() == sec && selected.info.anyExports()){
planets.drawArc(planet, selected.tile.v, sec.tile.v, Pal.place.write(Tmp.c2).a(selectAlpha), Pal.accent.write(Tmp.c3).a(selectAlpha), 0.4f, 90f, 25); planets.drawArc(planet, selected.tile.v, sec.tile.v, Pal.place.write(Tmp.c2).a(state.uiAlpha), Pal.accent.write(Tmp.c3).a(state.uiAlpha), 0.4f, 90f, 25);
} }
} }
} }
@@ -415,7 +423,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
if(icon != null){ if(icon != null){
planets.drawPlane(sec, () -> { planets.drawPlane(sec, () -> {
//use white for content icons //use white for content icons
Draw.color(preficon == icon && sec.info.contentIcon != null ? Color.white : color, selectAlpha); Draw.color(preficon == icon && sec.info.contentIcon != null ? Color.white : color, state.uiAlpha);
Draw.rect(icon, 0, 0, iw, iw * icon.height / icon.width); Draw.rect(icon, 0, 0, iw, iw * icon.height / icon.width);
}); });
} }
@@ -444,13 +452,13 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
boolean selectable(Planet planet){ boolean selectable(Planet planet){
//TODO what if any sector is selectable? //TODO what if any sector is selectable?
if(mode == planetLaunch) return launchSector != null && planet != launchSector.planet; if(mode == planetLaunch) return launchSector != null && planet != launchSector.planet;
return planet == planets.planet || planet.alwaysUnlocked || planet.sectors.contains(Sector::hasBase); return planet == state.planet || (planet.alwaysUnlocked && planet.isLandable()) || planet.sectors.contains(Sector::hasBase);
} }
void setup(){ void setup(){
searchText = ""; searchText = "";
zoom = planets.zoom = 1f; zoom = state.zoom = 1f;
selectAlpha = 1f; state.uiAlpha = 1f;
ui.minimapfrag.hide(); ui.minimapfrag.hide();
clearChildren(); clearChildren();
@@ -492,8 +500,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
@Override @Override
public void draw(){ public void draw(){
planets.orbitAlpha = selectAlpha; planets.render(state);
planets.render(PlanetDialog.this);
} }
}, },
//info text //info text
@@ -518,12 +525,12 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
pt.button(planet.localizedName, Styles.clearTogglet, () -> { pt.button(planet.localizedName, Styles.clearTogglet, () -> {
selected = null; selected = null;
launchSector = null; launchSector = null;
if(renderer.planets.planet != planet){ if(state.planet != planet){
renderer.planets.planet = planet; state.planet = planet;
rebuildList(); rebuildList();
} }
settings.put("lastplanet", planet.name); settings.put("lastplanet", planet.name);
}).width(200).height(40).growX().update(bb -> bb.setChecked(renderer.planets.planet == planet)); }).width(200).height(40).growX().update(bb -> bb.setChecked(state.planet == planet));
pt.row(); pt.row();
} }
} }
@@ -533,8 +540,8 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
new Table(c -> { new Table(c -> {
c.visible(() -> !(graphics.isPortrait() && mobile)); c.visible(() -> !(graphics.isPortrait() && mobile));
if(planets.planet.sectors.contains(Sector::hasBase)){ if(state.planet.sectors.contains(Sector::hasBase)){
int attacked = planets.planet.sectors.count(Sector::isAttacked); int attacked = state.planet.sectors.count(Sector::isAttacked);
//sector notifications & search //sector notifications & search
c.top().right(); c.top().right();
@@ -564,7 +571,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
notifs.clear(); notifs.clear();
var all = planets.planet.sectors.select(Sector::hasBase); var all = state.planet.sectors.select(Sector::hasBase);
all.sort(Structs.comps(Structs.comparingBool(s -> !s.isAttacked()), Structs.comparingInt(s -> s.save == null ? 0 : -(int)s.save.meta.timePlayed))); all.sort(Structs.comps(Structs.comparingBool(s -> !s.isAttacked()), Structs.comparingInt(s -> s.save == null ? 0 : -(int)s.save.meta.timePlayed)));
notifs.pane(p -> { notifs.pane(p -> {
@@ -646,20 +653,20 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
} }
public void lookAt(Sector sector, float alpha){ public void lookAt(Sector sector, float alpha){
float len = planets.camPos.len(); float len = state.camPos.len();
planets.camPos.slerp(Tmp.v31.set(sector.tile.v).rotate(Vec3.Y, -sector.planet.getRotation()).setLength(len), alpha); state.camPos.slerp(Tmp.v31.set(sector.tile.v).rotate(Vec3.Y, -sector.planet.getRotation()).setLength(len), alpha);
} }
@Override @Override
public void act(float delta){ public void act(float delta){
super.act(delta); super.act(delta);
if(hovered != null && !mobile){ if(hovered != null && !mobile && state.planet.hasGrid()){
addChild(hoverLabel); addChild(hoverLabel);
hoverLabel.toFront(); hoverLabel.toFront();
hoverLabel.touchable = Touchable.disabled; hoverLabel.touchable = Touchable.disabled;
Vec3 pos = planets.cam.project(Tmp.v31.set(hovered.tile.v).setLength(PlanetRenderer.outlineRad).rotate(Vec3.Y, -planets.planet.getRotation()).add(planets.planet.position)); Vec3 pos = planets.cam.project(Tmp.v31.set(hovered.tile.v).setLength(PlanetRenderer.outlineRad).rotate(Vec3.Y, -state.planet.getRotation()).add(state.planet.position));
hoverLabel.setPosition(pos.x - Core.scene.marginLeft, pos.y - Core.scene.marginBottom, Align.center); hoverLabel.setPosition(pos.x - Core.scene.marginLeft, pos.y - Core.scene.marginBottom, Align.center);
hoverLabel.getText().setLength(0); hoverLabel.getText().setLength(0);
@@ -704,14 +711,24 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
} }
} }
if(planets.planet.hasGrid()){ if(state.planet.hasGrid()){
hovered = planets.planet.getSector(planets.cam.getMouseRay(), PlanetRenderer.outlineRad); hovered = state.planet.getSector(planets.cam.getMouseRay(), PlanetRenderer.outlineRad);
}else if(state.planet.isLandable()){
boolean wasNull = selected == null;
//always have the first sector selected.
//TODO better support for multiple sectors in gridless planets?
hovered = selected = state.planet.sectors.first();
//autoshow
if(wasNull){
updateSelected();
}
}else{ }else{
hovered = selected = null; hovered = selected = null;
} }
planets.zoom = Mathf.lerpDelta(planets.zoom, zoom, 0.4f); state.zoom = Mathf.lerpDelta(state.zoom, zoom, 0.4f);
selectAlpha = Mathf.lerpDelta(selectAlpha, Mathf.num(planets.zoom < 1.9f), 0.1f); state.uiAlpha = Mathf.lerpDelta(state.uiAlpha, Mathf.num(state.zoom < 1.9f), 0.1f);
} }
void displayItems(Table c, float scl, ObjectMap<Item, ExportStat> stats, String name){ void displayItems(Table c, float scl, ObjectMap<Item, ExportStat> stats, String name){
@@ -996,13 +1013,17 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
if(launching){ if(launching){
stable.color.sub(0, 0, 0, 0.05f * Time.delta); stable.color.sub(0, 0, 0, 0.05f * Time.delta);
}else{ }else{
//fade out UI when not facing selected sector if(!state.planet.hasGrid()){
Tmp.v31.set(selected.tile.v).rotate(Vec3.Y, -planets.planet.getRotation()).scl(-1f).nor(); stable.color.a = 1f;
float dot = planets.cam.direction.dot(Tmp.v31); }else{
stable.color.a = Math.max(dot, 0f)*2f; //fade out UI when not facing selected sector
if(dot*2f <= -0.1f){ Tmp.v31.set(selected.tile.v).rotate(Vec3.Y, -state.planet.getRotation()).scl(-1f).nor();
selected = null; float dot = planets.cam.direction.dot(Tmp.v31);
updateSelected(); stable.color.a = Math.max(dot, 0f)*2f;
if(dot*2f <= -0.1f){
selected = null;
updateSelected();
}
} }
} }
} }
@@ -1029,7 +1050,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
boolean shouldHide = true; boolean shouldHide = true;
//save before launch. //save before launch.
if(control.saves.getCurrent() != null && state.isGame() && mode != select){ if(control.saves.getCurrent() != null && Vars.state.isGame() && mode != select){
try{ try{
control.saves.getCurrent().save(); control.saves.getCurrent().save();
}catch(Throwable e){ }catch(Throwable e){

View File

@@ -25,6 +25,7 @@ import mindustry.graphics.*;
import mindustry.graphics.MultiPacker.*; import mindustry.graphics.MultiPacker.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.ui.*; import mindustry.ui.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.environment.*; import mindustry.world.blocks.environment.*;
import mindustry.world.blocks.power.*; import mindustry.world.blocks.power.*;
import mindustry.world.consumers.*; import mindustry.world.consumers.*;
@@ -122,6 +123,8 @@ public class Block extends UnlockableContent{
public boolean useColor = true; public boolean useColor = true;
/** item that drops from this block, used for drills */ /** item that drops from this block, used for drills */
public @Nullable Item itemDrop = null; public @Nullable Item itemDrop = null;
/** Array of affinities to certain things. */
public Attributes attributes = new Attributes();
/** tile entity health */ /** tile entity health */
public int health = -1; public int health = -1;
/** base block explosiveness */ /** base block explosiveness */
@@ -384,10 +387,16 @@ public class Block extends UnlockableContent{
} }
/** Returns whether or not this block can be place on the specified */ /** Returns whether or not this block can be place on the specified */
public boolean canPlaceOn(Tile tile, Team team, int rotation){
return canPlaceOn(tile, team);
}
/** Legacy canPlaceOn implementation, override {@link #canPlaceOn(Tile, Team, int)} instead.*/
public boolean canPlaceOn(Tile tile, Team team){ public boolean canPlaceOn(Tile tile, Team team){
return true; return true;
} }
public boolean canBreak(Tile tile){ public boolean canBreak(Tile tile){
return true; return true;
} }

View File

@@ -169,7 +169,7 @@ public class Build{
return false; return false;
} }
if(!type.canPlaceOn(tile, team)){ if(!type.canPlaceOn(tile, team, rotation)){
return false; return false;
} }

View File

@@ -227,6 +227,7 @@ public class ConstructBlock extends Block{
for(TextureRegion region : current.getGeneratedIcons()){ for(TextureRegion region : current.getGeneratedIcons()){
Shaders.blockbuild.region = region; Shaders.blockbuild.region = region;
Shaders.blockbuild.time = Time.time;
Shaders.blockbuild.progress = progress; Shaders.blockbuild.progress = progress;
Draw.rect(region, x, y, current.rotate ? rotdeg() : 0); Draw.rect(region, x, y, current.rotate ? rotdeg() : 0);

View File

@@ -58,6 +58,7 @@ public class ForceProjector extends Block{
ambientSound = Sounds.shield; ambientSound = Sounds.shield;
ambientSoundVolume = 0.08f; ambientSoundVolume = 0.08f;
consumes.add(new ConsumeCoolant(0.1f)).boost().update(false); consumes.add(new ConsumeCoolant(0.1f)).boost().update(false);
envEnabled |= Env.space;
} }
@Override @Override

View File

@@ -36,6 +36,7 @@ public class MendProjector extends Block{
hasItems = true; hasItems = true;
emitLight = true; emitLight = true;
lightRadius = 50f; lightRadius = 50f;
envEnabled |= Env.space;
} }
@Override @Override

View File

@@ -41,6 +41,7 @@ public class OverdriveProjector extends Block{
canOverdrive = false; canOverdrive = false;
emitLight = true; emitLight = true;
lightRadius = 50f; lightRadius = 50f;
envEnabled |= Env.space;
} }
@Override @Override

View File

@@ -36,6 +36,9 @@ public class Wall extends Block{
buildCostMultiplier = 6f; buildCostMultiplier = 6f;
canOverdrive = false; canOverdrive = false;
drawDisabled = false; drawDisabled = false;
//it's a wall of course it's supported everywhere
envEnabled = Env.any;
} }
@Override @Override

View File

@@ -12,6 +12,7 @@ public class PowerTurret extends Turret{
public PowerTurret(String name){ public PowerTurret(String name){
super(name); super(name);
hasPower = true; hasPower = true;
envEnabled |= Env.space;
} }
@Override @Override

View File

@@ -410,7 +410,7 @@ public class ItemBridge extends Block{
} }
protected boolean checkAccept(Building source, Tile other){ protected boolean checkAccept(Building source, Tile other){
if(linked(source)) return true; if(tile == null || linked(source)) return true;
if(linkValid(tile, other)){ if(linkValid(tile, other)){
int rel = relativeTo(other); int rel = relativeTo(other);

View File

@@ -48,6 +48,7 @@ public class MassDriver extends Block{
hasPower = true; hasPower = true;
outlineIcon = true; outlineIcon = true;
sync = true; sync = true;
envEnabled |= Env.space;
//point2 is relative //point2 is relative
config(Point2.class, (MassDriverBuild tile, Point2 point) -> tile.link = Point2.pack(point.x + tile.tileX(), point.y + tile.tileY())); config(Point2.class, (MassDriverBuild tile, Point2 point) -> tile.link = Point2.pack(point.x + tile.tileX(), point.y + tile.tileY()));

View File

@@ -30,6 +30,7 @@ public class PayloadConveyor extends Block{
update = true; update = true;
outputsPayload = true; outputsPayload = true;
noUpdateDisabled = true; noUpdateDisabled = true;
envEnabled |= Env.space;
sync = true; sync = true;
} }

View File

@@ -14,6 +14,7 @@ public class AirBlock extends Floor{
useColor = false; useColor = false;
wall = this; wall = this;
needsSurface = false; needsSurface = false;
canShadow = false;
} }
@Override @Override

View File

@@ -0,0 +1,24 @@
package mindustry.world.blocks.environment;
import mindustry.content.*;
import mindustry.world.*;
public class EmptyFloor extends Floor{
public EmptyFloor(String name){
super(name);
variants = 0;
canShadow = false;
}
@Override
public void drawBase(Tile tile){
//draws only edges, never itself
drawEdges(tile);
Floor floor = tile.overlay();
if(floor != Blocks.air && floor != this){
floor.drawBase(tile);
}
}
}

View File

@@ -15,7 +15,6 @@ import mindustry.graphics.*;
import mindustry.graphics.MultiPacker.*; import mindustry.graphics.MultiPacker.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.blocks.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
@@ -54,8 +53,6 @@ public class Floor extends Block{
public boolean playerUnmineable = false; public boolean playerUnmineable = false;
/** Group of blocks that this block does not draw edges on. */ /** Group of blocks that this block does not draw edges on. */
public Block blendGroup = this; public Block blendGroup = this;
/** Array of affinities to certain things. */
public Attributes attributes = new Attributes();
/** Whether this ore generates in maps by default. */ /** Whether this ore generates in maps by default. */
public boolean oreDefault = false; public boolean oreDefault = false;
/** Ore generation params. */ /** Ore generation params. */
@@ -64,6 +61,8 @@ public class Floor extends Block{
public Block wall = Blocks.air; public Block wall = Blocks.air;
/** Decoration block. Usually a rock. May be air. */ /** Decoration block. Usually a rock. May be air. */
public Block decoration = Blocks.air; public Block decoration = Blocks.air;
/** Whether units can draw shadows over this. */
public boolean canShadow = true;
/** Whether this overlay needs a surface to be on. False for floating blocks, like spawns. */ /** Whether this overlay needs a surface to be on. False for floating blocks, like spawns. */
public boolean needsSurface = true; public boolean needsSurface = true;
@@ -116,10 +115,6 @@ public class Floor extends Block{
//keep default value if not found... //keep default value if not found...
if(wall == null) wall = Blocks.air; if(wall == null) wall = Blocks.air;
if(decoration == Blocks.air){
decoration = content.blocks().min(b -> b instanceof Prop && b.minfo.mod == null && b.breakable ? mapColor.diff(b.mapColor) : Float.POSITIVE_INFINITY);
}
if(isLiquid && walkEffect == Fx.none){ if(isLiquid && walkEffect == Fx.none){
walkEffect = Fx.ripple; walkEffect = Fx.ripple;
} }

View File

@@ -1,14 +1,17 @@
package mindustry.world.blocks.experimental; package mindustry.world.blocks.experimental;
import mindustry.world.blocks.payloads.*;
/** @deprecated use Constructor instead. */
@Deprecated @Deprecated
public class BlockForge extends mindustry.world.blocks.payloads.BlockForge{ public class BlockForge extends Constructor{
public BlockForge(String name){ public BlockForge(String name){
super(name); super(name);
} }
@Deprecated @Deprecated
public class BlockForgeBuild extends mindustry.world.blocks.payloads.BlockForge.BlockForgeBuild{ public class BlockForgeBuild extends Constructor.ConstructorBuild{
} }
} }

View File

@@ -1,14 +1,16 @@
package mindustry.world.blocks.experimental; package mindustry.world.blocks.experimental;
import mindustry.world.blocks.payloads.*;
@Deprecated @Deprecated
public class BlockLoader extends mindustry.world.blocks.payloads.BlockLoader{ public class BlockLoader extends PayloadLoader{
public BlockLoader(String name){ public BlockLoader(String name){
super(name); super(name);
} }
@Deprecated @Deprecated
public class BlockLoaderBuild extends mindustry.world.blocks.payloads.BlockLoader.BlockLoaderBuild{ public class BlockLoaderBuild extends PayloadLoaderBuild{
} }
} }

View File

@@ -1,14 +1,16 @@
package mindustry.world.blocks.experimental; package mindustry.world.blocks.experimental;
import mindustry.world.blocks.payloads.*;
@Deprecated @Deprecated
public class BlockUnloader extends mindustry.world.blocks.payloads.BlockUnloader{ public class BlockUnloader extends PayloadUnloader{
public BlockUnloader(String name){ public BlockUnloader(String name){
super(name); super(name);
} }
@Deprecated @Deprecated
public class BlockUnloaderBuild extends mindustry.world.blocks.payloads.BlockUnloader.BlockUnloaderBuild{ public class BlockUnloaderBuild extends PayloadUnloaderBuild{
} }
} }

View File

@@ -20,7 +20,7 @@ public class ArmoredConduit extends Conduit{
public class ArmoredConduitBuild extends ConduitBuild{ public class ArmoredConduitBuild extends ConduitBuild{
@Override @Override
public boolean acceptLiquid(Building source, Liquid liquid){ public boolean acceptLiquid(Building source, Liquid liquid){
return super.acceptLiquid(source, liquid) && (source.block instanceof Conduit || return super.acceptLiquid(source, liquid) && (tile == null || source.block instanceof Conduit ||
source.tile.absoluteRelativeTo(tile.x, tile.y) == rotation); source.tile.absoluteRelativeTo(tile.x, tile.y) == rotation);
} }
} }

View File

@@ -151,7 +151,7 @@ public class Conduit extends LiquidBlock implements Autotiler{
public boolean acceptLiquid(Building source, Liquid liquid){ public boolean acceptLiquid(Building source, Liquid liquid){
noSleep(); noSleep();
return (liquids.current() == liquid || liquids.currentAmount() < 0.2f) return (liquids.current() == liquid || liquids.currentAmount() < 0.2f)
&& ((source.relativeTo(tile.x, tile.y) + 2) % 4 != rotation); && (tile == null || (source.relativeTo(tile.x, tile.y) + 2) % 4 != rotation);
} }
@Override @Override

View File

@@ -19,6 +19,7 @@ public class LiquidBlock extends Block{
hasLiquids = true; hasLiquids = true;
group = BlockGroup.liquids; group = BlockGroup.liquids;
outputsLiquid = true; outputsLiquid = true;
envEnabled |= Env.space | Env.underwater;
} }
@Override @Override

View File

@@ -13,6 +13,7 @@ public class LiquidBridge extends ItemBridge{
outputsLiquid = true; outputsLiquid = true;
canOverdrive = false; canOverdrive = false;
group = BlockGroup.liquids; group = BlockGroup.liquids;
envEnabled = Env.any;
} }
public class LiquidBridgeBuild extends ItemBridgeBuild{ public class LiquidBridgeBuild extends ItemBridgeBuild{

View File

@@ -42,6 +42,9 @@ public class LogicBlock extends Block{
group = BlockGroup.logic; group = BlockGroup.logic;
schematicPriority = 5; schematicPriority = 5;
//universal, no real requirements
envEnabled = Env.any;
config(byte[].class, (LogicBuild build, byte[] data) -> build.readCompressed(data, true)); config(byte[].class, (LogicBuild build, byte[] data) -> build.readCompressed(data, true));
config(Integer.class, (LogicBuild entity, Integer pos) -> { config(Integer.class, (LogicBuild entity, Integer pos) -> {

View File

@@ -36,6 +36,7 @@ public class LogicDisplay extends Block{
solid = true; solid = true;
group = BlockGroup.logic; group = BlockGroup.logic;
drawDisabled = false; drawDisabled = false;
envEnabled = Env.any;
} }
@Override @Override

View File

@@ -14,6 +14,7 @@ public class MemoryBlock extends Block{
solid = true; solid = true;
group = BlockGroup.logic; group = BlockGroup.logic;
drawDisabled = false; drawDisabled = false;
envEnabled = Env.any;
} }
@Override @Override

View File

@@ -30,6 +30,7 @@ public class MessageBlock extends Block{
destructible = true; destructible = true;
group = BlockGroup.logic; group = BlockGroup.logic;
drawDisabled = false; drawDisabled = false;
envEnabled = Env.any;
config(String.class, (MessageBuild tile, String text) -> { config(String.class, (MessageBuild tile, String text) -> {
if(text.length() > maxTextLength){ if(text.length() > maxTextLength){

View File

@@ -17,6 +17,7 @@ public class SwitchBlock extends Block{
drawDisabled = false; drawDisabled = false;
autoResetEnabled = false; autoResetEnabled = false;
group = BlockGroup.logic; group = BlockGroup.logic;
envEnabled = Env.any;
config(Boolean.class, (SwitchBuild entity, Boolean b) -> entity.enabled = b); config(Boolean.class, (SwitchBuild entity, Boolean b) -> entity.enabled = b);
} }

View File

@@ -80,16 +80,16 @@ public class PayloadBlock extends Block{
} }
@Override @Override
public boolean canControlSelect(Player player){ public boolean canControlSelect(Unit player){
return !player.unit().spawnedByCore && this.payload == null && acceptUnitPayload(player.unit()) && player.tileOn() != null && player.tileOn().build == this; return !player.spawnedByCore && this.payload == null && acceptUnitPayload(player) && player.tileOn() != null && player.tileOn().build == this;
} }
@Override @Override
public void onControlSelect(Player player){ public void onControlSelect(Unit player){
float x = player.x, y = player.y; float x = player.x, y = player.y;
acceptPlayerPayload(player, p -> payload = (T)p); handleUnitPayload(player, p -> payload = (T)p);
this.payVector.set(x, y).sub(this).clamp(-size * tilesize / 2f, -size * tilesize / 2f, size * tilesize / 2f, size * tilesize / 2f); this.payVector.set(x, y).sub(this).clamp(-size * tilesize / 2f, -size * tilesize / 2f, size * tilesize / 2f, size * tilesize / 2f);
this.payRotation = player.unit().rotation; this.payRotation = player.rotation;
} }
@Override @Override

View File

@@ -21,6 +21,8 @@ public class Battery extends PowerDistributor{
outputsPower = true; outputsPower = true;
consumesPower = true; consumesPower = true;
flags = EnumSet.of(BlockFlag.battery); flags = EnumSet.of(BlockFlag.battery);
//TODO could be supported everywhere...
envEnabled |= Env.space;
} }
public class BatteryBuild extends Building{ public class BatteryBuild extends Building{

View File

@@ -1,6 +1,7 @@
package mindustry.world.blocks.power; package mindustry.world.blocks.power;
import mindustry.type.*; import mindustry.type.*;
import mindustry.world.meta.*;
public class DecayGenerator extends ItemLiquidGenerator{ public class DecayGenerator extends ItemLiquidGenerator{
@@ -8,6 +9,7 @@ public class DecayGenerator extends ItemLiquidGenerator{
super(true, false, name); super(true, false, name);
hasItems = true; hasItems = true;
hasLiquids = false; hasLiquids = false;
envEnabled = Env.any;
} }
@Override @Override

View File

@@ -43,6 +43,7 @@ public class ImpactReactor extends PowerGenerator{
flags = EnumSet.of(BlockFlag.reactor, BlockFlag.generator); flags = EnumSet.of(BlockFlag.reactor, BlockFlag.generator);
lightRadius = 115f; lightRadius = 115f;
emitLight = true; emitLight = true;
envEnabled = Env.any;
} }
@Override @Override

View File

@@ -14,6 +14,7 @@ import mindustry.graphics.*;
import mindustry.input.*; import mindustry.input.*;
import mindustry.logic.*; import mindustry.logic.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.meta.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
@@ -28,6 +29,7 @@ public class LightBlock extends Block{
update = true; update = true;
configurable = true; configurable = true;
saveConfig = true; saveConfig = true;
envEnabled |= Env.space;
swapDiagonalPlacement = true; swapDiagonalPlacement = true;
config(Integer.class, (LightBuild tile, Integer value) -> tile.color = value); config(Integer.class, (LightBuild tile, Integer value) -> tile.color = value);

View File

@@ -56,6 +56,7 @@ public class NuclearReactor extends PowerGenerator{
rebuildable = false; rebuildable = false;
flags = EnumSet.of(BlockFlag.reactor, BlockFlag.generator); flags = EnumSet.of(BlockFlag.reactor, BlockFlag.generator);
schematicPriority = -5; schematicPriority = -5;
envEnabled = Env.any;
} }
@Override @Override

View File

@@ -23,6 +23,7 @@ public class PowerDiode extends Block{
group = BlockGroup.power; group = BlockGroup.power;
noUpdateDisabled = true; noUpdateDisabled = true;
schematicPriority = 10; schematicPriority = 10;
envEnabled |= Env.space;
} }
@Override @Override

View File

@@ -43,6 +43,7 @@ public class PowerNode extends PowerBlock{
swapDiagonalPlacement = true; swapDiagonalPlacement = true;
schematicPriority = -10; schematicPriority = -10;
drawDisabled = false; drawDisabled = false;
envEnabled |= Env.space;
config(Integer.class, (entity, value) -> { config(Integer.class, (entity, value) -> {
PowerModule power = entity.power; PowerModule power = entity.power;

View File

@@ -12,6 +12,7 @@ public class SolarGenerator extends PowerGenerator{
super(name); super(name);
//remove the BlockFlag.generator flag to make this a lower priority target than other generators. //remove the BlockFlag.generator flag to make this a lower priority target than other generators.
flags = EnumSet.of(); flags = EnumSet.of();
envEnabled = Env.any;
} }
@Override @Override

View File

@@ -41,7 +41,7 @@ public class ThermalGenerator extends PowerGenerator{
} }
@Override @Override
public boolean canPlaceOn(Tile tile, Team team){ public boolean canPlaceOn(Tile tile, Team team, int rotation){
//make sure there's heat at this location //make sure there's heat at this location
return tile.getLinkedTilesAs(this, tempTiles).sumf(other -> other.floor().attributes.get(attribute)) > 0.01f; return tile.getLinkedTilesAs(this, tempTiles).sumf(other -> other.floor().attributes.get(attribute)) > 0.01f;
} }

View File

@@ -36,7 +36,7 @@ public class Drill extends Block{
/** How many times faster the drill will progress when boosted by liquid. */ /** How many times faster the drill will progress when boosted by liquid. */
public float liquidBoostIntensity = 1.6f; public float liquidBoostIntensity = 1.6f;
/** Speed at which the drill speeds up. */ /** Speed at which the drill speeds up. */
public float warmupSpeed = 0.02f; public float warmupSpeed = 0.015f;
//return variables for countOre //return variables for countOre
protected @Nullable Item returnItem; protected @Nullable Item returnItem;
@@ -108,7 +108,7 @@ public class Drill extends Block{
} }
@Override @Override
public boolean canPlaceOn(Tile tile, Team team){ public boolean canPlaceOn(Tile tile, Team team, int rotation){
if(isMultiblock()){ if(isMultiblock()){
for(Tile other : tile.getLinkedTilesAs(this, tempTiles)){ for(Tile other : tile.getLinkedTilesAs(this, tempTiles)){
if(canMine(other)){ if(canMine(other)){
@@ -275,14 +275,14 @@ public class Drill extends Block{
speed *= efficiency(); // Drill slower when not at full power speed *= efficiency(); // Drill slower when not at full power
lastDrillSpeed = (speed * dominantItems * warmup) / (drillTime + hardnessDrillMultiplier * dominantItem.hardness); lastDrillSpeed = (speed * dominantItems * warmup) / (drillTime + hardnessDrillMultiplier * dominantItem.hardness);
warmup = Mathf.lerpDelta(warmup, speed, warmupSpeed); warmup = Mathf.approachDelta(warmup, speed, warmupSpeed);
progress += delta() * dominantItems * speed * warmup; progress += delta() * dominantItems * speed * warmup;
if(Mathf.chanceDelta(updateEffectChance * warmup)) if(Mathf.chanceDelta(updateEffectChance * warmup))
updateEffect.at(x + Mathf.range(size * 2f), y + Mathf.range(size * 2f)); updateEffect.at(x + Mathf.range(size * 2f), y + Mathf.range(size * 2f));
}else{ }else{
lastDrillSpeed = 0f; lastDrillSpeed = 0f;
warmup = Mathf.lerpDelta(warmup, 0f, warmupSpeed); warmup = Mathf.approachDelta(warmup, 0f, warmupSpeed);
return; return;
} }

View File

@@ -28,11 +28,7 @@ public class Incinerator extends Block{
@Override @Override
public void updateTile(){ public void updateTile(){
if(consValid() && efficiency() > 0.9f){ heat = Mathf.approachDelta(heat, consValid() && efficiency() > 0.9f ? 1f : 0f, 0.04f);
heat = Mathf.lerpDelta(heat, 1f, 0.04f);
}else{
heat = Mathf.lerpDelta(heat, 0f, 0.02f);
}
} }
@Override @Override

View File

@@ -20,6 +20,7 @@ public class Pump extends LiquidBlock{
super(name); super(name);
group = BlockGroup.liquids; group = BlockGroup.liquids;
floating = true; floating = true;
envEnabled = Env.terrestrial;
} }
@Override @Override
@@ -61,7 +62,7 @@ public class Pump extends LiquidBlock{
} }
@Override @Override
public boolean canPlaceOn(Tile tile, Team team){ public boolean canPlaceOn(Tile tile, Team team, int rotation){
if(isMultiblock()){ if(isMultiblock()){
Liquid last = null; Liquid last = null;
for(Tile other : tile.getLinkedTilesAs(this, tempTiles)){ for(Tile other : tile.getLinkedTilesAs(this, tempTiles)){

View File

@@ -31,6 +31,8 @@ public class SolidPump extends Pump{
public SolidPump(String name){ public SolidPump(String name){
super(name); super(name);
hasPower = true; hasPower = true;
//only supports ground by default
envEnabled = Env.terrestrial;
} }
@Override @Override
@@ -63,7 +65,7 @@ public class SolidPump extends Pump{
} }
@Override @Override
public boolean canPlaceOn(Tile tile, Team team){ public boolean canPlaceOn(Tile tile, Team team, int rotation){
float sum = tile.getLinkedTilesAs(this, tempTiles).sumf(t -> canPump(t) ? baseEfficiency + (attribute != null ? t.floor().attributes.get(attribute) : 0f) : 0f); float sum = tile.getLinkedTilesAs(this, tempTiles).sumf(t -> canPump(t) ? baseEfficiency + (attribute != null ? t.floor().attributes.get(attribute) : 0f) : 0f);
return sum > 0.00001f; return sum > 0.00001f;
} }

View File

@@ -27,6 +27,7 @@ public class LiquidSource extends Block{
noUpdateDisabled = true; noUpdateDisabled = true;
displayFlow = false; displayFlow = false;
group = BlockGroup.liquids; group = BlockGroup.liquids;
envEnabled = Env.any;
config(Liquid.class, (LiquidSourceBuild tile, Liquid l) -> tile.source = l); config(Liquid.class, (LiquidSourceBuild tile, Liquid l) -> tile.source = l);
configClear((LiquidSourceBuild tile) -> tile.source = null); configClear((LiquidSourceBuild tile) -> tile.source = null);

Some files were not shown because too many files have changed in this diff Show More