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

View File

@@ -380,7 +380,7 @@ public class Vars implements Loadable{
log.log(level, text);
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();
}catch(IOException e){
e.printStackTrace();

View File

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

View File

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

View File

@@ -35,7 +35,7 @@ public class Blocks implements ContentList{
public static Block
//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,
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,
@@ -435,18 +435,6 @@ public class Blocks implements ContentList{
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);
metalFloorDamaged = new Floor("metal-floor-damaged", 3);
@@ -2105,14 +2093,15 @@ public class Blocks implements ContentList{
}};
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;
consumes.power(2f);
size = 3;
}};
//yes this block is pretty much useless
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;
consumes.power(2f);
maxBlockSize = 4;
@@ -2121,20 +2110,20 @@ public class Blocks implements ContentList{
}};
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;
consumes.power(2f);
size = 3;
}};
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;
consumes.power(2f);
size = 3;
}};
//TODO deprecated
//deprecated, will be removed.
blockForge = constructor;
blockLoader = payloadLoader;
blockUnloader = payloadUnloader;

View File

@@ -14,7 +14,7 @@ public class Planets implements ContentList{
@Override
public void load(){
sun = new Planet("sun", null, 0, 2){{
sun = new Planet("sun", null, 4){{
bloom = true;
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();
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");
atmosphereRadIn = 0.02f;
atmosphereRadOut = 0.3f;

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
package mindustry.core;
import arc.*;
import arc.assets.loaders.TextureLoader.*;
import arc.files.*;
import arc.graphics.*;
import arc.graphics.Texture.*;
@@ -42,12 +43,14 @@ public class Renderer implements ApplicationListener{
public PlanetRenderer planets;
public @Nullable Bloom bloom;
public @Nullable FrameBuffer backgroundBuffer;
public FrameBuffer effectBuffer = new FrameBuffer();
public boolean animateShields, drawWeather = true, drawStatus;
public float weatherAlpha;
/** minZoom = zooming out, maxZoom = zooming in */
public float minZoom = 1.5f, maxZoom = 6f;
public Seq<EnvRenderer> envRenderers = new Seq<>();
public ObjectMap<String, Runnable> customBackgrounds = new ObjectMap<>();
public TextureRegion[] bubbles = new TextureRegion[16], splashes = new TextureRegion[12];
private @Nullable CoreBuild landCore;
@@ -88,6 +91,10 @@ public class Renderer implements ApplicationListener{
envRenderers.add(new EnvRenderer(mask, render));
}
public void addCustomBackground(String name, Runnable render){
customBackgrounds.put(name, render);
}
@Override
public void init(){
planets = new PlanetRenderer();
@@ -108,6 +115,14 @@ public class Renderer implements ApplicationListener{
t.setWrap(TextureWrap.repeat);
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
@@ -311,8 +326,81 @@ public class Renderer implements ApplicationListener{
Events.fire(Trigger.postDraw);
}
private void drawBackground(){
//nothing to draw currently
protected void drawBackground(){
//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(){

View File

@@ -588,7 +588,7 @@ public class UI implements ApplicationListener, Loadable{
if(mag >= 1_000_000_000){
return sign + Strings.fixed(mag / 1_000_000_000f, 1) + "[gray]" + billions+ "[]";
}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){
return number / 1000 + "[gray]" + thousands + "[]";
}else if(mag >= 1000){

View File

@@ -8,6 +8,7 @@ import arc.math.geom.Geometry.*;
import arc.struct.*;
import arc.util.*;
import arc.util.noise.*;
import mindustry.*;
import mindustry.content.*;
import mindustry.core.GameState.*;
import mindustry.ctype.*;
@@ -246,15 +247,17 @@ public class World{
if(sector.preset != null){
sector.preset.generator.generate(tiles);
sector.preset.rules.get(state.rules); //apply extra rules
}else{
}else if(sector.planet.generator != null){
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
state.rules.sector = sector;
});
//postgenerate for bases
if(sector.preset == null){
if(sector.preset == null && sector.planet.generator != null){
sector.planet.generator.postGenerate(tiles);
}
@@ -477,12 +480,14 @@ public class World{
//TODO optimize; this is very slow and called too often!
public float getDarkness(int x, int y){
int edgeBlend = 2;
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){
dark = Math.max((edgeBlend - edgeDst) * (4f / edgeBlend), dark);
if(Vars.state.rules.borderDarkness){
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){

View File

@@ -6,7 +6,7 @@ import mindustry.*;
import mindustry.mod.Mods.*;
/** 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;
/** Info on which mod this content was loaded from. */
public ModContentInfo minfo = new ModContentInfo();
@@ -39,11 +39,6 @@ public abstract class Content implements Comparable<Content>, Disposable{
return minfo.error != null;
}
@Override
public void dispose(){
//does nothing by default
}
@Override
public int compareTo(Content c){
return Integer.compare(id, c.id);

View File

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

View File

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

View File

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

View File

@@ -8,6 +8,7 @@ import mindustry.annotations.Annotations.*;
import mindustry.content.*;
import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.type.*;
import mindustry.world.blocks.environment.*;
import static mindustry.Vars.*;
@@ -16,14 +17,16 @@ import static mindustry.Vars.*;
abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
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 UnitType type;
@SyncLocal float elevation;
private transient boolean wasFlying;
transient boolean hovering;
transient float drownTime;
transient float splashTimer;
transient @Nullable Floor lastDrownFloor;
boolean checkTarget(boolean targetAir, boolean targetGround){
return (isGrounded() && targetGround) || (isFlying() && targetAir);
@@ -41,6 +44,10 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
return isGrounded() && !hovering;
}
@Nullable Floor drownFloor(){
return canDrown() ? floorOn() : null;
}
boolean emitWalkSound(){
return true;
}
@@ -90,20 +97,27 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
}
}
if(canDrown() && floor.isLiquid && floor.drownTime > 0){
drownTime += Time.delta / floor.drownTime;
drownTime = Mathf.clamp(drownTime);
updateDrowning();
}
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)){
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()){
kill();
Events.fire(new UnitDrownEvent(self()));
}
}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.gen.*;
import mindustry.graphics.*;
import mindustry.ui.*;
import mindustry.world.*;
@EntityDef(value = LaunchCorec.class, serialize = false)

View File

@@ -9,6 +9,7 @@ import mindustry.annotations.Annotations.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.EntityCollisions.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
@@ -18,22 +19,30 @@ import mindustry.world.blocks.environment.*;
abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{
@Import float x, y;
@Import UnitType type;
@Import Team team;
transient Leg[] legs = {};
transient float totalLength;
transient float moveSpace;
transient float baseRotation;
transient Floor lastDeepFloor;
@Replace
@Override
public SolidPred solidity(){
return !type.allowLegStep ? EntityCollisions::solid : EntityCollisions::legsSolid;
return type.allowLegStep ? EntityCollisions::legsSolid : EntityCollisions::solid;
}
@Override
@Replace
public int pathType(){
return Pathfinder.costLegs;
return type.allowLegStep ? Pathfinder.costGround : Pathfinder.costLegs;
}
@Override
@Replace
public Floor drownFloor(){
return lastDeepFloor;
}
@Override
@@ -41,10 +50,18 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{
resetLegs();
}
@Override
public void unloaded(){
resetLegs(1f);
}
public void resetLegs(){
resetLegs(type.legLength);
}
public void resetLegs(float legLength){
float rot = baseRotation;
int count = type.legCount;
float legLength = type.legLength;
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);
boolean moving = moving();
lastDeepFloor = null;
int deeps = 0;
for(int i = 0; i < legs.length; i++){
float dstRot = legAngle(rot, i);
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.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){
//create effect when transitioning to a group it can't move in
if(!move && i % div == l.group){
Floor floor = Vars.world.floorWorld(l.base.x, l.base.y);
if(floor.isLiquid){
floor.walkEffect.at(l.base.x, l.base.y, type.rippleScale, floor.mapColor);
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){
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);
}
//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. */

View File

@@ -10,6 +10,7 @@ import mindustry.entities.*;
import mindustry.gen.*;
import mindustry.type.*;
import mindustry.world.*;
import mindustry.world.blocks.environment.*;
import static mindustry.Vars.*;
@@ -62,6 +63,21 @@ abstract class MechComp implements Posc, Flyingc, Hitboxc, Unitc, Mechc, Elevati
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){
//now ranges from -maxExtension to maxExtension*3

View File

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

View File

@@ -45,12 +45,18 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
boolean spawnedByCore;
double flag;
transient float shadowAlpha = -1f;
transient Seq<Ability> abilities = new Seq<>(0);
transient float healTime;
private transient float resupplyTime = Mathf.random(10f);
private transient boolean wasPlayer;
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. */
public void movePref(Vec2 movement){
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();
}

View File

@@ -6,6 +6,7 @@ import arc.util.*;
import arc.util.serialization.*;
import arc.util.serialization.Json.*;
import mindustry.content.*;
import mindustry.graphics.g3d.*;
import mindustry.io.*;
import mindustry.type.*;
import mindustry.type.Weather.*;
@@ -117,8 +118,22 @@ public class Rules{
public @Nullable String modeName;
/** Whether cores incinerate items when full, just like in the campaign. */
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. */
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. */
public Rules copy(){
@@ -140,6 +155,10 @@ public class Rules{
}
}
public boolean hasEnv(int env){
return (environment & env) != 0;
}
public float unitBuildSpeed(Team team){
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
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
state.rules.ambientLight.a = 1f - alpha;

View File

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

View File

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

View File

@@ -23,6 +23,7 @@ public class Shaders{
public static LightShader light;
public static SurfaceShader water, mud, tar, slag, cryofluid, space, caustics;
public static PlanetShader planet;
public static CloudShader clouds;
public static PlanetGridShader planetGrid;
public static AtmosphereShader atmosphere;
public static MeshShader mesh;
@@ -56,6 +57,7 @@ public class Shaders{
// }
//};
planet = new PlanetShader();
clouds = new CloudShader();
planetGrid = new PlanetGridShader();
atmosphere = new AtmosphereShader();
unlit = new LoadShader("planet", "unlit");
@@ -94,6 +96,7 @@ public class Shaders{
public Vec3 lightDir = new Vec3(1, 1, 1).nor();
public Color ambientColor = Color.white.cpy();
public Vec3 camDir = new Vec3();
public Planet planet;
public PlanetShader(){
super("planet", "planet");
@@ -101,7 +104,7 @@ public class Shaders{
@Override
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_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 MeshShader(){
@@ -176,6 +200,7 @@ public class Shaders{
public static class BlockBuildShader extends LoadShader{
public float progress;
public TextureRegion region = new TextureRegion();
public float time;
public BlockBuildShader(){
super("blockbuild", "default");
@@ -186,7 +211,7 @@ public class Shaders{
setUniformf("u_progress", progress);
setUniformf("u_uv", region.u, region.v);
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);
}
}

View File

@@ -396,7 +396,7 @@ public class Voronoi{
private void clipLine(Edge e){
float pxmin, pxmax, pymin, pymax;
Site s1, s2;
float x1 = 0, x2 = 0, y1 = 0, y2 = 0;
float x1, x2, y1, y2;
x1 = e.reg[0].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);
}
public HexMesh(){
}
@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.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 final Ptile empty = new Ptile(0, 0);
public int id;
public int edgeCount;

View File

@@ -3,14 +3,13 @@ package mindustry.graphics.g3d;
import arc.graphics.*;
import arc.graphics.gl.*;
import arc.math.geom.*;
import arc.util.*;
import mindustry.type.*;
/** Defines a mesh that is rendered for a planet. Subclasses provide a mesh and a shader. */
public abstract class PlanetMesh implements Disposable{
protected final Mesh mesh;
protected final Planet planet;
protected final Shader shader;
public abstract class PlanetMesh implements GenericMesh{
protected Mesh mesh;
protected Planet planet;
protected Shader shader;
public PlanetMesh(Planet planet, Mesh mesh, Shader shader){
this.planet = planet;
@@ -18,20 +17,21 @@ public abstract class PlanetMesh implements Disposable{
this.shader = shader;
}
/** Should be overridden to set up any shader parameters such as planet position, normals, etc. */
public abstract void preRender();
public PlanetMesh(){}
public void render(Mat3D projection, Mat3D transform){
preRender();
/** Should be overridden to set up any shader parameters such as planet position, normals, etc.
* @param params*/
public void preRender(PlanetParams params){
}
@Override
public void render(PlanetParams params, Mat3D projection, Mat3D transform){
preRender(params);
shader.bind();
shader.setUniformMatrix4("u_proj", projection.val);
shader.setUniformMatrix4("u_trans", transform.val);
shader.apply();
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.struct.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.game.EventType.*;
import mindustry.graphics.*;
import mindustry.graphics.g3d.PlanetGrid.*;
@@ -25,25 +24,15 @@ public class PlanetRenderer implements Disposable{
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. */
public Camera3D cam = new Camera3D();
public final Camera3D cam = new Camera3D();
/** Raw vertex batch. */
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];
public final PlaneBatch3D projector = new PlaneBatch3D();
public final Mat3D mat = new Mat3D();
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){{
setThreshold(0.8f);
@@ -55,16 +44,13 @@ public class PlanetRenderer implements Disposable{
public final CubemapMesh skybox = new CubemapMesh(new Cubemap("cubemaps/stars/"));
public PlanetRenderer(){
camPos.set(0, 0f, camLength);
projector.setScaling(1f / 150f);
cam.fov = 60f;
cam.far = 150f;
}
/** Render the entire planet scene to the screen. */
public void render(PlanetInterfaceRenderer irenderer){
this.irenderer = irenderer;
public void render(PlanetParams params){
Draw.flush();
Gl.clear(Gl.depthBufferBit);
Gl.enable(Gl.depthTest);
@@ -73,49 +59,63 @@ public class PlanetRenderer implements Disposable{
Gl.enable(Gl.cullFace);
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
cam.up.set(Vec3.Y);
cam.resize(Core.graphics.getWidth(), Core.graphics.getHeight());
camPos.setLength(planet.radius * camLength + (zoom-1f) * planet.radius * 2);
cam.position.set(planet.position).add(camPos);
cam.lookAt(planet.position);
cam.resize(w, h);
params.camPos.setLength((params.planet.radius + params.planet.camRadius) * camLength + (params.zoom-1f) * (params.planet.radius + params.planet.camRadius) * 2);
cam.position.set(params.planet.position).add(params.camPos);
//cam.up.set(params.camUp); //TODO broken
cam.lookAt(params.planet.position);
cam.update();
//write back once it changes.
params.camUp.set(cam.up);
params.camDir.set(cam.direction);
projector.proj(cam.combined);
batch.proj(cam.combined);
Events.fire(Trigger.universeDrawBegin);
beginBloom();
//begin bloom
bloom.resize(w, h);
bloom.capture();
//render skybox at 0,0,0
Vec3 lastPos = Tmp.v31.set(cam.position);
cam.position.setZero();
cam.update();
if(params.drawSkybox){
//render skybox at 0,0,0
Vec3 lastPos = Tmp.v31.set(cam.position);
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.update();
cam.position.set(lastPos);
cam.update();
}
Events.fire(Trigger.universeDraw);
renderPlanet(solarSystem);
renderPlanet(params.solarSystem, params);
renderTransparent(params.solarSystem, params);
renderTransparent(solarSystem);
endBloom();
bloom.render();
Events.fire(Trigger.universeDrawEnd);
Gl.enable(Gl.blend);
irenderer.renderProjections(planet);
if(params.renderer != null){
params.renderer.renderProjections(params.planet);
}
Gl.disable(Gl.cullFace);
Gl.disable(Gl.depthTest);
@@ -123,68 +123,64 @@ public class PlanetRenderer implements Disposable{
cam.update();
}
public void beginBloom(){
bloom.resize(Core.graphics.getWidth(), Core.graphics.getHeight());
bloom.capture();
}
public void endBloom(){
bloom.render();
}
public void renderPlanet(Planet planet){
public void renderPlanet(Planet planet, PlanetParams params){
if(!planet.visible()) return;
cam.update();
if(cam.frustum.containsSphere(planet.position, planet.clipRadius)){
//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){
renderPlanet(child);
renderPlanet(child, params);
}
}
public void renderTransparent(Planet planet){
public void renderTransparent(Planet planet, PlanetParams params){
if(!planet.visible()) return;
if(planet.hasGrid() && planet == this.planet){
renderSectors(planet);
planet.drawClouds(params, cam.combined, planet.getTransform(mat));
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.drawClouds(cam.combined, planet.getTransform(mat));
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){
if(planet.parent == null || !planet.visible() || orbitAlpha <= 0.02f) return;
public void renderOrbit(Planet planet, PlanetParams params){
if(planet.parent == null || !planet.visible() || params.uiAlpha <= 0.02f || !planet.drawOrbit) return;
Vec3 center = planet.parent.position;
float radius = planet.orbitRadius;
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);
}
public void renderSectors(Planet planet){
if(orbitAlpha <= 0.02f) return;
public void renderSectors(Planet planet, PlanetParams params){
if(params.uiAlpha <= 0.02f) return;
//apply transformed position
batch.proj().mul(planet.getTransform(mat));
irenderer.renderSectors(planet);
if(params.renderer != null){
params.renderer.renderSectors(planet);
}
//render sector grid
Mesh mesh = outline(planet.grid.size);
@@ -262,12 +258,12 @@ public class PlanetRenderer implements Disposable{
}
public void setPlane(Sector sector){
float rotation = -planet.getRotation();
float rotation = -sector.planet.getRotation();
float length = 0.01f;
projector.setPlane(
//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
sector.plane.project(Tmp.v32.set(sector.tile.v).add(Vec3.Y)).sub(sector.tile.v).rotate(Vec3.Y, rotation).nor(),
//right vector

View File

@@ -8,9 +8,4 @@ public class ShaderSphereMesh extends PlanetMesh{
public ShaderSphereMesh(Planet planet, Shader shader, int divisions){
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);
}
@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<>(){
@Override
public void write(Json json, Weather object, Class knownType){

View File

@@ -56,7 +56,10 @@ public abstract class SaveFileReader{
"water", "shallow-water",
"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(

View File

@@ -123,6 +123,11 @@ public abstract class PlanetGenerator extends BasicGenerator implements HexMeshe
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){
this.tiles = tiles;
this.sector = sec;

View File

@@ -218,14 +218,8 @@ public class ClassMap{
classes.put("SwitchBuild", mindustry.world.blocks.logic.SwitchBlock.SwitchBuild.class);
classes.put("BallisticSilo", mindustry.world.blocks.payloads.BallisticSilo.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("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("NuclearWarhead", mindustry.world.blocks.payloads.NuclearWarhead.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;
}
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){
for(Item item : Vars.content.items()){
set(item, Math.min(get(item), number));
@@ -90,6 +105,12 @@ public class ItemSeq implements Iterable<ItemStack>, JsonSerializable{
itemModule.each(this::add);
}
public void add(ItemStack[] stacks){
for(var s : stacks){
add(s);
}
}
public void add(ItemSeq seq){
seq.each(this::add);
}

View File

@@ -18,14 +18,12 @@ import mindustry.maps.generators.*;
import static mindustry.Vars.*;
public class Planet extends UnlockableContent{
/** Default spacing between planet orbits in world units. */
private static final float orbitSpacing = 11f;
/** intersect() temp var. */
private static final Vec3 intersectResult = new Vec3();
/** 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. */
public @Nullable PlanetMesh cloudMesh;
public @Nullable GenericMesh cloudMesh;
/** Position in global coordinates. Will be 0,0,0 until the Universe updates it. */
public Vec3 position = new Vec3();
/** 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. */
public @Nullable PlanetGenerator generator;
/** 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. */
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. */
public float atmosphereRadIn = 0, atmosphereRadOut = 0.3f;
/** Frustrum sphere clip radius. */
@@ -48,12 +54,18 @@ public class Planet extends UnlockableContent{
public float orbitTime;
/** Time for the planet to perform a full revolution, in seconds. One day. */
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. */
public float sectorApproxRadius;
/** Whether this planet is tidally locked relative to its parent - see https://en.wikipedia.org/wiki/Tidal_locking */
public boolean tidalLock = false;
/** Whether this planet is listed in the planet access UI. **/
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. */
public int startSector = 0;
/** Whether the bloom render effect is enabled. */
@@ -77,32 +89,20 @@ public class Planet extends UnlockableContent{
/** Satellites orbiting this planet. */
public Seq<Satellite> satellites = new Seq<>();
/** 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);
this.radius = radius;
this.parent = parent;
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<>();
}
this.orbitOffset = Mathf.randomSeed(id, 360);
//total radius is initially just the radius
totalRadius += radius;
totalRadius = 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]
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);
}
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(){
if(sectors.isEmpty()){
return null;
@@ -137,6 +152,11 @@ public class Planet extends UnlockableContent{
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(){
totalRadius = radius;
for(Planet planet : children){
@@ -151,9 +171,7 @@ public class Planet extends UnlockableContent{
/** Calculates orbital rotation based on universe time.*/
public float getOrbitAngle(){
//applies random offset to prevent planets from starting out in a line
float offset = Mathf.randomSeed(id, 360);
return (offset + universe.secondsf() / (orbitTime / 360f)) % 360f;
return (orbitOffset + universe.secondsf() / (orbitTime / 360f)) % 360f;
}
/** 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. */
public void reloadMesh(){
if(mesh != null){
mesh.dispose();
}
mesh = meshLoader.get();
}
@@ -246,14 +261,6 @@ public class Planet extends UnlockableContent{
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. */
public Sector getSector(Ptile tile){
return sectors.get(tile.id);
@@ -294,8 +301,8 @@ public class Planet extends UnlockableContent{
return visible;
}
public void draw(Mat3D projection, Mat3D transform){
mesh.render(projection, transform);
public void draw(PlanetParams params, Mat3D projection, Mat3D transform){
mesh.render(params, projection, transform);
}
public void drawAtmosphere(Mesh atmosphere, Camera3D cam){
@@ -316,9 +323,9 @@ public class Planet extends UnlockableContent{
Gl.depthMask(true);
}
public void drawClouds(Mat3D projection, Mat3D transform){
public void drawClouds(PlanetParams params, Mat3D projection, Mat3D transform){
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.tile = tile;
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;
}
@@ -156,9 +161,7 @@ public class Sector{
/** @return the sector size, in tiles */
public int getSize(){
if(planet.generator == null) return 1;
int res = (int)(rect.radius * planet.generator.getSizeScl());
return res % 2 == 0 ? res : res + 1;
return planet.generator == null ? 1 : planet.generator.getSectorSize(this);
}
public void removeItems(ItemSeq items){

View File

@@ -71,9 +71,13 @@ public class UnitType extends UnlockableContent{
public int commandLimit = 8;
public float commandRadius = 150f;
public float visualElevation = -1f;
/** If true and this is a legged unit, this unit can walk over blocks. */
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 omniMovement = true;
public boolean showHeal = true;
public Color healColor = Pal.heal;
public Effect fallEffect = Fx.fallSmoke;
public Effect fallThrusterEffect = Fx.fallSmoke;
public Effect deathExplosionEffect = Fx.dynamicExplosion;
@@ -112,13 +116,14 @@ public class UnitType extends UnlockableContent{
public float dpsEstimate = -1;
public float clipSize = -1;
public boolean canDrown = true, naval = false;
public float drownTimeMultiplier = 1f;
public float engineOffset = 5f, engineSize = 2.5f;
public float strafePenalty = 0.5f;
public float hitSize = 6f;
public float itemOffsetY = 3f;
public float lightRadius = -1f, lightOpacity = 0.6f;
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 float trailX = 4f, trailY = -3f, trailScl = 1f;
/** Whether the unit can heal blocks. Initialized in init() */
@@ -135,7 +140,9 @@ public class UnitType extends UnlockableContent{
softShadowRegion, jointRegion, footRegion, legBaseRegion, baseJointRegion, outlineRegion;
public TextureRegion[] wreckRegions;
protected float buildTime = -1f;
protected @Nullable ItemStack[] cachedRequirements;
protected @Nullable ItemStack[] totalRequirements;
public UnitType(String name){
super(name);
@@ -312,6 +319,8 @@ public class UnitType extends UnlockableContent{
Unit example = constructor.get();
allowLegStep = example instanceof Legsc;
//water preset
if(example instanceof WaterMovec){
naval = true;
@@ -323,6 +332,10 @@ public class UnitType extends UnlockableContent{
}
}
if(flying){
envEnabled |= Env.space;
}
if(lightRadius == -1){
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
public ItemStack[] researchRequirements(){
if(cachedRequirements != null){
return cachedRequirements;
}
ItemStack[] stacks = 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;
}
}
ItemStack[] stacks = getRequirements(null, null);
if(stacks != null){
ItemStack[] out = new ItemStack[stacks.length];
@@ -557,10 +617,10 @@ public class UnitType extends UnlockableContent{
Draw.z(z);
drawOutline(unit);
if(drawBody) drawOutline(unit);
drawWeaponOutlines(unit);
if(engineSize > 0) drawEngine(unit);
drawBody(unit);
if(drawBody) drawBody(unit);
if(drawCell) drawCell(unit);
drawWeapons(unit);
if(drawItems) drawItems(unit);
@@ -623,14 +683,25 @@ public class UnitType extends UnlockableContent{
}
public void drawShadow(Unit unit){
Draw.color(Pal.shadow);
float e = Math.max(unit.elevation, visualElevation);
float e = Math.max(unit.elevation, visualElevation) * (1f - unit.drownTime);
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.color();
}
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 size = Math.max(region.width, region.height) * Draw.scl;
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();
}
public void applyOutlineColor(Unit unit){
if(unit.isBoss()){
Draw.mixcol(unit.team.color, Mathf.absin(7f, 1f));
}
}
public void drawOutline(Unit unit){
Draw.reset();
if(Core.atlas.isFound(outlineRegion)){
applyColor(unit);
applyOutlineColor(unit);
Draw.rect(outlineRegion, unit.x, unit.y, unit.rotation - 90);
Draw.reset();
@@ -764,14 +830,16 @@ public class UnitType extends UnlockableContent{
public <T extends Unit & Legsc> void drawLegs(T unit){
applyColor(unit);
Tmp.c3.set(Draw.getMixColor());
Leg[] legs = unit.legs();
float ssize = footRegion.width * Draw.scl * 1.5f;
float rotation = unit.baseRotation();
float invDrown = 1f - unit.drownTime;
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
@@ -787,13 +855,15 @@ public class UnitType extends UnlockableContent{
Tmp.v1.set(leg.base).sub(leg.joint).inv().setLength(legExtension);
if(leg.moving && visualElevation > 0){
float scl = visualElevation;
float scl = visualElevation * invDrown;
float elev = Mathf.slope(1f - leg.stage) * scl;
Draw.color(Pal.shadow);
Draw.rect(footRegion, leg.base.x + shadowTX * elev, leg.base.y + shadowTY * elev, position.angleTo(leg.base));
Draw.color();
}
Draw.mixcol(Tmp.c3, Tmp.c3.a);
Draw.rect(footRegion, leg.base.x, leg.base.y, position.angleTo(leg.base));
Lines.stroke(legRegion.height * Draw.scl * flips);
@@ -848,8 +918,8 @@ public class UnitType extends UnlockableContent{
Draw.mixcol(Color.white, unit.hitTime);
if(floor.isLiquid){
Draw.color(Color.white, floor.mapColor, unit.drownTime() * 0.4f);
if(unit.lastDrownFloor != null){
Draw.color(Color.white, Tmp.c1.set(unit.lastDrownFloor.mapColor).mul(0.83f), unit.drownTime * 0.9f);
}else{
Draw.color(Color.white);
}
@@ -859,13 +929,25 @@ public class UnitType extends UnlockableContent{
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){
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)));
if(unit.drownTime > 0 && unit.floorOn().isDeep()){
Draw.mixcol(unit.floorOn().mapColor, unit.drownTime * 0.8f);
if(unit.drownTime > 0 && unit.lastDrownFloor != null){
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;
/** displayed weapon region */
public String name = "";
public String name;
/** bullet shot */
public BulletType bullet = Bullets.standardCopper;
/** shell ejection effect */

View File

@@ -148,6 +148,8 @@ public class Weather extends UnlockableContent{
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){

View File

@@ -11,11 +11,12 @@ import static mindustry.Vars.*;
/** Class for handling menus and notifications across the network. Unstable API! */
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. */
public static void registerMenu(int id, MenuListener listener){
menuListeners.put(id, listener);
public static int registerMenu(MenuListener listener){
menuListeners.add(listener);
return menuListeners.size - 1;
}
//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)
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));
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){
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));
}else{
connect(ip, port);

View File

@@ -97,7 +97,7 @@ public class MapPlayDialog extends BaseDialog{
table.row();
for(Gamemode mode : Gamemode.values()){
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();
}

View File

@@ -15,6 +15,7 @@ import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*;
import mindustry.*;
import mindustry.content.*;
import mindustry.content.TechTree.*;
import mindustry.core.*;
@@ -24,6 +25,7 @@ import mindustry.game.SectorInfo.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.graphics.g3d.PlanetGrid.*;
import mindustry.graphics.g3d.*;
import mindustry.input.*;
import mindustry.maps.*;
@@ -49,10 +51,11 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
public static float sectorShowDuration = 60f * 2.4f;
public final FrameBuffer buffer = new FrameBuffer(2, 2, true);
public final PlanetRenderer planets = renderer.planets;
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 Mode mode = look;
public boolean launching;
@@ -68,10 +71,13 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
public PlanetDialog(){
super("", Styles.fullDialog);
state.renderer = this;
state.drawUi = true;
shouldPause = true;
planets.planet = content.getByName(ContentType.planet, Core.settings.getString("lastplanet", "serpulo"));
if(planets.planet == null) planets.planet = Planets.serpulo;
state.planet = content.getByName(ContentType.planet, Core.settings.getString("lastplanet", "serpulo"));
if(state.planet == null) state.planet = Planets.serpulo;
addListener(new InputListener(){
@Override
@@ -107,7 +113,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
newPresets.clear();
}
Vec3 pos = planets.camPos;
Vec3 pos = state.camPos;
float upV = pos.angle(Vec3.Y);
float xscale = 9f, yscale = 10f;
@@ -116,20 +122,20 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
//scale X speed depending on polar coordinate
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
float amount = cy / yscale;
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(){
@Override
public boolean scrolled(InputEvent event, float x, float y, float amountX, float amountY){
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;
}
@@ -144,7 +150,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
lastZoom = zoom;
}
zoom = (Mathf.clamp(initialDistance / distance * lastZoom, 0.5f, 2f));
zoom = (Mathf.clamp(initialDistance / distance * lastZoom, state.planet.minZoom, 2f));
}
@Override
@@ -170,9 +176,9 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
launching = false;
zoom = 1f;
planets.zoom = 1f;
selectAlpha = 0f;
launchSector = state.getSector();
state.zoom = 1f;
state.uiAlpha = 0f;
launchSector = Vars.state.getSector();
presetShow = 0f;
showed = false;
listener = s -> {};
@@ -181,7 +187,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
//announce new presets
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);
preset.sector.info.shown = true;
preset.sector.saveInfo();
@@ -189,14 +195,14 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
}
if(newPresets.any()){
newPresets.add(planets.planet.getLastSector());
newPresets.add(state.planet.getLastSector());
}
newPresets.reverse();
updateSelected();
if(planets.planet.getLastSector() != null){
lookAt(planets.planet.getLastSector());
if(state.planet.getLastSector() != null){
lookAt(state.planet.getLastSector());
}
return super.show();
@@ -252,8 +258,8 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
//update view to sector
zoom = 1f;
planets.zoom = 1f;
selectAlpha = 0f;
state.zoom = 1f;
state.uiAlpha = 0f;
mode = planetLaunch;
@@ -269,8 +275,8 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
//update view to sector
lookAt(sector);
zoom = 1f;
planets.zoom = 1f;
selectAlpha = 0f;
state.zoom = 1f;
state.uiAlpha = 0f;
launchSector = sector;
mode = select;
@@ -279,7 +285,9 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
}
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){
@@ -307,7 +315,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
launchFrom = to.near().find(Sector::hasBase);
if(launchFrom == null && to.preset != null){
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;
}
}
@@ -323,7 +331,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
public void renderSectors(Planet planet){
//draw all sector stuff
if(selectAlpha > 0.01f){
if(state.uiAlpha > 0.01f){
for(Sector sec : planet.sectors){
if(canSelect(sec) || sec.unlocked() || debugSelect){
@@ -336,15 +344,15 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
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{
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){
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){
if(sec.hasBase()){
for(Sector enemy : sec.near()){
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()){
//imports
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
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){
planets.drawPlane(sec, () -> {
//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);
});
}
@@ -444,13 +452,13 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
boolean selectable(Planet planet){
//TODO what if any sector is selectable?
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(){
searchText = "";
zoom = planets.zoom = 1f;
selectAlpha = 1f;
zoom = state.zoom = 1f;
state.uiAlpha = 1f;
ui.minimapfrag.hide();
clearChildren();
@@ -492,8 +500,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
@Override
public void draw(){
planets.orbitAlpha = selectAlpha;
planets.render(PlanetDialog.this);
planets.render(state);
}
},
//info text
@@ -518,12 +525,12 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
pt.button(planet.localizedName, Styles.clearTogglet, () -> {
selected = null;
launchSector = null;
if(renderer.planets.planet != planet){
renderer.planets.planet = planet;
if(state.planet != planet){
state.planet = planet;
rebuildList();
}
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();
}
}
@@ -533,8 +540,8 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
new Table(c -> {
c.visible(() -> !(graphics.isPortrait() && mobile));
if(planets.planet.sectors.contains(Sector::hasBase)){
int attacked = planets.planet.sectors.count(Sector::isAttacked);
if(state.planet.sectors.contains(Sector::hasBase)){
int attacked = state.planet.sectors.count(Sector::isAttacked);
//sector notifications & search
c.top().right();
@@ -564,7 +571,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
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)));
notifs.pane(p -> {
@@ -646,20 +653,20 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
}
public void lookAt(Sector sector, float alpha){
float len = planets.camPos.len();
planets.camPos.slerp(Tmp.v31.set(sector.tile.v).rotate(Vec3.Y, -sector.planet.getRotation()).setLength(len), alpha);
float len = state.camPos.len();
state.camPos.slerp(Tmp.v31.set(sector.tile.v).rotate(Vec3.Y, -sector.planet.getRotation()).setLength(len), alpha);
}
@Override
public void act(float delta){
super.act(delta);
if(hovered != null && !mobile){
if(hovered != null && !mobile && state.planet.hasGrid()){
addChild(hoverLabel);
hoverLabel.toFront();
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.getText().setLength(0);
@@ -704,14 +711,24 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
}
}
if(planets.planet.hasGrid()){
hovered = planets.planet.getSector(planets.cam.getMouseRay(), PlanetRenderer.outlineRad);
if(state.planet.hasGrid()){
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{
hovered = selected = null;
}
planets.zoom = Mathf.lerpDelta(planets.zoom, zoom, 0.4f);
selectAlpha = Mathf.lerpDelta(selectAlpha, Mathf.num(planets.zoom < 1.9f), 0.1f);
state.zoom = Mathf.lerpDelta(state.zoom, zoom, 0.4f);
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){
@@ -996,13 +1013,17 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
if(launching){
stable.color.sub(0, 0, 0, 0.05f * Time.delta);
}else{
//fade out UI when not facing selected sector
Tmp.v31.set(selected.tile.v).rotate(Vec3.Y, -planets.planet.getRotation()).scl(-1f).nor();
float dot = planets.cam.direction.dot(Tmp.v31);
stable.color.a = Math.max(dot, 0f)*2f;
if(dot*2f <= -0.1f){
selected = null;
updateSelected();
if(!state.planet.hasGrid()){
stable.color.a = 1f;
}else{
//fade out UI when not facing selected sector
Tmp.v31.set(selected.tile.v).rotate(Vec3.Y, -state.planet.getRotation()).scl(-1f).nor();
float dot = planets.cam.direction.dot(Tmp.v31);
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;
//save before launch.
if(control.saves.getCurrent() != null && state.isGame() && mode != select){
if(control.saves.getCurrent() != null && Vars.state.isGame() && mode != select){
try{
control.saves.getCurrent().save();
}catch(Throwable e){

View File

@@ -25,6 +25,7 @@ import mindustry.graphics.*;
import mindustry.graphics.MultiPacker.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.environment.*;
import mindustry.world.blocks.power.*;
import mindustry.world.consumers.*;
@@ -122,6 +123,8 @@ public class Block extends UnlockableContent{
public boolean useColor = true;
/** item that drops from this block, used for drills */
public @Nullable Item itemDrop = null;
/** Array of affinities to certain things. */
public Attributes attributes = new Attributes();
/** tile entity health */
public int health = -1;
/** base block explosiveness */
@@ -384,10 +387,16 @@ public class Block extends UnlockableContent{
}
/** 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){
return true;
}
public boolean canBreak(Tile tile){
return true;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -48,6 +48,7 @@ public class MassDriver extends Block{
hasPower = true;
outlineIcon = true;
sync = true;
envEnabled |= Env.space;
//point2 is relative
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;
outputsPayload = true;
noUpdateDisabled = true;
envEnabled |= Env.space;
sync = true;
}

View File

@@ -14,6 +14,7 @@ public class AirBlock extends Floor{
useColor = false;
wall = this;
needsSurface = false;
canShadow = false;
}
@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.type.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
import static mindustry.Vars.*;
@@ -54,8 +53,6 @@ public class Floor extends Block{
public boolean playerUnmineable = false;
/** Group of blocks that this block does not draw edges on. */
public Block blendGroup = this;
/** Array of affinities to certain things. */
public Attributes attributes = new Attributes();
/** Whether this ore generates in maps by default. */
public boolean oreDefault = false;
/** Ore generation params. */
@@ -64,6 +61,8 @@ public class Floor extends Block{
public Block wall = Blocks.air;
/** Decoration block. Usually a rock. May be 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. */
public boolean needsSurface = true;
@@ -116,10 +115,6 @@ public class Floor extends Block{
//keep default value if not found...
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){
walkEffect = Fx.ripple;
}

View File

@@ -1,14 +1,17 @@
package mindustry.world.blocks.experimental;
import mindustry.world.blocks.payloads.*;
/** @deprecated use Constructor instead. */
@Deprecated
public class BlockForge extends mindustry.world.blocks.payloads.BlockForge{
public class BlockForge extends Constructor{
public BlockForge(String name){
super(name);
}
@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;
import mindustry.world.blocks.payloads.*;
@Deprecated
public class BlockLoader extends mindustry.world.blocks.payloads.BlockLoader{
public class BlockLoader extends PayloadLoader{
public BlockLoader(String name){
super(name);
}
@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;
import mindustry.world.blocks.payloads.*;
@Deprecated
public class BlockUnloader extends mindustry.world.blocks.payloads.BlockUnloader{
public class BlockUnloader extends PayloadUnloader{
public BlockUnloader(String name){
super(name);
}
@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{
@Override
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);
}
}

View File

@@ -151,7 +151,7 @@ public class Conduit extends LiquidBlock implements Autotiler{
public boolean acceptLiquid(Building source, Liquid liquid){
noSleep();
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -80,16 +80,16 @@ public class PayloadBlock extends Block{
}
@Override
public boolean canControlSelect(Player player){
return !player.unit().spawnedByCore && this.payload == null && acceptUnitPayload(player.unit()) && player.tileOn() != null && player.tileOn().build == this;
public boolean canControlSelect(Unit player){
return !player.spawnedByCore && this.payload == null && acceptUnitPayload(player) && player.tileOn() != null && player.tileOn().build == this;
}
@Override
public void onControlSelect(Player player){
public void onControlSelect(Unit player){
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.payRotation = player.unit().rotation;
this.payRotation = player.rotation;
}
@Override

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -41,7 +41,7 @@ public class ThermalGenerator extends PowerGenerator{
}
@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
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. */
public float liquidBoostIntensity = 1.6f;
/** Speed at which the drill speeds up. */
public float warmupSpeed = 0.02f;
public float warmupSpeed = 0.015f;
//return variables for countOre
protected @Nullable Item returnItem;
@@ -108,7 +108,7 @@ public class Drill extends Block{
}
@Override
public boolean canPlaceOn(Tile tile, Team team){
public boolean canPlaceOn(Tile tile, Team team, int rotation){
if(isMultiblock()){
for(Tile other : tile.getLinkedTilesAs(this, tempTiles)){
if(canMine(other)){
@@ -275,14 +275,14 @@ public class Drill extends Block{
speed *= efficiency(); // Drill slower when not at full power
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;
if(Mathf.chanceDelta(updateEffectChance * warmup))
updateEffect.at(x + Mathf.range(size * 2f), y + Mathf.range(size * 2f));
}else{
lastDrillSpeed = 0f;
warmup = Mathf.lerpDelta(warmup, 0f, warmupSpeed);
warmup = Mathf.approachDelta(warmup, 0f, warmupSpeed);
return;
}

View File

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

View File

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

View File

@@ -31,6 +31,8 @@ public class SolidPump extends Pump{
public SolidPump(String name){
super(name);
hasPower = true;
//only supports ground by default
envEnabled = Env.terrestrial;
}
@Override
@@ -63,7 +65,7 @@ public class SolidPump extends Pump{
}
@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);
return sum > 0.00001f;
}

View File

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

View File

@@ -13,6 +13,7 @@ public class LiquidVoid extends Block{
solid = true;
update = true;
group = BlockGroup.liquids;
envEnabled = Env.any;
}
@Override

View File

@@ -121,7 +121,7 @@ public class CoreBlock extends StorageBlock{
}
@Override
public boolean canPlaceOn(Tile tile, Team team){
public boolean canPlaceOn(Tile tile, Team team, int rotation){
if(tile == null) return false;
CoreBuild core = team.core();
//must have all requirements
@@ -166,7 +166,7 @@ public class CoreBlock extends StorageBlock{
public void drawPlace(int x, int y, int rotation, boolean valid){
if(world.tile(x, y) == null) return;
if(!canPlaceOn(world.tile(x, y), player.team())){
if(!canPlaceOn(world.tile(x, y), player.team(), rotation)){
drawPlaceText(Core.bundle.get(
(player.team().core() != null && player.team().core().items.has(requirements, state.rules.buildCostMultiplier)) || state.rules.infiniteResources ?

View File

@@ -23,6 +23,7 @@ public class StorageBlock extends Block{
group = BlockGroup.transportation;
flags = EnumSet.of(BlockFlag.storage);
allowResupply = true;
envEnabled = Env.any;
}
@Override

View File

@@ -28,6 +28,7 @@ public class Unloader extends Block{
itemCapacity = 0;
noUpdateDisabled = true;
unloadable = false;
envEnabled = Env.any;
config(Item.class, (UnloaderBuild tile, Item item) -> tile.sortItem = item);
configClear((UnloaderBuild tile) -> tile.sortItem = null);

View File

@@ -37,6 +37,7 @@ public class CommandCenter extends Block{
configurable = true;
drawDisabled = false;
logicConfigurable = true;
envEnabled = Env.any;
config(UnitCommand.class, (CommandBuild build, UnitCommand command) -> {
if(build.team.data().command != command){

View File

@@ -59,6 +59,8 @@ public class RepairPoint extends Block{
outlineIcon = true;
//yeah, this isn't the same thing, but it's close enough
group = BlockGroup.projectors;
envEnabled |= Env.space;
}
@Override

View File

@@ -108,14 +108,18 @@ public class StatValues{
};
}
public static StatValue floorEfficiency(Floor floor, float multiplier, boolean startZero){
public static StatValue blockEfficiency(Block floor, float multiplier, boolean startZero){
return table -> table.stack(
new Image(floor.uiIcon).setScaling(Scaling.fit),
new Table(t -> t.top().right().add((multiplier < 0 ? "[scarlet]" : startZero ? "[accent]" : "[accent]+") + (int)((multiplier) * 100) + "%").style(Styles.outlineLabel))
);
}
public static StatValue floors(Attribute attr, boolean floating, float scale, boolean startZero){
public static StatValue blocks(Attribute attr, boolean floating, float scale, boolean startZero){
return blocks(attr, floating, scale, startZero, true);
}
public static StatValue blocks(Attribute attr, boolean floating, float scale, boolean startZero, boolean checkFloors){
return table -> table.table(c -> {
Runnable[] rebuild = {null};
Map[] lastMap = {null};
@@ -126,14 +130,14 @@ public class StatValues{
if(state.isGame()){
var blocks = Vars.content.blocks()
.select(block -> block instanceof Floor f && indexer.isBlockPresent(block) && f.attributes.get(attr) != 0 && !(f.isDeep() && !floating))
.select(block -> (!checkFloors || block instanceof Floor) && indexer.isBlockPresent(block) && block.attributes.get(attr) != 0 && !((block instanceof Floor f && f.isDeep()) && !floating))
.<Floor>as().with(s -> s.sort(f -> f.attributes.get(attr)));
if(blocks.any()){
int i = 0;
for(var block : blocks){
floorEfficiency(block, block.attributes.get(attr) * scale, startZero).display(c);
blockEfficiency(block, block.attributes.get(attr) * scale, startZero).display(c);
if(++i % 5 == 0){
c.row();
}

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