Merge remote-tracking branch 'upstream/master' into wall-stats
This commit is contained in:
@@ -89,7 +89,7 @@ public class Vars implements Loadable{
|
||||
/** duration of time between turns in ticks */
|
||||
public static final float turnDuration = 2 * Time.toMinutes;
|
||||
/** chance of an invasion per turn, 1 = 100% */
|
||||
public static final float baseInvasionChance = 1f / 25f;
|
||||
public static final float baseInvasionChance = 1f / 30f;
|
||||
/** how many turns have to pass before invasions start */
|
||||
public static final int invasionGracePeriod = 20;
|
||||
/** min armor fraction damage; e.g. 0.05 = at least 5% damage */
|
||||
@@ -285,10 +285,10 @@ public class Vars implements Loadable{
|
||||
if(loadedLogger) return;
|
||||
|
||||
String[] tags = {"[green][D][]", "[royal][I][]", "[yellow][W][]", "[scarlet][E][]", ""};
|
||||
String[] stags = {"&lc&fb[D]", "&lg&fb[I]", "&ly&fb[W]", "&lr&fb[E]", ""};
|
||||
String[] stags = {"&lc&fb[D]", "&lb&fb[I]", "&ly&fb[W]", "&lr&fb[E]", ""};
|
||||
|
||||
Seq<String> logBuffer = new Seq<>();
|
||||
Log.setLogger((level, text) -> {
|
||||
Log.logger = (level, text) -> {
|
||||
String result = text;
|
||||
String rawText = Log.format(stags[level.ordinal()] + "&fr " + text);
|
||||
System.out.println(rawText);
|
||||
@@ -304,9 +304,9 @@ public class Vars implements Loadable{
|
||||
}
|
||||
}
|
||||
|
||||
ui.scriptfrag.addMessage(Log.removeCodes(result));
|
||||
ui.scriptfrag.addMessage(Log.removeColors(result));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Events.on(ClientLoadEvent.class, e -> logBuffer.each(ui.scriptfrag::addMessage));
|
||||
|
||||
@@ -319,18 +319,19 @@ public class Vars implements Loadable{
|
||||
settings.setAppName(appName);
|
||||
|
||||
Writer writer = settings.getDataDirectory().child("last_log.txt").writer(false);
|
||||
LogHandler log = Log.getLogger();
|
||||
Log.setLogger((level, text) -> {
|
||||
LogHandler log = Log.logger;
|
||||
//ignore it
|
||||
Log.logger = (level, text) -> {
|
||||
log.log(level, text);
|
||||
|
||||
try{
|
||||
writer.write("[" + Character.toUpperCase(level.name().charAt(0)) +"] " + Log.removeCodes(text) + "\n");
|
||||
writer.write("[" + Character.toUpperCase(level.name().charAt(0)) +"] " + Log.removeColors(text) + "\n");
|
||||
writer.flush();
|
||||
}catch(IOException e){
|
||||
e.printStackTrace();
|
||||
//ignore it
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
loadedFileLogger = true;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public class BaseAI{
|
||||
private static final Vec2 axis = new Vec2(), rotator = new Vec2();
|
||||
private static final float correctPercent = 0.5f;
|
||||
private static final float step = 5;
|
||||
private static final int attempts = 5;
|
||||
private static final int attempts = 4;
|
||||
private static final float emptyChance = 0.01f;
|
||||
private static final int timerStep = 0, timerSpawn = 1;
|
||||
|
||||
@@ -72,6 +72,11 @@ public class BaseAI{
|
||||
int wx = (int)(World.toTile(pos.getX()) + Tmp.v1.x), wy = (int)(World.toTile(pos.getY()) + Tmp.v1.y);
|
||||
Tile tile = world.tiles.getc(wx, wy);
|
||||
|
||||
//try not to block the spawn point
|
||||
if(spawner.getSpawns().contains(t -> t.within(tile, tilesize * 40f))){
|
||||
continue;
|
||||
}
|
||||
|
||||
Seq<BasePart> parts = null;
|
||||
|
||||
//pick a completely random base part, and place it a random location
|
||||
|
||||
@@ -103,7 +103,7 @@ public class Pathfinder implements Runnable{
|
||||
boolean nearLiquid = false, nearSolid = false, nearGround = false;
|
||||
|
||||
for(int i = 0; i < 4; i++){
|
||||
Tile other = tile.getNearby(i);
|
||||
Tile other = tile.nearby(i);
|
||||
if(other != null){
|
||||
if(other.floor().isLiquid) nearLiquid = true;
|
||||
if(other.solid()) nearSolid = true;
|
||||
|
||||
@@ -80,7 +80,7 @@ public class WaveSpawner{
|
||||
|
||||
Unit unit = group.createUnit(state.rules.waveTeam, state.wave - 1);
|
||||
unit.set(spawnX + Tmp.v1.x, spawnY + Tmp.v1.y);
|
||||
Time.run(Math.min(i * 5, 60 * 2), () -> spawnEffect(unit));
|
||||
spawnEffect(unit);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -34,17 +34,15 @@ public class FlyingAI extends AIController{
|
||||
Teamc result = target(x, y, range, air, ground);
|
||||
if(result != null) return result;
|
||||
|
||||
if(ground) result = targetFlag(x, y, BlockFlag.producer, true);
|
||||
if(ground) result = targetFlag(x, y, BlockFlag.generator, true);
|
||||
if(result != null) return result;
|
||||
|
||||
if(ground) result = targetFlag(x, y, BlockFlag.turret, true);
|
||||
if(ground) result = targetFlag(x, y, BlockFlag.core, true);
|
||||
if(result != null) return result;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
//TODO clean up
|
||||
|
||||
protected void attack(float circleLength){
|
||||
vec.set(target).sub(unit);
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ public class FormationAI extends AIController implements FormationMember{
|
||||
|
||||
@Override
|
||||
public float formationSize(){
|
||||
return unit.hitSize * 1f;
|
||||
return unit.hitSize * 1.1f;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -13,8 +13,6 @@ import java.util.*;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class GroundAI extends AIController{
|
||||
//static final float commandCooldown = 60f * 10;
|
||||
//float commandTimer = 60*3;
|
||||
|
||||
@Override
|
||||
public void updateMovement(){
|
||||
@@ -57,19 +55,5 @@ public class GroundAI extends AIController{
|
||||
unit.lookAt(unit.vel().angle());
|
||||
}
|
||||
|
||||
//auto-command works but it's very buggy
|
||||
/*
|
||||
if(unit instanceof Commanderc){
|
||||
Commanderc c = (Commanderc)unit;
|
||||
//try to command when missing members
|
||||
if(c.controlling().size <= unit.type().commandLimit/2){
|
||||
commandTimer -= Time.delta;
|
||||
|
||||
if(commandTimer <= 0){
|
||||
c.commandNearby(new SquareFormation(), u -> !(u.controller() instanceof FormationAI) && !(u instanceof Commanderc));
|
||||
commandTimer = commandCooldown;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ import mindustry.world.blocks.*;
|
||||
import mindustry.world.blocks.campaign.*;
|
||||
import mindustry.world.blocks.defense.*;
|
||||
import mindustry.world.blocks.defense.turrets.*;
|
||||
import mindustry.world.blocks.defense.turrets.PointDefenseTurret;
|
||||
import mindustry.world.blocks.defense.turrets.TractorBeamTurret;
|
||||
import mindustry.world.blocks.distribution.*;
|
||||
import mindustry.world.blocks.environment.*;
|
||||
import mindustry.world.blocks.experimental.*;
|
||||
@@ -1186,7 +1188,7 @@ public class Blocks implements ContentList{
|
||||
requirements(Category.power, with(Items.lead, 100, Items.silicon, 75, Items.phasefabric, 25, Items.plastanium, 75, Items.thorium, 50));
|
||||
size = 2;
|
||||
powerProduction = 4.5f;
|
||||
itemDuration = 60 * 15f;
|
||||
itemDuration = 60 * 18f;
|
||||
}};
|
||||
|
||||
solarPanel = new SolarGenerator("solar-panel"){{
|
||||
@@ -1355,7 +1357,7 @@ public class Blocks implements ContentList{
|
||||
size = 5;
|
||||
|
||||
unitCapModifier = 20;
|
||||
researchCostMultiplier = 0.06f;
|
||||
researchCostMultiplier = 0.05f;
|
||||
}};
|
||||
|
||||
vault = new StorageBlock("vault"){{
|
||||
@@ -1644,11 +1646,20 @@ public class Blocks implements ContentList{
|
||||
|
||||
float brange = range + 10f;
|
||||
|
||||
ammo(Items.thorium, new ShrapnelBulletType(){{
|
||||
ammo(
|
||||
Items.thorium, new ShrapnelBulletType(){{
|
||||
length = brange;
|
||||
damage = 105f;
|
||||
ammoMultiplier = 6f;
|
||||
}});
|
||||
ammoMultiplier = 5f;
|
||||
}},
|
||||
Items.titanium, new ShrapnelBulletType(){{
|
||||
length = brange;
|
||||
damage = 66f;
|
||||
ammoMultiplier = 4f;
|
||||
width = 17f;
|
||||
reloadMultiplier = 1.3f;
|
||||
}}
|
||||
);
|
||||
}};
|
||||
|
||||
ripple = new ItemTurret("ripple"){{
|
||||
@@ -1914,7 +1925,7 @@ public class Blocks implements ContentList{
|
||||
new UnitType[]{UnitTypes.antumbra, UnitTypes.eclipse},
|
||||
new UnitType[]{UnitTypes.arkyid, UnitTypes.toxopid},
|
||||
new UnitType[]{UnitTypes.scepter, UnitTypes.reign},
|
||||
new UnitType[] {UnitTypes.sei, UnitTypes.omura},
|
||||
new UnitType[]{UnitTypes.sei, UnitTypes.omura},
|
||||
new UnitType[]{UnitTypes.quad, UnitTypes.oct},
|
||||
new UnitType[]{UnitTypes.vela, UnitTypes.corvus}
|
||||
);
|
||||
|
||||
@@ -1293,6 +1293,14 @@ public class Fx{
|
||||
});
|
||||
}),
|
||||
|
||||
coreBurn = new Effect(23, e -> {
|
||||
randLenVectors(e.id, 5, e.fin() * 9f, (x, y) -> {
|
||||
float len = e.fout() * 4f;
|
||||
color(Pal.accent, Color.gray, e.fin());
|
||||
Fill.circle(e.x + x, e.y + y, len/2f);
|
||||
});
|
||||
}),
|
||||
|
||||
plasticburn = new Effect(40, e -> {
|
||||
randLenVectors(e.id, 5, 3f + e.fin() * 5f, (x, y) -> {
|
||||
color(Color.valueOf("e9ead3"), Color.gray, e.fin());
|
||||
|
||||
@@ -10,6 +10,7 @@ import mindustry.entities.bullet.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@@ -897,6 +898,7 @@ public class UnitTypes implements ContentList{
|
||||
range = 140f;
|
||||
faceTarget = false;
|
||||
armor = 4f;
|
||||
targetFlag = BlockFlag.factory;
|
||||
|
||||
weapons.add(new Weapon(){{
|
||||
minShootVelocity = 0.75f;
|
||||
@@ -977,6 +979,7 @@ public class UnitTypes implements ContentList{
|
||||
engineOffset = 21;
|
||||
engineSize = 5.3f;
|
||||
hitSize = 56f;
|
||||
targetFlag = BlockFlag.battery;
|
||||
|
||||
BulletType missiles = new MissileBulletType(2.7f, 10){{
|
||||
width = 8f;
|
||||
@@ -1051,6 +1054,7 @@ public class UnitTypes implements ContentList{
|
||||
hitSize = 58f;
|
||||
destructibleWreck = false;
|
||||
armor = 13f;
|
||||
targetFlag = BlockFlag.reactor;
|
||||
|
||||
BulletType fragBullet = new FlakBulletType(4f, 5){{
|
||||
shootEffect = Fx.shootBig;
|
||||
@@ -1196,7 +1200,6 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
mineTier = 3;
|
||||
health = 500;
|
||||
armor = 2f;
|
||||
armor = 5f;
|
||||
speed = 1.8f;
|
||||
accel = 0.06f;
|
||||
@@ -1246,6 +1249,7 @@ public class UnitTypes implements ContentList{
|
||||
buildSpeed = 2.5f;
|
||||
range = 140f;
|
||||
targetAir = false;
|
||||
targetFlag = BlockFlag.battery;
|
||||
|
||||
ammoType = AmmoTypes.powerHigh;
|
||||
|
||||
@@ -1650,11 +1654,11 @@ public class UnitTypes implements ContentList{
|
||||
mineTier = 1;
|
||||
buildSpeed = 0.5f;
|
||||
drag = 0.05f;
|
||||
speed = 2.8f;
|
||||
speed = 3f;
|
||||
rotateSpeed = 15f;
|
||||
accel = 0.1f;
|
||||
itemCapacity = 30;
|
||||
health = 120f;
|
||||
health = 150f;
|
||||
engineOffset = 6f;
|
||||
hitSize = 8f;
|
||||
commandLimit = 3;
|
||||
@@ -1665,13 +1669,13 @@ public class UnitTypes implements ContentList{
|
||||
y = 1f;
|
||||
top = false;
|
||||
|
||||
bullet = new BasicBulletType(2.5f, 9){{
|
||||
bullet = new BasicBulletType(2.5f, 10){{
|
||||
width = 7f;
|
||||
height = 9f;
|
||||
lifetime = 60f;
|
||||
shootEffect = Fx.shootSmall;
|
||||
smokeEffect = Fx.shootSmallSmoke;
|
||||
tileDamageMultiplier = 0.09f;
|
||||
tileDamageMultiplier = 0.03f;
|
||||
}};
|
||||
}});
|
||||
}};
|
||||
@@ -1685,11 +1689,11 @@ public class UnitTypes implements ContentList{
|
||||
mineTier = 1;
|
||||
buildSpeed = 0.75f;
|
||||
drag = 0.05f;
|
||||
speed = 3f;
|
||||
speed = 3.3f;
|
||||
rotateSpeed = 17f;
|
||||
accel = 0.1f;
|
||||
itemCapacity = 50;
|
||||
health = 150f;
|
||||
health = 170f;
|
||||
engineOffset = 6f;
|
||||
hitSize = 9f;
|
||||
rotateShooting = false;
|
||||
@@ -1706,13 +1710,13 @@ public class UnitTypes implements ContentList{
|
||||
shotDelay = 4f;
|
||||
spacing = 0f;
|
||||
|
||||
bullet = new BasicBulletType(3f, 9){{
|
||||
bullet = new BasicBulletType(3f, 10){{
|
||||
width = 7f;
|
||||
height = 9f;
|
||||
lifetime = 60f;
|
||||
shootEffect = Fx.shootSmall;
|
||||
smokeEffect = Fx.shootSmallSmoke;
|
||||
tileDamageMultiplier = 0.1f;
|
||||
tileDamageMultiplier = 0.03f;
|
||||
}};
|
||||
}});
|
||||
}};
|
||||
@@ -1726,11 +1730,11 @@ public class UnitTypes implements ContentList{
|
||||
mineTier = 2;
|
||||
buildSpeed = 1f;
|
||||
drag = 0.05f;
|
||||
speed = 3.5f;
|
||||
speed = 3.55f;
|
||||
rotateSpeed = 19f;
|
||||
accel = 0.11f;
|
||||
itemCapacity = 70;
|
||||
health = 190f;
|
||||
health = 220f;
|
||||
engineOffset = 6f;
|
||||
hitSize = 10f;
|
||||
commandLimit = 7;
|
||||
@@ -1745,13 +1749,13 @@ public class UnitTypes implements ContentList{
|
||||
inaccuracy = 3f;
|
||||
shotDelay = 3f;
|
||||
|
||||
bullet = new BasicBulletType(3.5f, 9){{
|
||||
bullet = new BasicBulletType(3.5f, 10){{
|
||||
width = 6.5f;
|
||||
height = 11f;
|
||||
lifetime = 70f;
|
||||
shootEffect = Fx.shootSmall;
|
||||
smokeEffect = Fx.shootSmallSmoke;
|
||||
tileDamageMultiplier = 0.1f;
|
||||
tileDamageMultiplier = 0.03f;
|
||||
homingPower = 0.04f;
|
||||
}};
|
||||
}});
|
||||
|
||||
@@ -1,339 +1,89 @@
|
||||
package mindustry.content;
|
||||
|
||||
import arc.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.Texture.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.util.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.type.weather.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class Weathers implements ContentList{
|
||||
public static Weather
|
||||
rain,
|
||||
snow,
|
||||
sandstorm,
|
||||
sporestorm;
|
||||
sporestorm,
|
||||
fog;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
snow = new Weather("snow"){
|
||||
TextureRegion region;
|
||||
float yspeed = 2f, xspeed = 0.25f, padding = 16f, size = 12f, density = 1200f;
|
||||
snow = new ParticleWeather("snow"){{
|
||||
sizeMax = 13f;
|
||||
sizeMin = 2.6f;
|
||||
density = 1200f;
|
||||
attrs.set(Attribute.light, -0.15f);
|
||||
}};
|
||||
|
||||
{
|
||||
attrs.set(Attribute.light, -0.15f);
|
||||
}
|
||||
rain = new RainWeather("rain"){{
|
||||
attrs.set(Attribute.light, -0.2f);
|
||||
attrs.set(Attribute.water, 0.2f);
|
||||
status = StatusEffects.wet;
|
||||
}};
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
super.load();
|
||||
sandstorm = new ParticleWeather("sandstorm"){{
|
||||
color = noiseColor = Color.valueOf("f7cba4");
|
||||
drawNoise = true;
|
||||
useWindVector = true;
|
||||
sizeMax = 140f;
|
||||
sizeMin = 70f;
|
||||
minAlpha = 0f;
|
||||
maxAlpha = 0.2f;
|
||||
density = 1500f;
|
||||
baseSpeed = 6.1f;
|
||||
attrs.set(Attribute.light, -0.1f);
|
||||
attrs.set(Attribute.water, -0.1f);
|
||||
opacityMultiplier = 0.8f;
|
||||
force = 0.1f;
|
||||
}};
|
||||
|
||||
region = Core.atlas.find("circle-shadow");
|
||||
}
|
||||
sporestorm = new ParticleWeather("sporestorm"){{
|
||||
color = noiseColor = Color.valueOf("7457ce");
|
||||
particleRegion = "circle";
|
||||
drawNoise = true;
|
||||
statusGround = false;
|
||||
useWindVector = true;
|
||||
sizeMax = 5f;
|
||||
sizeMin = 2.5f;
|
||||
minAlpha = 0.1f;
|
||||
maxAlpha = 0.8f;
|
||||
density = 2000f;
|
||||
baseSpeed = 4.3f;
|
||||
attrs.set(Attribute.spores, 1f);
|
||||
attrs.set(Attribute.light, -0.15f);
|
||||
status = StatusEffects.sporeSlowed;
|
||||
opacityMultiplier = 0.85f;
|
||||
force = 0.1f;
|
||||
}};
|
||||
|
||||
@Override
|
||||
public void drawOver(WeatherState state){
|
||||
rand.setSeed(0);
|
||||
Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale());
|
||||
Tmp.r1.grow(padding);
|
||||
Core.camera.bounds(Tmp.r2);
|
||||
int total = (int)(Tmp.r1.area() / density * state.intensity());
|
||||
|
||||
for(int i = 0; i < total; i++){
|
||||
float scl = rand.random(0.5f, 1f);
|
||||
float scl2 = rand.random(0.5f, 1f);
|
||||
float sscl = rand.random(0.2f, 1f);
|
||||
float x = (rand.random(0f, world.unitWidth()) + Time.time() * xspeed * scl2);
|
||||
float y = (rand.random(0f, world.unitHeight()) - Time.time() * yspeed * scl);
|
||||
|
||||
x += Mathf.sin(y, rand.random(30f, 80f), rand.random(1f, 7f));
|
||||
|
||||
x -= Tmp.r1.x;
|
||||
y -= Tmp.r1.y;
|
||||
x = Mathf.mod(x, Tmp.r1.width);
|
||||
y = Mathf.mod(y, Tmp.r1.height);
|
||||
x += Tmp.r1.x;
|
||||
y += Tmp.r1.y;
|
||||
|
||||
if(Tmp.r3.setCentered(x, y, size * sscl).overlaps(Tmp.r2)){
|
||||
Draw.rect(region, x, y, size * sscl, size * sscl);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
rain = new Weather("rain"){
|
||||
float yspeed = 5f, xspeed = 1.5f, padding = 16f, size = 40f, density = 1200f;
|
||||
TextureRegion[] splashes = new TextureRegion[12];
|
||||
|
||||
{
|
||||
attrs.set(Attribute.light, -0.2f);
|
||||
attrs.set(Attribute.water, 0.2f);
|
||||
status = StatusEffects.wet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
super.load();
|
||||
|
||||
for(int i = 0; i < splashes.length; i++){
|
||||
splashes[i] = Core.atlas.find("splash-" + i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOver(WeatherState state){
|
||||
Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale());
|
||||
Tmp.r1.grow(padding);
|
||||
Core.camera.bounds(Tmp.r2);
|
||||
int total = (int)(Tmp.r1.area() / density * state.intensity());
|
||||
Lines.stroke(0.75f);
|
||||
float alpha = Draw.getColor().a;
|
||||
Draw.color(Color.royal, Color.white, 0.3f);
|
||||
|
||||
for(int i = 0; i < total; i++){
|
||||
float scl = rand.random(0.5f, 1f);
|
||||
float scl2 = rand.random(0.5f, 1f);
|
||||
float sscl = rand.random(0.2f, 1f);
|
||||
float x = (rand.random(0f, world.unitWidth()) + Time.time() * xspeed * scl2);
|
||||
float y = (rand.random(0f, world.unitHeight()) - Time.time() * yspeed * scl);
|
||||
float tint = rand.random(1f) * alpha;
|
||||
|
||||
x -= Tmp.r1.x;
|
||||
y -= Tmp.r1.y;
|
||||
x = Mathf.mod(x, Tmp.r1.width);
|
||||
y = Mathf.mod(y, Tmp.r1.height);
|
||||
x += Tmp.r1.x;
|
||||
y += Tmp.r1.y;
|
||||
|
||||
if(Tmp.r3.setCentered(x, y, size * sscl).overlaps(Tmp.r2)){
|
||||
Draw.alpha(tint);
|
||||
Lines.lineAngle(x, y, Angles.angle(xspeed * scl2, - yspeed * scl), size*sscl/2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawUnder(WeatherState state){
|
||||
Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale());
|
||||
Tmp.r1.grow(padding);
|
||||
Core.camera.bounds(Tmp.r2);
|
||||
int total = (int)(Tmp.r1.area() / density * state.intensity()) / 2;
|
||||
Lines.stroke(0.75f);
|
||||
|
||||
float t = Time.time() / 22f;
|
||||
|
||||
for(int i = 0; i < total; i++){
|
||||
float offset = rand.random(0f, 1f);
|
||||
float time = t + offset;
|
||||
|
||||
int pos = (int)((time));
|
||||
float life = time % 1f;
|
||||
float x = (rand.random(0f, world.unitWidth()) + pos*953);
|
||||
float y = (rand.random(0f, world.unitHeight()) - pos*453);
|
||||
|
||||
x -= Tmp.r1.x;
|
||||
y -= Tmp.r1.y;
|
||||
x = Mathf.mod(x, Tmp.r1.width);
|
||||
y = Mathf.mod(y, Tmp.r1.height);
|
||||
x += Tmp.r1.x;
|
||||
y += Tmp.r1.y;
|
||||
|
||||
if(Tmp.r3.setCentered(x, y, life * 4f).overlaps(Tmp.r2)){
|
||||
Tile tile = world.tileWorld(x, y);
|
||||
|
||||
if(tile != null && tile.floor().liquidDrop == Liquids.water){
|
||||
Draw.color(Tmp.c1.set(tile.floor().mapColor).mul(1.5f).a(state.opacity()));
|
||||
Draw.rect(splashes[(int)(life * (splashes.length - 1))], x, y);
|
||||
}else if(tile != null && tile.floor().liquidDrop == null && !tile.floor().solid){
|
||||
Draw.color(Color.royal, Color.white, 0.3f);
|
||||
Draw.alpha(Mathf.slope(life) * state.opacity());
|
||||
|
||||
float space = 45f;
|
||||
for(int j : new int[]{-1, 1}){
|
||||
Tmp.v1.trns(90f + j*space, 1f + 5f * life);
|
||||
Lines.lineAngle(x + Tmp.v1.x, y + Tmp.v1.y, 90f + j*space, 3f * (1f - life));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
sandstorm = new Weather("sandstorm"){
|
||||
TextureRegion region;
|
||||
float size = 140f, padding = size, invDensity = 1500f, baseSpeed = 6.1f;
|
||||
float force = 0.4f * 0;
|
||||
Color color = Color.valueOf("f7cba4");
|
||||
Texture noise;
|
||||
|
||||
{
|
||||
attrs.set(Attribute.light, -0.1f);
|
||||
opacityMultiplier = 0.8f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
region = Core.atlas.find("circle-shadow");
|
||||
noise = new Texture("sprites/noiseAlpha.png");
|
||||
noise.setWrap(TextureWrap.repeat);
|
||||
noise.setFilter(TextureFilter.linear);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
noise.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(WeatherState state){
|
||||
float speed = force * state.intensity;
|
||||
float windx = state.windVector.x * speed, windy = state.windVector.y * speed;
|
||||
|
||||
for(Unit unit : Groups.unit){
|
||||
unit.impulse(windx, windy);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOver(WeatherState state){
|
||||
Draw.tint(color);
|
||||
float speed = baseSpeed * state.intensity;
|
||||
float windx = state.windVector.x * speed, windy = state.windVector.y * speed;
|
||||
|
||||
float scale = 1f / 2000f;
|
||||
float scroll = Time.time() * scale;
|
||||
Tmp.tr1.texture = noise;
|
||||
Core.camera.bounds(Tmp.r1);
|
||||
Tmp.tr1.set(Tmp.r1.x*scale, Tmp.r1.y*scale, (Tmp.r1.x + Tmp.r1.width)*scale, (Tmp.r1.y + Tmp.r1.height)*scale);
|
||||
Tmp.tr1.scroll(-windx * scroll, windy * scroll);
|
||||
Draw.rect(Tmp.tr1, Core.camera.position.x, Core.camera.position.y, Core.camera.width, -Core.camera.height);
|
||||
|
||||
rand.setSeed(0);
|
||||
Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale());
|
||||
Tmp.r1.grow(padding);
|
||||
Core.camera.bounds(Tmp.r2);
|
||||
int total = (int)(Tmp.r1.area() / invDensity * state.intensity());
|
||||
Draw.tint(color);
|
||||
float baseAlpha = Draw.getColor().a;
|
||||
|
||||
for(int i = 0; i < total; i++){
|
||||
float scl = rand.random(0.5f, 1f);
|
||||
float scl2 = rand.random(0.5f, 1f);
|
||||
float sscl = rand.random(0.5f, 1f);
|
||||
float x = (rand.random(0f, world.unitWidth()) + Time.time() * windx * scl2);
|
||||
float y = (rand.random(0f, world.unitHeight()) + Time.time() * windy * scl);
|
||||
float alpha = rand.random(0.2f);
|
||||
|
||||
x += Mathf.sin(y, rand.random(30f, 80f), rand.random(1f, 7f));
|
||||
|
||||
x -= Tmp.r1.x;
|
||||
y -= Tmp.r1.y;
|
||||
x = Mathf.mod(x, Tmp.r1.width);
|
||||
y = Mathf.mod(y, Tmp.r1.height);
|
||||
x += Tmp.r1.x;
|
||||
y += Tmp.r1.y;
|
||||
|
||||
if(Tmp.r3.setCentered(x, y, size * sscl).overlaps(Tmp.r2)){
|
||||
Draw.alpha(alpha * baseAlpha);
|
||||
Draw.rect(region, x, y, size * sscl, size * sscl);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
sporestorm = new Weather("sporestorm"){
|
||||
TextureRegion region;
|
||||
float size = 5f, padding = size, invDensity = 2000f, baseSpeed = 4.3f, force = 0.28f * 0;
|
||||
Color color = Color.valueOf("7457ce");
|
||||
Texture noise;
|
||||
|
||||
{
|
||||
attrs.set(Attribute.spores, 1f);
|
||||
attrs.set(Attribute.light, -0.15f);
|
||||
status = StatusEffects.sporeSlowed;
|
||||
statusGround = false;
|
||||
opacityMultiplier = 0.85f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
region = Core.atlas.find("circle-shadow");
|
||||
noise = new Texture("sprites/noiseAlpha.png");
|
||||
noise.setWrap(TextureWrap.repeat);
|
||||
noise.setFilter(TextureFilter.linear);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(WeatherState state){
|
||||
float speed = force * state.intensity;
|
||||
float windx = state.windVector.x * speed, windy = state.windVector.y * speed;
|
||||
|
||||
for(Unit unit : Groups.unit){
|
||||
unit.impulse(windx, windy);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
noise.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOver(WeatherState state){
|
||||
Draw.alpha(state.opacity * 0.8f);
|
||||
Draw.tint(color);
|
||||
|
||||
float speed = baseSpeed * state.intensity;
|
||||
float windx = state.windVector.x * speed, windy = state.windVector.y * speed;
|
||||
|
||||
float scale = 1f / 2000f;
|
||||
float scroll = Time.time() * scale;
|
||||
Tmp.tr1.texture = noise;
|
||||
Core.camera.bounds(Tmp.r1);
|
||||
Tmp.tr1.set(Tmp.r1.x*scale, Tmp.r1.y*scale, (Tmp.r1.x + Tmp.r1.width)*scale, (Tmp.r1.y + Tmp.r1.height)*scale);
|
||||
Tmp.tr1.scroll(-windx * scroll, windy * scroll);
|
||||
Draw.rect(Tmp.tr1, Core.camera.position.x, Core.camera.position.y, Core.camera.width, -Core.camera.height);
|
||||
|
||||
rand.setSeed(0);
|
||||
Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale());
|
||||
Tmp.r1.grow(padding);
|
||||
Core.camera.bounds(Tmp.r2);
|
||||
int total = (int)(Tmp.r1.area() / invDensity * state.intensity());
|
||||
Draw.tint(color);
|
||||
float baseAlpha = state.opacity;
|
||||
Draw.alpha(baseAlpha);
|
||||
|
||||
for(int i = 0; i < total; i++){
|
||||
float scl = rand.random(0.5f, 1f);
|
||||
float scl2 = rand.random(0.5f, 1f);
|
||||
float sscl = rand.random(0.5f, 1f);
|
||||
float x = (rand.random(0f, world.unitWidth()) + Time.time() * windx * scl2);
|
||||
float y = (rand.random(0f, world.unitHeight()) + Time.time() * windy * scl);
|
||||
float alpha = rand.random(0.1f, 0.8f);
|
||||
|
||||
x += Mathf.sin(y, rand.random(30f, 80f), rand.random(1f, 7f));
|
||||
|
||||
x -= Tmp.r1.x;
|
||||
y -= Tmp.r1.y;
|
||||
x = Mathf.mod(x, Tmp.r1.width);
|
||||
y = Mathf.mod(y, Tmp.r1.height);
|
||||
x += Tmp.r1.x;
|
||||
y += Tmp.r1.y;
|
||||
|
||||
if(Tmp.r3.setCentered(x, y, size * sscl).overlaps(Tmp.r2)){
|
||||
Draw.alpha(alpha * baseAlpha);
|
||||
Fill.circle(x, y, size * sscl / 2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
fog = new ParticleWeather("fog"){{
|
||||
duration = 15f * Time.toMinutes;
|
||||
noiseLayers = 3;
|
||||
noiseLayerSclM = 0.8f;
|
||||
noiseLayerAlphaM = 0.7f;
|
||||
noiseLayerSpeedM = 2f;
|
||||
noiseLayerSclM = 0.6f;
|
||||
baseSpeed = 0.05f;
|
||||
color = noiseColor = Color.grays(0.4f);
|
||||
noiseScale = 1100f;
|
||||
noisePath = "fog";
|
||||
drawParticles = false;
|
||||
drawNoise = true;
|
||||
useWindVector = false;
|
||||
xspeed = 1f;
|
||||
yspeed = 0.01f;
|
||||
attrs.set(Attribute.light, -0.3f);
|
||||
attrs.set(Attribute.water, 0.05f);
|
||||
opacityMultiplier = 0.47f;
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import arc.math.*;
|
||||
import arc.scene.ui.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.audio.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.core.GameState.*;
|
||||
@@ -25,7 +24,6 @@ import mindustry.maps.Map;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.dialogs.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.storage.CoreBlock.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.text.*;
|
||||
@@ -250,19 +248,6 @@ public class Control implements ApplicationListener, Loadable{
|
||||
});
|
||||
}
|
||||
|
||||
//TODO move
|
||||
public void handleLaunch(CoreBuild tile){
|
||||
LaunchCorec ent = LaunchCore.create();
|
||||
ent.set(tile);
|
||||
ent.block(Blocks.coreShard);
|
||||
ent.lifetime(Vars.launchDuration);
|
||||
ent.add();
|
||||
|
||||
//remove schematic requirements from core
|
||||
tile.items.remove(universe.getLastLoadout().requirements());
|
||||
tile.items.remove(universe.getLaunchResources());
|
||||
}
|
||||
|
||||
public void playSector(Sector sector){
|
||||
playSector(sector, sector);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ public class GameState{
|
||||
/** The current game rules. */
|
||||
public Rules rules = new Rules();
|
||||
/** Statistics for this save/game. Displayed after game over. */
|
||||
public Stats stats = new Stats();
|
||||
public GameStats stats = new GameStats();
|
||||
/** Global attributes of the environment, calculated by weather. */
|
||||
public Attributes envAttrs = new Attributes();
|
||||
/** Sector information. Only valid in the campaign. */
|
||||
|
||||
@@ -194,14 +194,14 @@ public class NetClient implements ApplicationListener{
|
||||
}
|
||||
|
||||
//server console logging
|
||||
Log.info("&y@: &lb@", player.name, message);
|
||||
Log.info("&fi@: @", "&lc" + player.name, "&lw" + message);
|
||||
|
||||
//invoke event for all clients but also locally
|
||||
//this is required so other clients get the correct name even if they don't know who's sending it yet
|
||||
Call.sendMessage(message, colorizeName(player.id(), player.name), player);
|
||||
}else{
|
||||
//log command to console but with brackets
|
||||
Log.info("<&y@: &lm@&lg>", player.name, message);
|
||||
Log.info("<&fi@: @&fr>", "&lk" + player.name, "&lw" + message);
|
||||
|
||||
//a command was sent, now get the output
|
||||
if(response.type != ResponseType.valid){
|
||||
|
||||
@@ -18,6 +18,7 @@ import mindustry.game.EventType.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.game.Teams.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.net.*;
|
||||
import mindustry.net.Administration.*;
|
||||
import mindustry.net.Packets.*;
|
||||
@@ -299,6 +300,15 @@ public class NetServer implements ApplicationListener{
|
||||
}
|
||||
});
|
||||
|
||||
clientCommands.<Player>register("a", "<message...>", "Send a message only to admins.", (args, player) -> {
|
||||
if(!player.admin){
|
||||
player.sendMessage("[scarlet]You must be admin to use this command.");
|
||||
return;
|
||||
}
|
||||
|
||||
Groups.player.each(Player::admin, a -> a.sendMessage(args[0], player, "[#" + Pal.adminChat.toString() + "]<A>" + NetClient.colorizeName(player.id, player.name)));
|
||||
});
|
||||
|
||||
//duration of a a kick in seconds
|
||||
int kickDuration = 60 * 60;
|
||||
//voting round duration in seconds
|
||||
@@ -508,7 +518,8 @@ public class NetServer implements ApplicationListener{
|
||||
Call.playerDisconnect(player.id());
|
||||
}
|
||||
|
||||
if(Config.showConnectMessages.bool()) Log.info("&lm[@] &lc@ has disconnected. &lg&fi(@)", player.uuid(), player.name, reason);
|
||||
String message = Strings.format("&lb@&fi&lk has disconnected. &fi&lk[&lb@&fi&lk] (@)", player.name, player.uuid(), reason);
|
||||
if(Config.showConnectMessages.bool()) Log.info(message);
|
||||
}
|
||||
|
||||
player.remove();
|
||||
@@ -736,7 +747,8 @@ public class NetServer implements ApplicationListener{
|
||||
|
||||
if(Config.showConnectMessages.bool()){
|
||||
Call.sendMessage("[accent]" + player.name + "[accent] has connected.");
|
||||
Log.info("&lm[@] &y@ has connected.", player.uuid(), player.name);
|
||||
String message = Strings.format("&lb@&fi&lk has connected. &fi&lk[&lb@&fi&lk]", player.name, player.uuid());
|
||||
Log.info(message);
|
||||
}
|
||||
|
||||
if(!Config.motd.string().equalsIgnoreCase("off")){
|
||||
@@ -785,7 +797,7 @@ public class NetServer implements ApplicationListener{
|
||||
public void openServer(){
|
||||
try{
|
||||
net.host(Config.port.num());
|
||||
info("&lcOpened a server on port @.", Config.port.num());
|
||||
info("Opened a server on port @.", Config.port.num());
|
||||
}catch(BindException e){
|
||||
Log.err("Unable to host: Port already in use! Make sure no other servers are running on the same port in your network.");
|
||||
state.set(State.menu);
|
||||
|
||||
@@ -310,7 +310,7 @@ public class World{
|
||||
|
||||
//TODO bad code
|
||||
boolean hasSnow = floors[0].name.contains("ice") || floors[0].name.contains("snow");
|
||||
boolean hasRain = !hasSnow && floors[0].name.contains("water");
|
||||
boolean hasRain = !hasSnow && content.contains(Liquids.water) && !floors[0].name.contains("sand");
|
||||
boolean hasDesert = !hasSnow && !hasRain && floors[0].name.contains("sand");
|
||||
boolean hasSpores = floors[0].name.contains("spore") || floors[0].name.contains("moss") || floors[0].name.contains("tainted");
|
||||
|
||||
@@ -320,6 +320,7 @@ public class World{
|
||||
|
||||
if(hasRain){
|
||||
state.rules.weather.add(new WeatherEntry(Weathers.rain));
|
||||
state.rules.weather.add(new WeatherEntry(Weathers.fog));
|
||||
}
|
||||
|
||||
if(hasDesert){
|
||||
|
||||
@@ -10,11 +10,14 @@ import mindustry.game.EventType.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
/** Base interface for an unlockable content type. */
|
||||
public abstract class UnlockableContent extends MappableContent{
|
||||
/** Stat storage for this content. Initialized on demand. */
|
||||
public Stats stats = new Stats();
|
||||
/** Localized, formal name. Never null. Set to internal name if not found in bundle. */
|
||||
public String localizedName;
|
||||
/** Localized description. May be null. */
|
||||
@@ -38,6 +41,18 @@ public abstract class UnlockableContent extends MappableContent{
|
||||
return minfo.mod == null ? description : description + "\n" + Core.bundle.format("mod.display", minfo.mod.meta.displayName());
|
||||
}
|
||||
|
||||
/** Checks stat initialization state. Call before displaying stats. */
|
||||
public void checkStats(){
|
||||
if(!stats.intialized){
|
||||
setStats();
|
||||
stats.intialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Intializes stats on demand. Should only be called once. Only called before something is displayed. */
|
||||
public void setStats(){
|
||||
}
|
||||
|
||||
/** Generate any special icons for this content. Called asynchronously.*/
|
||||
@CallSuper
|
||||
public void createIcons(MultiPacker packer){
|
||||
@@ -73,7 +88,9 @@ public abstract class UnlockableContent extends MappableContent{
|
||||
}
|
||||
|
||||
/** This should show all necessary info about this content in the specified table. */
|
||||
public abstract void displayInfo(Table table);
|
||||
public void display(Table table){
|
||||
|
||||
}
|
||||
|
||||
/** Called when this content is unlocked. Use this to unlock other related content. */
|
||||
public void onUnlock(){
|
||||
@@ -95,6 +112,14 @@ public abstract class UnlockableContent extends MappableContent{
|
||||
}
|
||||
}
|
||||
|
||||
/** Unlocks this content, but does not fire any events. */
|
||||
public void quiteUnlock(){
|
||||
if(!unlocked()){
|
||||
unlocked = true;
|
||||
Core.settings.put(name + "-unlocked", true);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean unlocked(){
|
||||
if(net.client()) return state.rules.researched.contains(name);
|
||||
return unlocked || alwaysUnlocked;
|
||||
|
||||
@@ -105,9 +105,9 @@ public class EditorTile extends Tile{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void changeEntity(Team team, Prov<Building> entityprov, int rotation){
|
||||
protected void changeBuild(Team team, Prov<Building> entityprov, int rotation){
|
||||
if(skip()){
|
||||
super.changeEntity(team, entityprov, rotation);
|
||||
super.changeBuild(team, entityprov, rotation);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ public class MapGenerateDialog extends BaseDialog{
|
||||
CachedTile ctile = new CachedTile(){
|
||||
//nothing.
|
||||
@Override
|
||||
protected void changeEntity(Team team, Prov<Building> entityprov, int rotation){
|
||||
protected void changeBuild(Team team, Prov<Building> entityprov, int rotation){
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -464,7 +464,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
*/
|
||||
public boolean movePayload(Payload todump){
|
||||
int trns = block.size/2 + 1;
|
||||
Tile next = tile.getNearby(Geometry.d4(rotation).x * trns, Geometry.d4(rotation).y * trns);
|
||||
Tile next = tile.nearby(Geometry.d4(rotation).x * trns, Geometry.d4(rotation).y * trns);
|
||||
|
||||
if(next != null && next.build != null && next.build.team == team && next.build.acceptPayload(self(), todump)){
|
||||
next.build.handlePayload(self(), todump);
|
||||
@@ -547,7 +547,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
}
|
||||
|
||||
public float moveLiquidForward(boolean leaks, Liquid liquid){
|
||||
Tile next = tile.getNearby(rotation);
|
||||
Tile next = tile.nearby(rotation);
|
||||
|
||||
if(next == null) return 0;
|
||||
|
||||
@@ -911,7 +911,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
/** Called when arbitrary configuration is applied to a tile. */
|
||||
public void configured(@Nullable Unit builder, @Nullable Object value){
|
||||
//null is of type void.class; anonymous classes use their superclass.
|
||||
Class<?> type = value == null ? void.class : value.getClass().isAnonymousClass() ? value.getClass().getSuperclass() : value.getClass();
|
||||
Class<?> type = value == null ? void.class : value.getClass().isAnonymousClass() || value.getClass().getSimpleName().startsWith("adapter") ? value.getClass().getSuperclass() : value.getClass();
|
||||
|
||||
if(builder != null && builder.isPlayer()){
|
||||
lastAccessed = builder.getPlayer().name;
|
||||
|
||||
@@ -74,7 +74,7 @@ abstract class CommanderComp implements Entityc, Posc{
|
||||
void command(Formation formation, Seq<Unit> units){
|
||||
clearCommand();
|
||||
|
||||
float spacing = hitSize * 0.65f;
|
||||
float spacing = hitSize * 0.8f;
|
||||
minFormationSpeed = type.speed;
|
||||
|
||||
controlling.addAll(units);
|
||||
|
||||
@@ -98,7 +98,7 @@ abstract class PuddleComp implements Posc, Puddlec, Drawc{
|
||||
boolean onLiquid = tile.floor().isLiquid;
|
||||
float f = Mathf.clamp(amount / (maxLiquid / 1.5f));
|
||||
float smag = onLiquid ? 0.8f : 0f;
|
||||
float sscl = 20f;
|
||||
float sscl = 25f;
|
||||
|
||||
Draw.color(tmp.set(liquid.color).shiftValue(-0.05f));
|
||||
Fill.circle(x + Mathf.sin(Time.time() + seeds * 532, sscl, smag), y + Mathf.sin(Time.time() + seeds * 53, sscl, smag), f * 8f);
|
||||
|
||||
@@ -89,7 +89,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
case rotation -> rotation;
|
||||
case health -> health;
|
||||
case maxHealth -> maxHealth;
|
||||
case ammo -> state.rules.unitAmmo ? type.ammoCapacity : ammo;
|
||||
case ammo -> !state.rules.unitAmmo ? type.ammoCapacity : ammo;
|
||||
case ammoCapacity -> type.ammoCapacity;
|
||||
case x -> World.conv(x);
|
||||
case y -> World.conv(y);
|
||||
|
||||
@@ -229,8 +229,8 @@ public class EventType{
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when block building begins by placing down the BuildBlock.
|
||||
* The tile's block will nearly always be a BuildBlock.
|
||||
* Called when block building begins by placing down the ConstructBlock.
|
||||
* The tile's block will nearly always be a ConstructBlock.
|
||||
*/
|
||||
public static class BlockBuildBeginEvent{
|
||||
public final Tile tile;
|
||||
@@ -262,7 +262,7 @@ public class EventType{
|
||||
|
||||
/**
|
||||
* Called when a player or drone begins building something.
|
||||
* This does not necessarily happen when a new BuildBlock is created.
|
||||
* This does not necessarily happen when a new ConstructBlock is created.
|
||||
*/
|
||||
public static class BuildSelectEvent{
|
||||
public final Tile tile;
|
||||
|
||||
@@ -6,7 +6,7 @@ import mindustry.type.*;
|
||||
|
||||
//TODO more stats:
|
||||
//- units constructed
|
||||
public class Stats{
|
||||
public class GameStats{
|
||||
/** Total items delivered to global resoure counter. Campaign only. */
|
||||
public ObjectIntMap<Item> itemsDelivered = new ObjectIntMap<>();
|
||||
/** Enemy (red team) units destroyed. */
|
||||
@@ -23,7 +23,6 @@ public enum Gamemode{
|
||||
rules.waveTimer = true;
|
||||
|
||||
rules.waveSpacing /= 2f;
|
||||
rules.teams.get(rules.waveTeam).ai = true;
|
||||
rules.teams.get(rules.waveTeam).infiniteResources = true;
|
||||
}, map -> map.teams.contains(state.rules.waveTeam.id)),
|
||||
pvp(rules -> {
|
||||
|
||||
@@ -28,7 +28,7 @@ public class SectorInfo{
|
||||
/** Items stored in all cores. */
|
||||
public ItemSeq items = new ItemSeq();
|
||||
/** The best available core type. */
|
||||
public Block bestCoreType = Blocks.air;
|
||||
public Block bestCoreType = Blocks.coreShard;
|
||||
/** Max storage capacity. */
|
||||
public int storageCapacity = 0;
|
||||
/** Whether a core is available here. */
|
||||
|
||||
@@ -6,6 +6,7 @@ import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.io.legacy.*;
|
||||
import mindustry.maps.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.blocks.storage.*;
|
||||
@@ -187,7 +188,7 @@ public class Universe{
|
||||
}
|
||||
|
||||
//add production, making sure that it's capped
|
||||
sector.info.production.each((item, stat) -> sector.info.items.add(item, Math.min((int)(stat.mean * seconds * scl), sector.info.storageCapacity - sector.info.items.get(item))));
|
||||
sector.info.production.each((item, stat) -> sector.info.items.add(item, Math.min((int)(stat.mean * newSecondsPassed * scl), sector.info.storageCapacity - sector.info.items.get(item))));
|
||||
|
||||
sector.saveInfo();
|
||||
}
|
||||
@@ -260,6 +261,11 @@ public class Universe{
|
||||
private void load(){
|
||||
seconds = Core.settings.getInt("utimei");
|
||||
turn = Core.settings.getInt("turn");
|
||||
|
||||
if(Core.settings.has("unlocks")){
|
||||
LegacyIO.readResearch();
|
||||
Core.settings.remove("unlocks");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -94,5 +94,7 @@ public class Pal{
|
||||
redDust = Color.valueOf("ffa480"),
|
||||
redderDust = Color.valueOf("ff7b69"),
|
||||
|
||||
plasticSmoke = Color.valueOf("f1e479");
|
||||
plasticSmoke = Color.valueOf("f1e479"),
|
||||
|
||||
adminChat = Color.valueOf("ff4000");
|
||||
}
|
||||
|
||||
@@ -353,9 +353,7 @@ public class DesktopInput extends InputHandler{
|
||||
ui.planet.show();
|
||||
}).visible(() -> state.isCampaign()).tooltip("@planetmap");
|
||||
|
||||
table.button(Icon.up, Styles.clearPartiali, () -> {
|
||||
ui.planet.showLaunch(state.getSector(), player.team().core());
|
||||
}).visible(() -> state.isCampaign()).tooltip("@launchcore").disabled(b -> player.team().core() == null);
|
||||
table.add();
|
||||
}
|
||||
|
||||
void pollInput(){
|
||||
@@ -661,7 +659,7 @@ public class DesktopInput extends InputHandler{
|
||||
}
|
||||
}
|
||||
|
||||
//update commander inut
|
||||
//update commander unit
|
||||
if(Core.input.keyTap(Binding.command)){
|
||||
Call.unitCommand(player);
|
||||
}
|
||||
|
||||
@@ -241,6 +241,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
pay.set(x, y);
|
||||
pay.dropLastPayload();
|
||||
pay.set(prevx, prevy);
|
||||
pay.controlling().each(u -> {
|
||||
if(u instanceof Payloadc){
|
||||
Call.payloadDropped(u, u.x, u.y);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -421,7 +426,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
if(controlledType != null){
|
||||
Unit unit = Units.closest(player.team(), player.x, player.y, u -> !u.isPlayer() && u.type == controlledType && !u.dead);
|
||||
if(unit == null && controlledType == UnitTypes.block){
|
||||
unit = world.buildWorld(player.x, player.y) instanceof ControlBlock ? ((ControlBlock)world.buildWorld(player.x, player.y)).unit() : null;
|
||||
unit = world.buildWorld(player.x, player.y) instanceof ControlBlock cont && cont.canControl() ? cont.unit() : null;
|
||||
}
|
||||
|
||||
if(unit != null){
|
||||
@@ -985,8 +990,8 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
}
|
||||
|
||||
Building tile = world.buildWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y);
|
||||
if(tile instanceof ControlBlock && tile.team == player.team()){
|
||||
return ((ControlBlock)tile).unit();
|
||||
if(tile instanceof ControlBlock cont && cont.canControl() && tile.team == player.team()){
|
||||
return cont.unit();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -24,6 +24,7 @@ import mindustry.graphics.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
import static mindustry.input.PlaceMode.*;
|
||||
@@ -936,7 +937,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
unit.aim(player.mouseX = Core.input.mouseWorldX(), player.mouseY = Core.input.mouseWorldY());
|
||||
}else if(target == null){
|
||||
player.shooting = false;
|
||||
if(Core.settings.getBool("autotarget")){
|
||||
if(Core.settings.getBool("autotarget") && !(player.unit() instanceof BlockUnitUnit u && u.tile() instanceof ControlBlock c && !c.shouldAutoTarget())){
|
||||
target = Units.closestTarget(unit.team, unit.x, unit.y, range, u -> u.team != Team.derelict, u -> u.team != Team.derelict);
|
||||
|
||||
if(allowHealing && target == null){
|
||||
|
||||
@@ -105,7 +105,7 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
|
||||
state.wave = map.getInt("wave");
|
||||
state.wavetime = map.getFloat("wavetime", state.rules.waveSpacing);
|
||||
state.stats = JsonIO.read(Stats.class, map.get("stats", "{}"));
|
||||
state.stats = JsonIO.read(GameStats.class, map.get("stats", "{}"));
|
||||
state.rules = JsonIO.read(Rules.class, map.get("rules", "{}"));
|
||||
if(state.rules.spawns.isEmpty()) state.rules.spawns = defaultWaves.get();
|
||||
lastReadBuild = map.getInt("build", -1);
|
||||
|
||||
@@ -185,7 +185,7 @@ public class TypeIO{
|
||||
return unit == null ? Nulls.unit : unit;
|
||||
}else if(type == 1){ //block
|
||||
Building tile = world.build(id);
|
||||
return tile instanceof ControlBlock ? ((ControlBlock)tile).unit() : Nulls.unit;
|
||||
return tile instanceof ControlBlock cont ? cont.unit() : Nulls.unit;
|
||||
}
|
||||
return Nulls.unit;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package mindustry.io.legacy;
|
||||
|
||||
import arc.*;
|
||||
import arc.struct.*;
|
||||
import mindustry.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.ui.dialogs.JoinDialog.*;
|
||||
|
||||
import java.io.*;
|
||||
@@ -48,4 +50,35 @@ public class LegacyIO{
|
||||
return arr;
|
||||
}
|
||||
|
||||
public static void readResearch(){
|
||||
try{
|
||||
byte[] bytes = Core.settings.getBytes("unlocks");
|
||||
DataInputStream stream = new DataInputStream(new ByteArrayInputStream(bytes));
|
||||
|
||||
int length = stream.readInt();
|
||||
if(length > 0){
|
||||
stream.readUTF(); //name of key type
|
||||
stream.readUTF(); //name of value type
|
||||
|
||||
//each element is an array list
|
||||
for(int i = 0; i < length; i++){
|
||||
ContentType type = ContentType.all[stream.readInt()];
|
||||
int arrLength = stream.readInt();
|
||||
if(arrLength > 0){
|
||||
stream.readUTF(); //type of contents (String)
|
||||
for(int j = 0; j < arrLength; j++){
|
||||
String name = stream.readUTF();
|
||||
Content out = Vars.content.getByName(type, name);
|
||||
if(out instanceof UnlockableContent u){
|
||||
u.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package mindustry.logic;
|
||||
|
||||
import mindustry.game.*;
|
||||
|
||||
/** An object that can be controlled with logic. */
|
||||
public interface Controllable{
|
||||
void control(LAccess type, double p1, double p2, double p3, double p4);
|
||||
void control(LAccess type, Object p1, double p2, double p3, double p4);
|
||||
Team team();
|
||||
}
|
||||
|
||||
@@ -189,17 +189,28 @@ public class LAssembler{
|
||||
return putConst("___" + symbol, symbol.substring(1, symbol.length() - 1).replace("\\n", "\n")).id;
|
||||
}
|
||||
|
||||
//remove spaces for non-strings
|
||||
symbol = symbol.replace(' ', '_');
|
||||
|
||||
try{
|
||||
double value = Double.parseDouble(symbol);
|
||||
double value = parseDouble(symbol);
|
||||
if(Double.isNaN(value) || Double.isInfinite(value)) value = 0;
|
||||
|
||||
//this creates a hidden const variable with the specified value
|
||||
String key = "___" + value;
|
||||
return putConst(key, value).id;
|
||||
return putConst("___" + value, value).id;
|
||||
}catch(NumberFormatException e){
|
||||
return putVar(symbol).id;
|
||||
}
|
||||
}
|
||||
|
||||
double parseDouble(String symbol) throws NumberFormatException{
|
||||
//parse hex/binary syntax
|
||||
if(symbol.startsWith("0b")) return Long.parseLong(symbol.substring(2), 2);
|
||||
if(symbol.startsWith("0x")) return Long.parseLong(symbol.substring(2), 16);
|
||||
|
||||
return Double.parseDouble(symbol);
|
||||
}
|
||||
|
||||
/** Adds a constant value by name. */
|
||||
public BVar putConst(String name, Object value){
|
||||
BVar var = putVar(name);
|
||||
|
||||
@@ -47,6 +47,7 @@ public class LExecutor{
|
||||
public LongSeq graphicsBuffer = new LongSeq();
|
||||
public StringBuilder textBuffer = new StringBuilder();
|
||||
public Building[] links = {};
|
||||
public IntSet linkIds = new IntSet();
|
||||
public Team team = Team.derelict;
|
||||
|
||||
public boolean initialized(){
|
||||
@@ -212,9 +213,9 @@ public class LExecutor{
|
||||
public LLocate locate = LLocate.building;
|
||||
public BlockFlag flag = BlockFlag.core;
|
||||
public int enemy, ore;
|
||||
public int outX, outY, outFound;
|
||||
public int outX, outY, outFound, outBuild;
|
||||
|
||||
public UnitLocateI(LLocate locate, BlockFlag flag, int enemy, int ore, int outX, int outY, int outFound){
|
||||
public UnitLocateI(LLocate locate, BlockFlag flag, int enemy, int ore, int outX, int outY, int outFound, int outBuild){
|
||||
this.locate = locate;
|
||||
this.flag = flag;
|
||||
this.enemy = enemy;
|
||||
@@ -271,6 +272,7 @@ public class LExecutor{
|
||||
cache.found = false;
|
||||
exec.setnum(outFound, 0);
|
||||
}
|
||||
exec.setobj(outFound, res != null && res.build != null && res.build.team == exec.team ? res.build : null);
|
||||
}else{
|
||||
exec.setbool(outFound, cache.found);
|
||||
exec.setnum(outX, cache.x);
|
||||
@@ -446,13 +448,13 @@ public class LExecutor{
|
||||
float range = Math.max(unit.range(), buildingRange);
|
||||
if(!unit.within(x1, y1, range)){
|
||||
exec.setobj(p3, null);
|
||||
exec.setnum(p4, 0);
|
||||
exec.setobj(p4, null);
|
||||
}else{
|
||||
Tile tile = world.tileWorld(x1, y1);
|
||||
//any environmental solid block is returned as StoneWall, aka "@solid"
|
||||
Block block = tile == null ? null : !tile.synthetic() ? (tile.solid() ? Blocks.stoneWall : Blocks.air) : tile.block();
|
||||
exec.setobj(p3, block);
|
||||
exec.setnum(p4, tile != null && tile.build != null ? tile.build.rotation : 0);
|
||||
exec.setobj(p4, tile != null && tile.build != null ? tile.build : null);
|
||||
}
|
||||
}
|
||||
case itemDrop -> {
|
||||
@@ -510,11 +512,11 @@ public class LExecutor{
|
||||
@Override
|
||||
public void run(LExecutor exec){
|
||||
Object obj = exec.obj(target);
|
||||
if(obj instanceof Controllable cont){
|
||||
if(obj instanceof Building b && b.team == exec.team && exec.linkIds.contains(b.id)){
|
||||
if(type.isObj){
|
||||
cont.control(type, exec.obj(p1), exec.num(p2), exec.num(p3), exec.num(p4));
|
||||
b.control(type, exec.obj(p1), exec.num(p2), exec.num(p3), exec.num(p4));
|
||||
}else{
|
||||
cont.control(type, exec.num(p1), exec.num(p2), exec.num(p3), exec.num(p4));
|
||||
b.control(type, exec.num(p1), exec.num(p2), exec.num(p3), exec.num(p4));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -607,6 +609,7 @@ public class LExecutor{
|
||||
Object target = exec.obj(from);
|
||||
Object sense = exec.obj(type);
|
||||
|
||||
//TODO should remote enemy buildings be senseable?
|
||||
if(target instanceof Senseable se){
|
||||
if(sense instanceof Content){
|
||||
exec.setnum(to, se.sense(((Content)sense)));
|
||||
|
||||
@@ -819,7 +819,7 @@ public class LStatements{
|
||||
public LLocate locate = LLocate.building;
|
||||
public BlockFlag flag = BlockFlag.core;
|
||||
public String enemy = "true", ore = "@copper";
|
||||
public String outX = "outx", outY = "outy", outFound = "found";
|
||||
public String outX = "outx", outY = "outy", outFound = "found", outBuild = "building";
|
||||
|
||||
@Override
|
||||
public void build(Table table){
|
||||
@@ -905,6 +905,8 @@ public class LStatements{
|
||||
table.add(" found ").left();
|
||||
fields(table, outFound, str -> outFound = str);
|
||||
|
||||
table.add(" building ").left();
|
||||
fields(table, outBuild, str -> outBuild = str);
|
||||
|
||||
}
|
||||
|
||||
@@ -915,7 +917,7 @@ public class LStatements{
|
||||
|
||||
@Override
|
||||
public LInstruction build(LAssembler builder){
|
||||
return new UnitLocateI(locate, flag, builder.var(enemy), builder.var(ore), builder.var(outX), builder.var(outY), builder.var(outFound));
|
||||
return new UnitLocateI(locate, flag, builder.var(enemy), builder.var(ore), builder.var(outX), builder.var(outY), builder.var(outFound), builder.var(outBuild));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ public enum LUnitControl{
|
||||
mine("x", "y"),
|
||||
flag("value"),
|
||||
build("x", "y", "block", "rotation"),
|
||||
getBlock("x", "y", "result", "resRot"),
|
||||
getBlock("x", "y", "type", "building"),
|
||||
within("x", "y", "radius", "result");
|
||||
|
||||
public final String[] params;
|
||||
|
||||
@@ -185,14 +185,18 @@ public class SectorDamage{
|
||||
}
|
||||
|
||||
//create sparse tile array for fast range query
|
||||
int sparseSkip = 6;
|
||||
int sparseSkip = 5, sparseSkip2 = 3;
|
||||
//TODO if this is slow, use a quadtree
|
||||
Seq<Tile> sparse = new Seq<>(path.size / sparseSkip + 1);
|
||||
Seq<Tile> sparse2 = new Seq<>(path.size / sparseSkip2 + 1);
|
||||
|
||||
for(int i = 0; i < path.size; i++){
|
||||
if(i % sparseSkip == 0){
|
||||
sparse.add(path.get(i));
|
||||
}
|
||||
if(i % sparseSkip2 == 0){
|
||||
sparse2.add(path.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
//regen is in health per second
|
||||
@@ -202,8 +206,11 @@ public class SectorDamage{
|
||||
|
||||
//first, calculate the total health of blocks in the path
|
||||
|
||||
for(Tile t : path){
|
||||
int radius = 2;
|
||||
//radius around the path that gets counted
|
||||
int radius = 7;
|
||||
IntSet counted = new IntSet();
|
||||
|
||||
for(Tile t : sparse2){
|
||||
|
||||
//radius is square.
|
||||
for(int dx = -radius; dx <= radius; dx++){
|
||||
@@ -212,7 +219,7 @@ public class SectorDamage{
|
||||
if(wx >= 0 && wy >= 0 && wx < world.width() && wy < world.height()){
|
||||
Tile tile = world.rawTile(wx, wy);
|
||||
|
||||
if(tile.build != null && tile.team() == state.rules.defaultTeam){
|
||||
if(tile.build != null && tile.team() == state.rules.defaultTeam && counted.add(tile.pos())){
|
||||
//health is divided by block size, because multiblocks are counted multiple times.
|
||||
sumHealth += tile.build.health / tile.block().size;
|
||||
totalPathBuild += 1f / tile.block().size;
|
||||
@@ -228,7 +235,7 @@ public class SectorDamage{
|
||||
for(Building build : Groups.build){
|
||||
float e = build.efficiency();
|
||||
if(e > 0.08f){
|
||||
if(build.team == state.rules.defaultTeam && build instanceof Ranged ranged && sparse.contains(t -> t.within(build, ranged.range()))){
|
||||
if(build.team == state.rules.defaultTeam && build instanceof Ranged ranged && sparse.contains(t -> t.within(build, ranged.range() + radius*tilesize))){
|
||||
if(build.block instanceof Turret t && build instanceof TurretBuild b && b.hasAmmo()){
|
||||
sumDps += t.shots / t.reloadTime * 60f * b.peekAmmo().estimateDPS() * e;
|
||||
}
|
||||
@@ -304,7 +311,7 @@ public class SectorDamage{
|
||||
//enemy units like to aim for a lot of non-essential things, so increase resulting health slightly
|
||||
info.sumHealth = sumHealth * 1.2f;
|
||||
//players tend to have longer range units/turrets, so assume DPS is higher
|
||||
info.sumDps = sumDps * 1.2f;
|
||||
info.sumDps = sumDps * 1.5f;
|
||||
info.sumRps = sumRps;
|
||||
|
||||
//finally, find an equation to put it all together and produce a 0-1 number
|
||||
|
||||
@@ -414,7 +414,7 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{
|
||||
|
||||
state.rules.attackMode = sector.info.attack = true;
|
||||
}else{
|
||||
state.rules.winWave = sector.info.winWave = 15 * (int)Math.max(difficulty * 10, 1);
|
||||
state.rules.winWave = sector.info.winWave = 10 + 5 * (int)Math.max(difficulty * 10, 1);
|
||||
}
|
||||
|
||||
state.rules.waves = sector.info.waves = true;
|
||||
|
||||
@@ -190,6 +190,7 @@ public class ContentParser{
|
||||
"mindustry.world.blocks.defense",
|
||||
"mindustry.world.blocks.defense.turrets",
|
||||
"mindustry.world.blocks.distribution",
|
||||
"mindustry.world.blocks.environment",
|
||||
"mindustry.world.blocks.liquid",
|
||||
"mindustry.world.blocks.logic",
|
||||
"mindustry.world.blocks.power",
|
||||
@@ -302,6 +303,20 @@ public class ContentParser{
|
||||
|
||||
return unit;
|
||||
},
|
||||
ContentType.weather, (TypeParser<Weather>)(mod, name, value) -> {
|
||||
Weather item;
|
||||
if(locate(ContentType.weather, name) != null){
|
||||
item = locate(ContentType.weather, name);
|
||||
readBundle(ContentType.weather, name, value);
|
||||
}else{
|
||||
readBundle(ContentType.weather, name, value);
|
||||
Class<? extends Weather> type = resolve(getType(value), "mindustry.type.weather");
|
||||
item = make(type);
|
||||
}
|
||||
currentContent = item;
|
||||
read(() -> readFields(item, value));
|
||||
return item;
|
||||
},
|
||||
ContentType.item, parser(ContentType.item, Item::new),
|
||||
ContentType.liquid, parser(ContentType.liquid, Liquid::new)
|
||||
//ContentType.sector, parser(ContentType.sector, SectorPreset::new)
|
||||
|
||||
@@ -59,12 +59,12 @@ public class Scripts implements Disposable{
|
||||
if(o instanceof Undefined) o = "undefined";
|
||||
return String.valueOf(o);
|
||||
}catch(Throwable t){
|
||||
return getError(t);
|
||||
return getError(t, false);
|
||||
}
|
||||
}
|
||||
|
||||
private String getError(Throwable t){
|
||||
t.printStackTrace();
|
||||
private String getError(Throwable t, boolean log){
|
||||
if(log) Log.err(t);
|
||||
return t.getClass().getSimpleName() + (t.getMessage() == null ? "" : ": " + t.getMessage());
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ public class Scripts implements Disposable{
|
||||
if(currentMod != null){
|
||||
file = currentMod.name + "/" + file;
|
||||
}
|
||||
log(LogLevel.err, file, "" + getError(t));
|
||||
log(LogLevel.err, file, "" + getError(t, true));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -577,7 +577,10 @@ public class Administration{
|
||||
autosave("Whether the periodically save the map when playing.", false),
|
||||
autosaveAmount("The maximum amount of autosaves. Older ones get replaced.", 10),
|
||||
autosaveSpacing("Spacing between autosaves in seconds.", 60 * 5),
|
||||
debug("Enable debug logging", false, () -> Log.setLogLevel(debug() ? LogLevel.debug : LogLevel.info));
|
||||
debug("Enable debug logging", false, () -> {
|
||||
LogLevel level = debug() ? LogLevel.debug : LogLevel.info;
|
||||
Log.level = level;
|
||||
});
|
||||
|
||||
public static final Config[] all = values();
|
||||
|
||||
|
||||
@@ -58,8 +58,6 @@ public class NetworkIO{
|
||||
state.rules = JsonIO.read(Rules.class, stream.readUTF());
|
||||
state.map = new Map(SaveIO.getSaveWriter().readStringMap(stream));
|
||||
|
||||
Log.info("READ RULES: @", state.rules.researched);
|
||||
|
||||
state.wave = stream.readInt();
|
||||
state.wavetime = stream.readFloat();
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public class AmmoTypes implements ContentList{
|
||||
@Override
|
||||
public void resupply(Unit unit){
|
||||
float range = unit.hitSize + 60f;
|
||||
Tile closest = Vars.indexer.findClosestFlag(unit.x, unit.y, unit.team, BlockFlag.powerRes);
|
||||
Tile closest = Vars.indexer.findClosestFlag(unit.x, unit.y, unit.team, BlockFlag.battery);
|
||||
|
||||
if(closest != null && closest.build != null && unit.within(closest.build, range) && closest.build.power != null){
|
||||
var build = closest.build;
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
package mindustry.type;
|
||||
|
||||
import arc.graphics.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.blocks.environment.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class Item extends UnlockableContent{
|
||||
public final Color color;
|
||||
public Color color;
|
||||
|
||||
/** how explosive this item is. */
|
||||
public float explosiveness = 0f;
|
||||
@@ -36,8 +35,10 @@ public class Item extends UnlockableContent{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayInfo(Table table){
|
||||
ContentDisplay.displayItem(table, this);
|
||||
public void setStats(){
|
||||
stats.addPercent(Stat.explosiveness, explosiveness);
|
||||
stats.addPercent(Stat.flammability, flammability);
|
||||
stats.addPercent(Stat.radioactivity, radioactivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,6 +21,13 @@ public class ItemSeq implements Iterable<ItemStack>, Serializable{
|
||||
stacks.each(this::add);
|
||||
}
|
||||
|
||||
public ItemSeq copy(){
|
||||
ItemSeq out = new ItemSeq();
|
||||
out.total = total;
|
||||
System.arraycopy(values, 0, out.values, 0, values.length);
|
||||
return out;
|
||||
}
|
||||
|
||||
public void each(ItemConsumer cons){
|
||||
for(int i = 0; i < values.length; i++){
|
||||
if(values[i] != 0){
|
||||
@@ -46,6 +53,19 @@ public class ItemSeq implements Iterable<ItemStack>, Serializable{
|
||||
return values[item.id] > 0;
|
||||
}
|
||||
|
||||
public boolean has(ItemSeq seq){
|
||||
for(int i = 0; i < values.length; i++){
|
||||
if(seq.values[i] > values[i]){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean has(Item item, int amount){
|
||||
return values[item.id] >= amount;
|
||||
}
|
||||
|
||||
public int get(Item item){
|
||||
return values[item.id];
|
||||
}
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package mindustry.type;
|
||||
|
||||
import arc.graphics.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.util.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
public class Liquid extends UnlockableContent{
|
||||
/** Color used in pipes and on the ground. */
|
||||
public final Color color;
|
||||
public Color color;
|
||||
/** Color used in bars. */
|
||||
public @Nullable Color barColor;
|
||||
/** Color used to draw lights. Note that the alpha channel is used to dictate brightness. */
|
||||
@@ -46,8 +45,12 @@ public class Liquid extends UnlockableContent{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayInfo(Table table){
|
||||
ContentDisplay.displayLiquid(table, this);
|
||||
public void setStats(){
|
||||
stats.addPercent(Stat.explosiveness, explosiveness);
|
||||
stats.addPercent(Stat.flammability, flammability);
|
||||
stats.addPercent(Stat.temperature, temperature);
|
||||
stats.addPercent(Stat.heatCapacity, heatCapacity);
|
||||
stats.addPercent(Stat.viscosity, viscosity);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,7 +5,6 @@ import arc.func.*;
|
||||
import arc.graphics.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.noise.*;
|
||||
@@ -259,11 +258,6 @@ public class Planet extends UnlockableContent{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayInfo(Table table){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getContentType(){
|
||||
return ContentType.planet;
|
||||
|
||||
@@ -40,9 +40,22 @@ public class Sector{
|
||||
this.id = tile.id;
|
||||
}
|
||||
|
||||
/** @return a copy of the items in this sector - may be core items, or stored data. */
|
||||
public ItemSeq getItems(){
|
||||
if(isBeingPlayed()){
|
||||
ItemSeq out = new ItemSeq();
|
||||
if(state.rules.defaultTeam.core() != null) out.add(state.rules.defaultTeam.core().items);
|
||||
return out;
|
||||
}else{
|
||||
return info.items;
|
||||
}
|
||||
}
|
||||
|
||||
public Seq<Sector> near(){
|
||||
tmpSeq1.clear();
|
||||
near(tmpSeq1::add);
|
||||
for(Ptile tile : tile.tiles){
|
||||
tmpSeq1.add(planet.getSector(tile));
|
||||
}
|
||||
|
||||
return tmpSeq1;
|
||||
}
|
||||
@@ -131,6 +144,12 @@ public class Sector{
|
||||
removeItem(item, -amount);
|
||||
}
|
||||
|
||||
public void removeItems(ItemSeq items){
|
||||
ItemSeq copy = items.copy();
|
||||
copy.each((i, a) -> copy.set(i, -a));
|
||||
addItems(copy);
|
||||
}
|
||||
|
||||
public void removeItem(Item item, int amount){
|
||||
ItemSeq seq = new ItemSeq();
|
||||
seq.add(item, -amount);
|
||||
|
||||
@@ -2,7 +2,6 @@ package mindustry.type;
|
||||
|
||||
import arc.func.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
@@ -39,11 +38,6 @@ public class SectorPreset extends UnlockableContent{
|
||||
return true;
|
||||
}
|
||||
|
||||
//neither of these are implemented, as zones are not displayed in a normal fashion... yet
|
||||
@Override
|
||||
public void displayInfo(Table table){
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getContentType(){
|
||||
return ContentType.sector;
|
||||
|
||||
@@ -28,6 +28,8 @@ import mindustry.world.blocks.environment.*;
|
||||
import mindustry.world.blocks.payloads.*;
|
||||
import mindustry.world.blocks.units.*;
|
||||
import mindustry.world.consumers.*;
|
||||
import mindustry.world.meta.*;
|
||||
import mindustry.world.meta.values.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@@ -41,7 +43,7 @@ public class UnitType extends UnlockableContent{
|
||||
public Prov<? extends UnitController> defaultController = () -> !flying ? new GroundAI() : new FlyingAI();
|
||||
public float speed = 1.1f, boostMultiplier = 1f, rotateSpeed = 5f, baseRotateSpeed = 5f;
|
||||
public float drag = 0.3f, accel = 0.5f, landShake = 0f, rippleScale = 1f, fallSpeed = 0.018f;
|
||||
public float health = 200f, range = -1, armor = 0f;
|
||||
public float health = 200f, range = -1, armor = 0f, maxRange = -1f;
|
||||
public float crashDamageMultiplier = 1f;
|
||||
public boolean targetAir = true, targetGround = true;
|
||||
public boolean faceTarget = true, rotateShooting = true, isCounted = true, lowAltitude = false;
|
||||
@@ -58,6 +60,7 @@ public class UnitType extends UnlockableContent{
|
||||
public Effect fallEffect = Fx.fallSmoke;
|
||||
public Effect fallThrusterEffect = Fx.fallSmoke;
|
||||
public Seq<Ability> abilities = new Seq<>();
|
||||
public BlockFlag targetFlag = BlockFlag.generator;
|
||||
|
||||
public int legCount = 4, legGroupSize = 2;
|
||||
public float legLength = 10f, legSpeed = 0.1f, legTrns = 1f, legBaseOffset = 0f, legMoveSpace = 1f, legExtension = 0, legPairOffset = 0, legLengthScl = 1f, kinematicScl = 1f, maxStretch = 1.75f;
|
||||
@@ -156,11 +159,11 @@ public class UnitType extends UnlockableContent{
|
||||
table.table(bars -> {
|
||||
bars.defaults().growX().height(20f).pad(4);
|
||||
|
||||
bars.add(new Bar("blocks.health", Pal.health, unit::healthf).blink(Color.white));
|
||||
bars.add(new Bar("stat.health", Pal.health, unit::healthf).blink(Color.white));
|
||||
bars.row();
|
||||
|
||||
if(state.rules.unitAmmo){
|
||||
bars.add(new Bar(ammoType.icon + " " + Core.bundle.get("blocks.ammo"), ammoType.barColor, () -> unit.ammo / ammoCapacity));
|
||||
bars.add(new Bar(ammoType.icon + " " + Core.bundle.get("stat.ammo"), ammoType.barColor, () -> unit.ammo / ammoCapacity));
|
||||
bars.row();
|
||||
}
|
||||
}).growX();
|
||||
@@ -188,10 +191,21 @@ public class UnitType extends UnlockableContent{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void displayInfo(Table table){
|
||||
ContentDisplay.displayUnit(table, this);
|
||||
public void setStats(){
|
||||
Unit inst = constructor.get();
|
||||
|
||||
stats.add(Stat.health, health);
|
||||
stats.add(Stat.speed, speed);
|
||||
stats.add(Stat.itemCapacity, health);
|
||||
stats.add(Stat.range, (int)(maxRange / tilesize), StatUnit.blocks);
|
||||
//TODO abilities, maybe try something like DPS
|
||||
|
||||
if(inst instanceof Minerc && mineTier >= 1){
|
||||
stats.addPercent(Stat.mineSpeed, mineSpeed);
|
||||
stats.add(Stat.mineTier, new BlockFilterValue(b -> b instanceof Floor f && f.itemDrop != null && f.itemDrop.hardness <= mineTier && !f.playerUnmineable));
|
||||
}
|
||||
if(inst instanceof Builderc) stats.addPercent(Stat.buildSpeed, buildSpeed);
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
@@ -217,8 +231,10 @@ public class UnitType extends UnlockableContent{
|
||||
//set up default range
|
||||
if(range < 0){
|
||||
range = Float.MAX_VALUE;
|
||||
maxRange = 0f;
|
||||
for(Weapon weapon : weapons){
|
||||
range = Math.min(range, weapon.bullet.range() + hitSize /2f);
|
||||
maxRange = Math.max(maxRange, weapon.bullet.range() + hitSize /2f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,7 +338,7 @@ public class UnitType extends UnlockableContent{
|
||||
if(stacks != null){
|
||||
ItemStack[] out = new ItemStack[stacks.length];
|
||||
for(int i = 0; i < out.length; i++){
|
||||
out[i] = new ItemStack(stacks[i].item, UI.roundAmount((int)(Math.pow(stacks[i].amount, 1.1) * 50)));
|
||||
out[i] = new ItemStack(stacks[i].item, UI.roundAmount((int)(Math.pow(stacks[i].amount, 1) * 50)));
|
||||
}
|
||||
|
||||
return out;
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
package mindustry.type;
|
||||
|
||||
import arc.*;
|
||||
import arc.func.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.util.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
@@ -91,9 +93,136 @@ public abstract class Weather extends UnlockableContent{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayInfo(Table table){
|
||||
//do not
|
||||
public void drawParticles(TextureRegion region, Color color,
|
||||
float sizeMin, float sizeMax,
|
||||
float density, float intensity, float opacity,
|
||||
float windx, float windy,
|
||||
float minAlpha, float maxAlpha,
|
||||
float sinSclMin, float sinSclMax, float sinMagMin, float sinMagMax){
|
||||
rand.setSeed(0);
|
||||
Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale());
|
||||
Tmp.r1.grow(sizeMax * 1.5f);
|
||||
Core.camera.bounds(Tmp.r2);
|
||||
int total = (int)(Tmp.r1.area() / density * intensity);
|
||||
Draw.color(color, opacity);
|
||||
|
||||
for(int i = 0; i < total; i++){
|
||||
float scl = rand.random(0.5f, 1f);
|
||||
float scl2 = rand.random(0.5f, 1f);
|
||||
float size = rand.random(sizeMin, sizeMax);
|
||||
float x = (rand.random(0f, world.unitWidth()) + Time.time() * windx * scl2);
|
||||
float y = (rand.random(0f, world.unitHeight()) + Time.time() * windy * scl);
|
||||
float alpha = rand.random(minAlpha, maxAlpha);
|
||||
|
||||
x += Mathf.sin(y, rand.random(sinSclMin, sinSclMax), rand.random(sinMagMin, sinMagMax));
|
||||
|
||||
x -= Tmp.r1.x;
|
||||
y -= Tmp.r1.y;
|
||||
x = Mathf.mod(x, Tmp.r1.width);
|
||||
y = Mathf.mod(y, Tmp.r1.height);
|
||||
x += Tmp.r1.x;
|
||||
y += Tmp.r1.y;
|
||||
|
||||
if(Tmp.r3.setCentered(x, y, size).overlaps(Tmp.r2)){
|
||||
Draw.alpha(alpha * opacity);
|
||||
Draw.rect(region, x, y, size, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void drawRain(float sizeMin, float sizeMax, float xspeed, float yspeed, float density, float intensity, float stroke, Color color){
|
||||
float padding = sizeMax*0.9f;
|
||||
|
||||
Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale());
|
||||
Tmp.r1.grow(padding);
|
||||
Core.camera.bounds(Tmp.r2);
|
||||
int total = (int)(Tmp.r1.area() / density * intensity);
|
||||
Lines.stroke(stroke);
|
||||
float alpha = Draw.getColor().a;
|
||||
Draw.color(color);
|
||||
|
||||
for(int i = 0; i < total; i++){
|
||||
float scl = rand.random(0.5f, 1f);
|
||||
float scl2 = rand.random(0.5f, 1f);
|
||||
float size = rand.random(sizeMin, sizeMax);
|
||||
float x = (rand.random(0f, world.unitWidth()) + Time.time() * xspeed * scl2);
|
||||
float y = (rand.random(0f, world.unitHeight()) - Time.time() * yspeed * scl);
|
||||
float tint = rand.random(1f) * alpha;
|
||||
|
||||
x -= Tmp.r1.x;
|
||||
y -= Tmp.r1.y;
|
||||
x = Mathf.mod(x, Tmp.r1.width);
|
||||
y = Mathf.mod(y, Tmp.r1.height);
|
||||
x += Tmp.r1.x;
|
||||
y += Tmp.r1.y;
|
||||
|
||||
if(Tmp.r3.setCentered(x, y, size).overlaps(Tmp.r2)){
|
||||
Draw.alpha(tint);
|
||||
Lines.lineAngle(x, y, Angles.angle(xspeed * scl2, - yspeed * scl), size/2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void drawSplashes(TextureRegion[] splashes, float padding, float density, float intensity, float opacity, float timeScale, float stroke, Color color, Liquid splasher){
|
||||
Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale());
|
||||
Tmp.r1.grow(padding);
|
||||
Core.camera.bounds(Tmp.r2);
|
||||
int total = (int)(Tmp.r1.area() / density * intensity) / 2;
|
||||
Lines.stroke(stroke);
|
||||
|
||||
float t = Time.time() / timeScale;
|
||||
|
||||
for(int i = 0; i < total; i++){
|
||||
float offset = rand.random(0f, 1f);
|
||||
float time = t + offset;
|
||||
|
||||
int pos = (int)((time));
|
||||
float life = time % 1f;
|
||||
float x = (rand.random(0f, world.unitWidth()) + pos*953);
|
||||
float y = (rand.random(0f, world.unitHeight()) - pos*453);
|
||||
|
||||
x -= Tmp.r1.x;
|
||||
y -= Tmp.r1.y;
|
||||
x = Mathf.mod(x, Tmp.r1.width);
|
||||
y = Mathf.mod(y, Tmp.r1.height);
|
||||
x += Tmp.r1.x;
|
||||
y += Tmp.r1.y;
|
||||
|
||||
if(Tmp.r3.setCentered(x, y, life * 4f).overlaps(Tmp.r2)){
|
||||
Tile tile = world.tileWorld(x, y);
|
||||
|
||||
//only create splashes on specific liquid.
|
||||
if(tile != null && tile.floor().liquidDrop == splasher){
|
||||
Draw.color(Tmp.c1.set(tile.floor().mapColor).mul(1.5f).a(opacity));
|
||||
Draw.rect(splashes[(int)(life * (splashes.length - 1))], x, y);
|
||||
}else if(tile != null && tile.floor().liquidDrop == null && !tile.floor().solid){
|
||||
Draw.color(color);
|
||||
Draw.alpha(Mathf.slope(life) * opacity);
|
||||
|
||||
float space = 45f;
|
||||
for(int j : new int[]{-1, 1}){
|
||||
Tmp.v1.trns(90f + j*space, 1f + 5f * life);
|
||||
Lines.lineAngle(x + Tmp.v1.x, y + Tmp.v1.y, 90f + j*space, 3f * (1f - life));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void drawNoise(Texture noise, Color color, float noisescl, float opacity, float baseSpeed, float intensity, float vwindx, float vwindy, float offset){
|
||||
Draw.alpha(opacity);
|
||||
Draw.tint(color);
|
||||
|
||||
float speed = baseSpeed * intensity;
|
||||
float windx = vwindx * speed, windy = vwindy * speed;
|
||||
|
||||
float scale = 1f / noisescl;
|
||||
float scroll = Time.time() * scale + offset;
|
||||
Tmp.tr1.texture = noise;
|
||||
Core.camera.bounds(Tmp.r1);
|
||||
Tmp.tr1.set(Tmp.r1.x*scale, Tmp.r1.y*scale, (Tmp.r1.x + Tmp.r1.width)*scale, (Tmp.r1.y + Tmp.r1.height)*scale);
|
||||
Tmp.tr1.scroll(-windx * scroll, -windy * scroll);
|
||||
Draw.rect(Tmp.tr1, Core.camera.position.x, Core.camera.position.y, Core.camera.width, -Core.camera.height);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
90
core/src/mindustry/type/weather/ParticleWeather.java
Normal file
90
core/src/mindustry/type/weather/ParticleWeather.java
Normal file
@@ -0,0 +1,90 @@
|
||||
package mindustry.type.weather;
|
||||
|
||||
import arc.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.Texture.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.util.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
|
||||
public class ParticleWeather extends Weather{
|
||||
public String particleRegion = "circle-shadow";
|
||||
public Color color = Color.white.cpy();
|
||||
public TextureRegion region;
|
||||
public float yspeed = -2f, xspeed = 0.25f, padding = 16f, sizeMin = 2.4f, sizeMax = 12f, density = 1200f, minAlpha = 1f, maxAlpha = 1f, force = 0, noiseScale = 2000f, baseSpeed = 6.1f;
|
||||
public float sinSclMin = 30f, sinSclMax = 80f, sinMagMin = 1f, sinMagMax = 7f;
|
||||
|
||||
public Color noiseColor = color;
|
||||
public boolean drawNoise = false, drawParticles = true, useWindVector = false;
|
||||
public int noiseLayers = 1;
|
||||
public float noiseLayerSpeedM = 1.1f, noiseLayerAlphaM = 0.8f, noiseLayerSclM = 0.99f, noiseLayerColorM = 1f;
|
||||
public String noisePath = "noiseAlpha";
|
||||
public @Nullable Texture noise;
|
||||
|
||||
public ParticleWeather(String name){
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
super.load();
|
||||
|
||||
region = Core.atlas.find(particleRegion);
|
||||
|
||||
//load noise texture
|
||||
//TODO mod support
|
||||
if(drawNoise){
|
||||
Core.assets.load("sprites/" + noisePath + ".png", Texture.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(WeatherState state){
|
||||
float speed = force * state.intensity;
|
||||
if(speed > 0.001f){
|
||||
float windx = state.windVector.x * speed, windy = state.windVector.y * speed;
|
||||
|
||||
for(Unit unit : Groups.unit){
|
||||
unit.impulse(windx, windy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOver(WeatherState state){
|
||||
|
||||
float windx, windy;
|
||||
if(useWindVector){
|
||||
float speed = baseSpeed * state.intensity;
|
||||
windx = state.windVector.x * speed;
|
||||
windy = state.windVector.y * speed;
|
||||
}else{
|
||||
windx = this.xspeed;
|
||||
windy = this.yspeed;
|
||||
}
|
||||
|
||||
if(drawNoise){
|
||||
if(noise == null){
|
||||
noise = Core.assets.get("sprites/" + noisePath + ".png", Texture.class);
|
||||
noise.setWrap(TextureWrap.repeat);
|
||||
noise.setFilter(TextureFilter.linear);
|
||||
}
|
||||
|
||||
float sspeed = 1f, sscl = 1f, salpha = 1f, offset = 0f;
|
||||
Color col = Tmp.c1.set(noiseColor);
|
||||
for(int i = 0; i < noiseLayers; i++){
|
||||
drawNoise(noise, noiseColor, noiseScale * sscl, state.opacity * salpha * opacityMultiplier, baseSpeed * sspeed, state.intensity, windx, windy, offset);
|
||||
sspeed *= noiseLayerSpeedM;
|
||||
salpha *= noiseLayerAlphaM;
|
||||
sscl *= noiseLayerSclM;
|
||||
offset += 0.29f;
|
||||
col.mul(noiseLayerColorM);
|
||||
}
|
||||
}
|
||||
|
||||
if(drawParticles){
|
||||
drawParticles(region, color, sizeMin, sizeMax, density, state.intensity, state.opacity, windx, windy, minAlpha, maxAlpha, sinSclMin, sinSclMax, sinMagMin, sinMagMax);
|
||||
}
|
||||
}
|
||||
}
|
||||
38
core/src/mindustry/type/weather/RainWeather.java
Normal file
38
core/src/mindustry/type/weather/RainWeather.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package mindustry.type.weather;
|
||||
|
||||
import arc.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
|
||||
public class RainWeather extends Weather{
|
||||
public float yspeed = 5f, xspeed = 1.5f, padding = 16f, density = 1200f, stroke = 0.75f, sizeMin = 8f, sizeMax = 40f, splashTimeScale = 22f;
|
||||
public Liquid liquid = Liquids.water;
|
||||
public TextureRegion[] splashes = new TextureRegion[12];
|
||||
public Color color = Color.valueOf("7a95eaff");
|
||||
|
||||
public RainWeather(String name){
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
super.load();
|
||||
|
||||
for(int i = 0; i < splashes.length; i++){
|
||||
splashes[i] = Core.atlas.find("splash-" + i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOver(WeatherState state){
|
||||
drawRain(sizeMin, sizeMax, xspeed, yspeed, density, state.intensity, stroke, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawUnder(WeatherState state){
|
||||
drawSplashes(splashes, sizeMax, density, state.intensity, state.opacity, splashTimeScale, stroke, color, liquid);
|
||||
}
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
package mindustry.ui;
|
||||
|
||||
import arc.*;
|
||||
import arc.graphics.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
public class ContentDisplay{
|
||||
|
||||
public static void displayBlock(Table table, Block block){
|
||||
|
||||
table.table(title -> {
|
||||
int size = 8 * 6;
|
||||
|
||||
title.image(block.icon(Cicon.xlarge)).size(size);
|
||||
title.add("[accent]" + block.localizedName).padLeft(5);
|
||||
});
|
||||
|
||||
table.row();
|
||||
|
||||
table.image().height(3).color(Color.lightGray).pad(8).padLeft(0).padRight(0).fillX();
|
||||
|
||||
table.row();
|
||||
|
||||
if(block.description != null){
|
||||
table.add(block.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX();
|
||||
table.row();
|
||||
|
||||
table.image().height(3).color(Color.lightGray).pad(8).padLeft(0).padRight(0).fillX();
|
||||
table.row();
|
||||
}
|
||||
|
||||
BlockStats stats = block.stats;
|
||||
|
||||
for(StatCategory cat : stats.toMap().keys()){
|
||||
OrderedMap<BlockStat, Seq<StatValue>> map = stats.toMap().get(cat);
|
||||
|
||||
if(map.size == 0) continue;
|
||||
|
||||
table.add("@category." + cat.name()).color(Pal.accent).fillX();
|
||||
table.row();
|
||||
|
||||
for(BlockStat stat : map.keys()){
|
||||
table.table(inset -> {
|
||||
inset.left();
|
||||
inset.add("[lightgray]" + stat.localized() + ":[] ").left();
|
||||
Seq<StatValue> arr = map.get(stat);
|
||||
for(StatValue value : arr){
|
||||
value.display(inset);
|
||||
inset.add().size(10f);
|
||||
}
|
||||
|
||||
}).fillX().padLeft(10);
|
||||
table.row();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void displayItem(Table table, Item item){
|
||||
|
||||
table.table(title -> {
|
||||
title.image(item.icon(Cicon.xlarge)).size(8 * 6);
|
||||
title.add("[accent]" + item.localizedName).padLeft(5);
|
||||
});
|
||||
|
||||
table.row();
|
||||
|
||||
table.image().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX();
|
||||
|
||||
table.row();
|
||||
|
||||
if(item.description != null){
|
||||
table.add(item.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX();
|
||||
table.row();
|
||||
|
||||
table.image().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX();
|
||||
table.row();
|
||||
}
|
||||
|
||||
table.left().defaults().fillX();
|
||||
|
||||
table.add(Core.bundle.format("item.explosiveness", (int)(item.explosiveness * 100)));
|
||||
table.row();
|
||||
table.add(Core.bundle.format("item.flammability", (int)(item.flammability * 100)));
|
||||
table.row();
|
||||
table.add(Core.bundle.format("item.radioactivity", (int)(item.radioactivity * 100)));
|
||||
table.row();
|
||||
}
|
||||
|
||||
public static void displayLiquid(Table table, Liquid liquid){
|
||||
|
||||
table.table(title -> {
|
||||
title.image(liquid.icon(Cicon.xlarge)).size(8 * 6);
|
||||
title.add("[accent]" + liquid.localizedName).padLeft(5);
|
||||
});
|
||||
|
||||
table.row();
|
||||
|
||||
table.image().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX();
|
||||
|
||||
table.row();
|
||||
|
||||
if(liquid.description != null){
|
||||
table.add(liquid.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX();
|
||||
table.row();
|
||||
|
||||
table.image().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX();
|
||||
table.row();
|
||||
}
|
||||
|
||||
table.left().defaults().fillX();
|
||||
|
||||
table.add(Core.bundle.format("item.explosiveness", (int)(liquid.explosiveness * 100)));
|
||||
table.row();
|
||||
table.add(Core.bundle.format("item.flammability", (int)(liquid.flammability * 100)));
|
||||
table.row();
|
||||
table.add(Core.bundle.format("liquid.heatcapacity", (int)(liquid.heatCapacity * 100)));
|
||||
table.row();
|
||||
table.add(Core.bundle.format("liquid.temperature", (int)(liquid.temperature * 100)));
|
||||
table.row();
|
||||
table.add(Core.bundle.format("liquid.viscosity", (int)(liquid.viscosity * 100)));
|
||||
table.row();
|
||||
}
|
||||
|
||||
public static void displayUnit(Table table, UnitType unit){
|
||||
table.table(title -> {
|
||||
title.image(unit.icon(Cicon.xlarge)).size(8 * 6).scaling(Scaling.fit);
|
||||
title.add("[accent]" + unit.localizedName).padLeft(5);
|
||||
});
|
||||
|
||||
table.row();
|
||||
|
||||
table.image().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX();
|
||||
|
||||
table.row();
|
||||
|
||||
if(unit.description != null){
|
||||
table.add(unit.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX();
|
||||
table.row();
|
||||
|
||||
table.image().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX();
|
||||
table.row();
|
||||
}
|
||||
|
||||
table.left().defaults().fillX();
|
||||
|
||||
Unit inst = unit.constructor.get();
|
||||
|
||||
//TODO more stats
|
||||
table.add(Core.bundle.format("unit.health", unit.health)).row();
|
||||
table.add(Core.bundle.format("unit.speed", Strings.fixed(unit.speed, 1))).row();
|
||||
table.add(Core.bundle.format("unit.itemcapacity", unit.itemCapacity)).row();
|
||||
|
||||
if(inst instanceof Minerc) table.add(Core.bundle.format("unit.minespeed", (int)(unit.mineSpeed * 100f))).row();
|
||||
if(inst instanceof Builderc) table.add(Core.bundle.format("unit.buildspeed", (int)(unit.buildSpeed * 100f))).row();
|
||||
|
||||
table.row();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,14 @@
|
||||
package mindustry.ui.dialogs;
|
||||
|
||||
import arc.graphics.*;
|
||||
import arc.scene.ui.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
public class ContentInfoDialog extends BaseDialog{
|
||||
|
||||
@@ -18,11 +24,62 @@ public class ContentInfoDialog extends BaseDialog{
|
||||
Table table = new Table();
|
||||
table.margin(10);
|
||||
|
||||
content.displayInfo(table);
|
||||
//initialize stats if they haven't been yet
|
||||
content.checkStats();
|
||||
|
||||
table.table(title1 -> {
|
||||
int size = 8 * 6;
|
||||
|
||||
title1.image(content.icon(Cicon.xlarge)).size(size).scaling(Scaling.fit);
|
||||
title1.add("[accent]" + content.localizedName).padLeft(5);
|
||||
});
|
||||
|
||||
table.row();
|
||||
|
||||
table.image().height(3).color(Color.lightGray).pad(8).padLeft(0).padRight(0).fillX();
|
||||
|
||||
table.row();
|
||||
|
||||
if(content.description != null){
|
||||
table.add(content.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX();
|
||||
table.row();
|
||||
|
||||
table.image().height(3).color(Color.lightGray).pad(8).padLeft(0).padRight(0).fillX();
|
||||
table.row();
|
||||
}
|
||||
|
||||
Stats stats = content.stats;
|
||||
|
||||
for(StatCat cat : stats.toMap().keys()){
|
||||
OrderedMap<Stat, Seq<StatValue>> map = stats.toMap().get(cat);
|
||||
|
||||
if(map.size == 0) continue;
|
||||
|
||||
//TODO check
|
||||
if(stats.useCategories){
|
||||
table.add("@category." + cat.name()).color(Pal.accent).fillX();
|
||||
table.row();
|
||||
}
|
||||
|
||||
for(Stat stat : map.keys()){
|
||||
table.table(inset -> {
|
||||
inset.left();
|
||||
inset.add("[lightgray]" + stat.localized() + ":[] ").left();
|
||||
Seq<StatValue> arr = map.get(stat);
|
||||
for(StatValue value : arr){
|
||||
value.display(inset);
|
||||
inset.add().size(10f);
|
||||
}
|
||||
|
||||
}).fillX().padLeft(10);
|
||||
table.row();
|
||||
}
|
||||
}
|
||||
|
||||
ScrollPane pane = new ScrollPane(table);
|
||||
cont.add(pane);
|
||||
|
||||
show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package mindustry.ui.dialogs;
|
||||
|
||||
import arc.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.game.Stats.*;
|
||||
import mindustry.game.GameStats.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
|
||||
@@ -30,7 +30,7 @@ public class LaunchLoadoutDialog extends BaseDialog{
|
||||
super("@configure");
|
||||
}
|
||||
|
||||
public void show(CoreBlock core, Building build, Runnable confirm){
|
||||
public void show(CoreBlock core, Sector sector, Runnable confirm){
|
||||
cont.clear();
|
||||
buttons.clear();
|
||||
|
||||
@@ -43,12 +43,14 @@ public class LaunchLoadoutDialog extends BaseDialog{
|
||||
}
|
||||
});
|
||||
|
||||
ItemSeq sitems = sector.getItems();
|
||||
|
||||
//updates sum requirements
|
||||
Runnable update = () -> {
|
||||
total.clear();
|
||||
selected.requirements().each(total::add);
|
||||
universe.getLaunchResources().each(total::add);
|
||||
valid = build.items.has(total);
|
||||
valid = sitems.has(total);
|
||||
};
|
||||
|
||||
Cons<Table> rebuild = table -> {
|
||||
@@ -65,8 +67,8 @@ public class LaunchLoadoutDialog extends BaseDialog{
|
||||
String amountStr = "[lightgray]" + (al + " + [accent]" + as + "[lightgray]");
|
||||
|
||||
table.add(
|
||||
build.items.has(s.item, s.amount) ? amountStr :
|
||||
"[scarlet]" + (Math.min(build.items.get(s.item), s.amount) + "[lightgray]/" + amountStr)).padLeft(2).left().padRight(4);
|
||||
sitems.has(s.item, s.amount) ? amountStr :
|
||||
"[scarlet]" + (Math.min(sitems.get(s.item), s.amount) + "[lightgray]/" + amountStr)).padLeft(2).left().padRight(4);
|
||||
|
||||
if(++i % 4 == 0){
|
||||
table.row();
|
||||
@@ -108,7 +110,7 @@ public class LaunchLoadoutDialog extends BaseDialog{
|
||||
selected = s;
|
||||
update.run();
|
||||
rebuildItems.run();
|
||||
}).group(group).pad(4).disabled(!build.items.has(s.requirements())).checked(s == selected).size(200f);
|
||||
}).group(group).pad(4).disabled(!sitems.has(s.requirements())).checked(s == selected).size(200f);
|
||||
|
||||
if(++i % cols == 0){
|
||||
t.row();
|
||||
|
||||
@@ -78,10 +78,7 @@ public class PausedDialog extends BaseDialog{
|
||||
|
||||
cont.buttonRow("@load", Icon.download, load::show).disabled(b -> net.active());
|
||||
}else if(state.isCampaign()){
|
||||
cont.buttonRow("@launchcore", Icon.up, () -> {
|
||||
hide();
|
||||
ui.planet.showLaunch(state.getSector(), player.team().core());
|
||||
}).disabled(b -> player.team().core() == null || net.client());
|
||||
cont.buttonRow("@research", Icon.tree, ui.research::show);
|
||||
|
||||
cont.row();
|
||||
|
||||
@@ -93,11 +90,7 @@ public class PausedDialog extends BaseDialog{
|
||||
cont.row();
|
||||
}
|
||||
|
||||
if(state.isCampaign() && net.active()){
|
||||
cont.buttonRow("@research", Icon.tree, ui.research::show);
|
||||
}else{
|
||||
cont.buttonRow("@hostserver.mobile", Icon.host, ui.host::show).disabled(b -> net.active());
|
||||
}
|
||||
cont.buttonRow("@hostserver.mobile", Icon.host, ui.host::show).disabled(b -> net.active());
|
||||
|
||||
cont.buttonRow("@quit", Icon.exit, this::showQuitConfirm).update(s -> {
|
||||
s.setText(control.saves.getCurrent() != null && control.saves.getCurrent().isAutosave() ? "@save.quit" : "@quit");
|
||||
|
||||
@@ -13,6 +13,7 @@ import arc.scene.event.*;
|
||||
import arc.scene.ui.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.util.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.core.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.game.*;
|
||||
@@ -22,7 +23,6 @@ import mindustry.graphics.g3d.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.blocks.storage.*;
|
||||
import mindustry.world.blocks.storage.CoreBlock.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
import static mindustry.graphics.g3d.PlanetRenderer.*;
|
||||
@@ -40,7 +40,6 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
public int launchRange;
|
||||
public float zoom = 1f, selectAlpha = 1f;
|
||||
public @Nullable Sector selected, hovered, launchSector;
|
||||
public CoreBuild launcher;
|
||||
public Mode mode = look;
|
||||
public boolean launching;
|
||||
public Cons<Sector> listener = s -> {};
|
||||
@@ -91,9 +90,16 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
mode = look;
|
||||
selected = hovered = launchSector = null;
|
||||
launching = false;
|
||||
|
||||
zoom = 1f;
|
||||
planets.zoom = 1f;
|
||||
selectAlpha = 0f;
|
||||
launchSector = state.getSector();
|
||||
|
||||
if(planets.planet.getLastSector() != null){
|
||||
lookAt(planets.planet.getLastSector());
|
||||
}
|
||||
|
||||
return super.show();
|
||||
}
|
||||
|
||||
@@ -106,7 +112,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
//update view to sector
|
||||
lookAt(sector);
|
||||
zoom = 1f;
|
||||
planets.zoom = 2f;
|
||||
planets.zoom = 1f;
|
||||
selectAlpha = 0f;
|
||||
launchSector = sector;
|
||||
|
||||
@@ -115,37 +121,33 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
super.show();
|
||||
}
|
||||
|
||||
public void showLaunch(Sector sector, CoreBuild launcher){
|
||||
if(launcher == null) return;
|
||||
|
||||
this.launcher = launcher;
|
||||
selected = null;
|
||||
hovered = null;
|
||||
launching = false;
|
||||
|
||||
//update view to sector
|
||||
lookAt(sector);
|
||||
zoom = 1f;
|
||||
planets.zoom = 2f;
|
||||
selectAlpha = 0f;
|
||||
launchRange = ((CoreBlock)launcher.block).launchRange;
|
||||
launchSector = sector;
|
||||
|
||||
mode = launch;
|
||||
|
||||
super.show();
|
||||
}
|
||||
|
||||
private void lookAt(Sector sector){
|
||||
void lookAt(Sector sector){
|
||||
planets.camPos.set(Tmp.v33.set(sector.tile.v).rotate(Vec3.Y, -sector.planet.getRotation()));
|
||||
}
|
||||
|
||||
boolean canSelect(Sector sector){
|
||||
if(mode == select) return sector.hasBase();
|
||||
|
||||
return mode == launch &&
|
||||
(sector.tile.v.within(launchSector.tile.v, (launchRange + 0.5f) * planets.planet.sectorApproxRadius*2) //within range
|
||||
|| (sector.preset != null && sector.preset.unlocked())); //is an unlocked preset
|
||||
return sector.near().contains(Sector::hasBase)//(sector.tile.v.within(launchSector.tile.v, (launchRange + 0.5f) * planets.planet.sectorApproxRadius*2) //within range
|
||||
|| (sector.preset != null && sector.preset.unlocked()); //is an unlocked preset
|
||||
}
|
||||
|
||||
Sector findLauncher(Sector to){
|
||||
//directly nearby.
|
||||
if(to.near().contains(launchSector)) return launchSector;
|
||||
|
||||
Sector launchFrom = launchSector;
|
||||
if(launchFrom == null){
|
||||
//TODO pick one with the most resources
|
||||
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));
|
||||
if(!launchFrom.hasBase()) launchFrom = null;
|
||||
}
|
||||
}
|
||||
|
||||
return launchFrom;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -157,9 +159,6 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
|
||||
if(selectAlpha > 0.01f){
|
||||
if(canSelect(sec) || sec.unlocked()){
|
||||
if(sec.baseCoverage > 0){
|
||||
planets.fill(sec, Tmp.c1.set(Team.crux.color).a(0.5f * sec.baseCoverage * selectAlpha), -0.002f);
|
||||
}
|
||||
|
||||
Color color =
|
||||
sec.hasBase() ? Team.sharded.color :
|
||||
@@ -177,8 +176,10 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
}
|
||||
}
|
||||
|
||||
if(launchSector != null){
|
||||
planets.fill(launchSector, hoverColor, -0.001f);
|
||||
Sector current = state.getSector() != null && state.getSector().isBeingPlayed() ? state.getSector() : null;
|
||||
|
||||
if(current != null){
|
||||
planets.fill(current, hoverColor, -0.001f);
|
||||
}
|
||||
|
||||
//draw hover border
|
||||
@@ -195,9 +196,10 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
|
||||
planets.batch.flush(Gl.triangles);
|
||||
|
||||
if(mode == launch || mode == select){
|
||||
if(hovered != launchSector && hovered != null && canSelect(hovered)){
|
||||
planets.drawArc(planet, launchSector.tile.v, hovered.tile.v);
|
||||
if(hovered != null && !hovered.hasBase()){
|
||||
Sector launchFrom = findLauncher(hovered);
|
||||
if(launchFrom != null && hovered != launchFrom && canSelect(hovered)){
|
||||
planets.drawArc(planet, launchFrom.tile.v, hovered.tile.v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +246,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
addListener(new ElementGestureListener(){
|
||||
@Override
|
||||
public void tap(InputEvent event, float x, float y, int count, KeyCode button){
|
||||
if(hovered != null && ((mode == launch ? canSelect(hovered) && hovered != launchSector : hovered.unlocked()) || debugSelect)){
|
||||
if(hovered != null && ((mode == look ? canSelect(hovered) && hovered != launchSector : hovered.unlocked()) || debugSelect)){
|
||||
selected = hovered;
|
||||
}
|
||||
|
||||
@@ -263,9 +265,8 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
},
|
||||
new Table(t -> {
|
||||
t.touchable = Touchable.disabled;
|
||||
//TODO localize
|
||||
t.top();
|
||||
t.label(() -> mode == select ? "@sectors.select" : mode == launch ? "Select Launch Sector" : "").style(Styles.outlineLabel).color(Pal.accent);
|
||||
t.label(() -> mode == select ? "@sectors.select" : "").style(Styles.outlineLabel).color(Pal.accent);
|
||||
}),
|
||||
new Table(t -> {
|
||||
t.right();
|
||||
@@ -322,7 +323,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
stable.toFront();
|
||||
|
||||
//smooth camera toward the sector
|
||||
if(mode == launch && launching){
|
||||
if(mode == look && launching){
|
||||
float len = planets.camPos.len();
|
||||
planets.camPos.slerp(Tmp.v31.set(selected.tile.v).rotate(Vec3.Y,-selected.planet.getRotation()).setLength(len), 0.1f);
|
||||
}
|
||||
@@ -453,17 +454,26 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
}
|
||||
}
|
||||
|
||||
if(mode == launch && !sector.hasBase()){
|
||||
Sector current = state.rules.sector;
|
||||
if(mode == look && !sector.hasBase()){
|
||||
shouldHide = false;
|
||||
loadouts.show((CoreBlock)launcher.block, launcher, () -> {
|
||||
control.handleLaunch(launcher);
|
||||
launching = true;
|
||||
zoom = 0.5f;
|
||||
Sector from = findLauncher(sector);
|
||||
if(from == null){
|
||||
//free launch.
|
||||
control.playSector(sector);
|
||||
}else{
|
||||
CoreBlock block = from.info.bestCoreType instanceof CoreBlock b ? b : (CoreBlock)Blocks.coreShard;
|
||||
|
||||
ui.hudfrag.showLaunchDirect();
|
||||
Time.runTask(launchDuration, () -> control.playSector(current, sector));
|
||||
});
|
||||
loadouts.show(block, from, () -> {
|
||||
from.removeItems(universe.getLastLoadout().requirements());
|
||||
from.removeItems(universe.getLaunchResources());
|
||||
|
||||
launching = true;
|
||||
zoom = 0.5f;
|
||||
|
||||
ui.hudfrag.showLaunchDirect();
|
||||
Time.runTask(launchDuration, () -> control.playSector(from, sector));
|
||||
});
|
||||
}
|
||||
}else if(mode == select){
|
||||
listener.get(sector);
|
||||
}else{
|
||||
@@ -491,7 +501,6 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
selected = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@@ -501,8 +510,6 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
public enum Mode{
|
||||
/** Look around for existing sectors. Can only deploy. */
|
||||
look,
|
||||
/** Launch to a new location. */
|
||||
launch,
|
||||
/** Select a sector for some purpose. */
|
||||
select
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.pooling.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.core.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.entities.*;
|
||||
@@ -50,7 +51,6 @@ public class Block extends UnlockableContent{
|
||||
public float liquidCapacity = 10f;
|
||||
public float liquidPressure = 1f;
|
||||
|
||||
public final BlockStats stats = new BlockStats();
|
||||
public final BlockBars bars = new BlockBars();
|
||||
public final Consumers consumes = new Consumers();
|
||||
|
||||
@@ -320,27 +320,30 @@ public class Block extends UnlockableContent{
|
||||
return update || destructible;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStats(){
|
||||
stats.add(BlockStat.size, "@x@", size, size);
|
||||
stats.add(BlockStat.health, health, StatUnit.none);
|
||||
super.setStats();
|
||||
|
||||
stats.add(Stat.size, "@x@", size, size);
|
||||
stats.add(Stat.health, health, StatUnit.none);
|
||||
if(canBeBuilt()){
|
||||
stats.add(BlockStat.buildTime, buildCost / 60, StatUnit.seconds);
|
||||
stats.add(BlockStat.buildCost, new ItemListValue(false, requirements));
|
||||
stats.add(Stat.buildTime, buildCost / 60, StatUnit.seconds);
|
||||
stats.add(Stat.buildCost, new ItemListValue(false, requirements));
|
||||
}
|
||||
|
||||
if(instantTransfer){
|
||||
stats.add(BlockStat.maxConsecutive, 2, StatUnit.none);
|
||||
stats.add(Stat.maxConsecutive, 2, StatUnit.none);
|
||||
}
|
||||
|
||||
consumes.display(stats);
|
||||
|
||||
// Note: Power stats are added by the consumers.
|
||||
if(hasLiquids) stats.add(BlockStat.liquidCapacity, liquidCapacity, StatUnit.liquidUnits);
|
||||
if(hasItems && itemCapacity > 0) stats.add(BlockStat.itemCapacity, itemCapacity, StatUnit.items);
|
||||
//Note: Power stats are added by the consumers.
|
||||
if(hasLiquids) stats.add(Stat.liquidCapacity, liquidCapacity, StatUnit.liquidUnits);
|
||||
if(hasItems && itemCapacity > 0) stats.add(Stat.itemCapacity, itemCapacity, StatUnit.items);
|
||||
}
|
||||
|
||||
public void setBars(){
|
||||
bars.add("health", entity -> new Bar("blocks.health", Pal.health, entity::healthf).blink(Color.white));
|
||||
bars.add("health", entity -> new Bar("stat.health", Pal.health, entity::healthf).blink(Color.white));
|
||||
|
||||
if(hasLiquids){
|
||||
Func<Building, Liquid> current;
|
||||
@@ -348,7 +351,7 @@ public class Block extends UnlockableContent{
|
||||
Liquid liquid = consumes.<ConsumeLiquid>get(ConsumeType.liquid).liquid;
|
||||
current = entity -> liquid;
|
||||
}else{
|
||||
current = entity -> entity.liquids.current();
|
||||
current = entity -> entity.liquids == null ? Liquids.water : entity.liquids.current();
|
||||
}
|
||||
bars.add("liquid", entity -> new Bar(() -> entity.liquids.get(current.get(entity)) <= 0.001f ? Core.bundle.get("bar.liquid") : current.get(entity).localizedName,
|
||||
() -> current.get(entity).barColor(), () -> entity.liquids.get(current.get(entity)) / liquidCapacity));
|
||||
@@ -617,7 +620,7 @@ public class Block extends UnlockableContent{
|
||||
public ItemStack[] researchRequirements(){
|
||||
ItemStack[] out = new ItemStack[requirements.length];
|
||||
for(int i = 0; i < out.length; i++){
|
||||
int quantity = 40 + Mathf.round(Mathf.pow(requirements[i].amount, 1.25f) * 20 * researchCostMultiplier, 10);
|
||||
int quantity = 40 + Mathf.round(Mathf.pow(requirements[i].amount, 1.15f) * 20 * researchCostMultiplier, 10);
|
||||
|
||||
out[i] = new ItemStack(requirements[i].item, UI.roundAmount(quantity));
|
||||
}
|
||||
@@ -633,11 +636,6 @@ public class Block extends UnlockableContent{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayInfo(Table table){
|
||||
ContentDisplay.displayBlock(table, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getContentType(){
|
||||
return ContentType.block;
|
||||
@@ -668,9 +666,10 @@ public class Block extends UnlockableContent{
|
||||
if(consumes.has(ConsumeType.item)) hasItems = true;
|
||||
if(consumes.has(ConsumeType.liquid)) hasLiquids = true;
|
||||
|
||||
setStats();
|
||||
setBars();
|
||||
|
||||
stats.useCategories = true;
|
||||
|
||||
consumes.init();
|
||||
|
||||
if(!outputsPower && consumes.hasPower() && consumes.getPower().buffered){
|
||||
|
||||
@@ -45,7 +45,7 @@ public class Build{
|
||||
Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(tile, team, true)));
|
||||
}
|
||||
|
||||
/** Places a BuildBlock at this location. */
|
||||
/** Places a ConstructBlock at this location. */
|
||||
@Remote(called = Loc.server)
|
||||
public static void beginPlace(Block result, Team team, int x, int y, int rotation){
|
||||
if(!validPlace(result, team, x, y, rotation)){
|
||||
|
||||
@@ -21,7 +21,7 @@ public class CachedTile extends Tile{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void changeEntity(Team team, Prov<Building> entityprov, int rotation){
|
||||
protected void changeBuild(Team team, Prov<Building> entityprov, int rotation){
|
||||
build = null;
|
||||
|
||||
Block block = block();
|
||||
|
||||
@@ -45,7 +45,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{
|
||||
this.block = wall;
|
||||
|
||||
//update entity and create it if needed
|
||||
changeEntity(Team.derelict, wall::newBuilding, 0);
|
||||
changeBuild(Team.derelict, wall::newBuilding, 0);
|
||||
changed();
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{
|
||||
|
||||
this.block = type;
|
||||
preChanged();
|
||||
changeEntity(team, entityprov, (byte)Mathf.mod(rotation, 4));
|
||||
changeBuild(team, entityprov, (byte)Mathf.mod(rotation, 4));
|
||||
|
||||
if(build != null){
|
||||
build.team(team);
|
||||
@@ -430,15 +430,15 @@ public class Tile implements Position, QuadTreeObject, Displayable{
|
||||
getHitbox(rect);
|
||||
}
|
||||
|
||||
public Tile getNearby(Point2 relative){
|
||||
public Tile nearby(Point2 relative){
|
||||
return world.tile(x + relative.x, y + relative.y);
|
||||
}
|
||||
|
||||
public Tile getNearby(int dx, int dy){
|
||||
public Tile nearby(int dx, int dy){
|
||||
return world.tile(x + dx, y + dy);
|
||||
}
|
||||
|
||||
public Tile getNearby(int rotation){
|
||||
public Tile nearby(int rotation){
|
||||
if(rotation == 0) return world.tile(x + 1, y);
|
||||
if(rotation == 1) return world.tile(x, y + 1);
|
||||
if(rotation == 2) return world.tile(x - 1, y);
|
||||
@@ -446,7 +446,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{
|
||||
return null;
|
||||
}
|
||||
|
||||
public Building getNearbyEntity(int rotation){
|
||||
public Building nearbyBuild(int rotation){
|
||||
if(rotation == 0) return world.build(x + 1, y);
|
||||
if(rotation == 1) return world.build(x, y + 1);
|
||||
if(rotation == 2) return world.build(x - 1, y);
|
||||
@@ -503,7 +503,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{
|
||||
}
|
||||
}
|
||||
|
||||
protected void changeEntity(Team team, Prov<Building> entityprov, int rotation){
|
||||
protected void changeBuild(Team team, Prov<Building> entityprov, int rotation){
|
||||
if(build != null){
|
||||
int size = build.block.size;
|
||||
build.remove();
|
||||
|
||||
@@ -133,7 +133,7 @@ public interface Autotiler{
|
||||
|
||||
for(int i = 0; i < 4; i++){
|
||||
int realDir = Mathf.mod(rotation - i, 4);
|
||||
if(blends(tile, rotation, directional, i, world) && (tile != null && tile.getNearbyEntity(realDir) != null && !tile.getNearbyEntity(realDir).block.squareSprite)){
|
||||
if(blends(tile, rotation, directional, i, world) && (tile != null && tile.nearbyBuild(realDir) != null && !tile.nearbyBuild(realDir).block.squareSprite)){
|
||||
blendresult[4] |= (1 << i);
|
||||
}
|
||||
}
|
||||
@@ -194,7 +194,7 @@ public interface Autotiler{
|
||||
|
||||
// TODO docs -- use for direction?
|
||||
default boolean blends(Tile tile, int rotation, int direction){
|
||||
Building other = tile.getNearbyEntity(Mathf.mod(rotation - direction, 4));
|
||||
Building other = tile.nearbyBuild(Mathf.mod(rotation - direction, 4));
|
||||
return other != null && other.team == tile.team() && blends(tile, rotation, other.tileX(), other.tileY(), other.rotation, other.block);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ public class ConstructBlock extends Block{
|
||||
consBlocks[size - 1] = this;
|
||||
}
|
||||
|
||||
/** Returns a BuildBlock by size. */
|
||||
/** Returns a ConstructBlock by size. */
|
||||
public static ConstructBlock get(int size){
|
||||
if(size > maxSize) throw new IllegalArgumentException("No. Don't place ConstructBlock of size greater than " + maxSize);
|
||||
return consBlocks[size - 1];
|
||||
|
||||
@@ -10,4 +10,14 @@ public interface ControlBlock{
|
||||
default boolean isControlled(){
|
||||
return unit().isPlayer();
|
||||
}
|
||||
|
||||
/** @return whether this block can be controlled at all. */
|
||||
default boolean canControl(){
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @return whether targets should automatically be selected (on mobile) */
|
||||
default boolean shouldAutoTarget(){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class LaunchPad extends Block{
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
||||
stats.add(BlockStat.launchTime, launchTime / 60f, StatUnit.seconds);
|
||||
stats.add(Stat.launchTime, launchTime / 60f, StatUnit.seconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -61,11 +61,11 @@ public class ForceProjector extends Block{
|
||||
@Override
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
stats.add(BlockStat.shieldHealth, breakage, StatUnit.none);
|
||||
stats.add(BlockStat.cooldownTime, (int) (breakage / cooldownBrokenBase / 60f), StatUnit.seconds);
|
||||
stats.add(BlockStat.powerUse, basePowerDraw * 60f, StatUnit.powerSecond);
|
||||
stats.add(BlockStat.boostEffect, phaseRadiusBoost / tilesize, StatUnit.blocks);
|
||||
stats.add(BlockStat.boostEffect, phaseShieldBoost, StatUnit.shieldHealth);
|
||||
stats.add(Stat.shieldHealth, breakage, StatUnit.none);
|
||||
stats.add(Stat.cooldownTime, (int) (breakage / cooldownBrokenBase / 60f), StatUnit.seconds);
|
||||
stats.add(Stat.powerUse, basePowerDraw * 60f, StatUnit.powerSecond);
|
||||
stats.add(Stat.boostEffect, phaseRadiusBoost / tilesize, StatUnit.blocks);
|
||||
stats.add(Stat.boostEffect, phaseShieldBoost, StatUnit.shieldHealth);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -44,11 +44,11 @@ public class MendProjector extends Block{
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
||||
stats.add(BlockStat.repairTime, (int)(100f / healPercent * reload / 60f), StatUnit.seconds);
|
||||
stats.add(BlockStat.range, range / tilesize, StatUnit.blocks);
|
||||
stats.add(Stat.repairTime, (int)(100f / healPercent * reload / 60f), StatUnit.seconds);
|
||||
stats.add(Stat.range, range / tilesize, StatUnit.blocks);
|
||||
|
||||
stats.add(BlockStat.boostEffect, phaseRangeBoost / tilesize, StatUnit.blocks);
|
||||
stats.add(BlockStat.boostEffect, (phaseBoost + healPercent) / healPercent, StatUnit.timesSpeed);
|
||||
stats.add(Stat.boostEffect, phaseRangeBoost / tilesize, StatUnit.blocks);
|
||||
stats.add(Stat.boostEffect, (phaseBoost + healPercent) / healPercent, StatUnit.timesSpeed);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -51,13 +51,13 @@ public class OverdriveProjector extends Block{
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
||||
stats.add(BlockStat.speedIncrease, (int)(100f * speedBoost), StatUnit.percent);
|
||||
stats.add(BlockStat.range, range / tilesize, StatUnit.blocks);
|
||||
stats.add(BlockStat.productionTime, useTime / 60f, StatUnit.seconds);
|
||||
stats.add(Stat.speedIncrease, (int)(100f * speedBoost), StatUnit.percent);
|
||||
stats.add(Stat.range, range / tilesize, StatUnit.blocks);
|
||||
stats.add(Stat.productionTime, useTime / 60f, StatUnit.seconds);
|
||||
|
||||
if(hasBoost){
|
||||
stats.add(BlockStat.boostEffect, phaseRangeBoost / tilesize, StatUnit.blocks);
|
||||
stats.add(BlockStat.boostEffect, (int)((speedBoost + speedBoostPhase) * 100f), StatUnit.percent);
|
||||
stats.add(Stat.boostEffect, phaseRangeBoost / tilesize, StatUnit.blocks);
|
||||
stats.add(Stat.boostEffect, (int)((speedBoost + speedBoostPhase) * 100f), StatUnit.percent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package mindustry.world.blocks.defense.turrets;
|
||||
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.logic.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.consumers.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public abstract class BaseTurret extends Block{
|
||||
public float range = 80f;
|
||||
public float rotateSpeed = 5;
|
||||
|
||||
public boolean acceptCoolant = true;
|
||||
/** Effect displayed when coolant is used. */
|
||||
public Effect coolEffect = Fx.fuelburn;
|
||||
/** How much reload is lowered by for each unit of liquid of heat capacity. */
|
||||
public float coolantMultiplier = 5f;
|
||||
|
||||
public BaseTurret(String name){
|
||||
super(name);
|
||||
|
||||
update = true;
|
||||
solid = true;
|
||||
outlineIcon = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
if(acceptCoolant && !consumes.has(ConsumeType.liquid)){
|
||||
hasLiquids = true;
|
||||
consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 0.2f)).update(false).boost();
|
||||
}
|
||||
|
||||
super.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawPlace(int x, int y, int rotation, boolean valid){
|
||||
Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.placing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
||||
stats.add(Stat.shootRange, range / tilesize, StatUnit.blocks);
|
||||
}
|
||||
|
||||
public class BaseTurretBuild extends Building implements Ranged{
|
||||
public float rotation = 90;
|
||||
|
||||
@Override
|
||||
public float range(){
|
||||
return range;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawSelect(){
|
||||
Drawf.dashCircle(x, y, range, team.color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,8 +35,8 @@ public class ItemTurret extends Turret{
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
||||
stats.remove(BlockStat.itemCapacity);
|
||||
stats.add(BlockStat.ammo, new AmmoListValue<>(ammoTypes));
|
||||
stats.remove(Stat.itemCapacity);
|
||||
stats.add(Stat.ammo, new AmmoListValue<>(ammoTypes));
|
||||
consumes.add(new ConsumeItemFilter(i -> ammoTypes.containsKey(i)){
|
||||
@Override
|
||||
public void build(Building tile, Table table){
|
||||
@@ -54,7 +54,7 @@ public class ItemTurret extends Turret{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void display(BlockStats stats){
|
||||
public void display(Stats stats){
|
||||
//don't display
|
||||
}
|
||||
});
|
||||
@@ -83,7 +83,7 @@ public class ItemTurret extends Turret{
|
||||
public void displayBars(Table bars){
|
||||
super.displayBars(bars);
|
||||
|
||||
bars.add(new Bar("blocks.ammo", Pal.ammo, () -> (float)totalAmmo / maxAmmo)).growX();
|
||||
bars.add(new Bar("stat.ammo", Pal.ammo, () -> (float)totalAmmo / maxAmmo)).growX();
|
||||
bars.row();
|
||||
}
|
||||
|
||||
|
||||
@@ -33,11 +33,11 @@ public class LaserTurret extends PowerTurret{
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
||||
stats.remove(BlockStat.booster);
|
||||
stats.add(BlockStat.input, new BoosterListValue(reloadTime, consumes.<ConsumeLiquidBase>get(ConsumeType.liquid).amount, coolantMultiplier, false, l -> consumes.liquidfilters.get(l.id)));
|
||||
stats.remove(BlockStat.damage);
|
||||
stats.remove(Stat.booster);
|
||||
stats.add(Stat.input, new BoosterListValue(reloadTime, consumes.<ConsumeLiquidBase>get(ConsumeType.liquid).amount, coolantMultiplier, false, l -> consumes.liquidfilters.get(l.id)));
|
||||
stats.remove(Stat.damage);
|
||||
//damages every 5 ticks, at least in meltdown's case
|
||||
stats.add(BlockStat.damage, shootType.damage * 60f / 5f, StatUnit.perSecond);
|
||||
stats.add(Stat.damage, shootType.damage * 60f / 5f, StatUnit.perSecond);
|
||||
}
|
||||
|
||||
public class LaserTurretBuild extends PowerTurretBuild{
|
||||
|
||||
@@ -36,7 +36,11 @@ public class LiquidTurret extends Turret{
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
||||
stats.add(BlockStat.ammo, new AmmoListValue<>(ammoTypes));
|
||||
stats.add(Stat.ammo, new AmmoListValue<>(ammoTypes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
consumes.add(new ConsumeLiquidFilter(i -> ammoTypes.containsKey(i), 1f){
|
||||
@Override
|
||||
public boolean valid(Building entity){
|
||||
@@ -49,10 +53,12 @@ public class LiquidTurret extends Turret{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void display(BlockStats stats){
|
||||
public void display(Stats stats){
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
super.init();
|
||||
}
|
||||
|
||||
public class LiquidTurretBuild extends TurretBuild{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package mindustry.world.blocks.defense;
|
||||
package mindustry.world.blocks.defense.turrets;
|
||||
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
@@ -11,12 +11,9 @@ import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class PointDefenseTurret extends Block{
|
||||
public class PointDefenseTurret extends ReloadTurret{
|
||||
public final int timerTarget = timers++;
|
||||
public float retargetTime = 5f;
|
||||
|
||||
@@ -27,9 +24,6 @@ public class PointDefenseTurret extends Block{
|
||||
public Effect hitEffect = Fx.pointHit;
|
||||
public Effect shootEffect = Fx.sparkShoot;
|
||||
|
||||
public float range = 80f;
|
||||
public float reloadTime = 30f;
|
||||
public float rotateSpeed = 20;
|
||||
public float shootCone = 5f;
|
||||
public float bulletDamage = 10f;
|
||||
public float shootLength = 3f;
|
||||
@@ -37,13 +31,12 @@ public class PointDefenseTurret extends Block{
|
||||
public PointDefenseTurret(String name){
|
||||
super(name);
|
||||
|
||||
outlineIcon = true;
|
||||
update = true;
|
||||
}
|
||||
rotateSpeed = 20f;
|
||||
reloadTime = 30f;
|
||||
|
||||
@Override
|
||||
public void drawPlace(int x, int y, int rotation, boolean valid){
|
||||
Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.accent);
|
||||
coolantMultiplier = 2f;
|
||||
//disabled due to version mismatch problems
|
||||
acceptCoolant = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,12 +48,10 @@ public class PointDefenseTurret extends Block{
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
||||
stats.add(BlockStat.shootRange, range / tilesize, StatUnit.blocks);
|
||||
stats.add(BlockStat.reload, 60f / reloadTime, StatUnit.none);
|
||||
stats.add(Stat.reload, 60f / reloadTime, StatUnit.none);
|
||||
}
|
||||
|
||||
public class PointDefenseBuild extends Building{
|
||||
public float rotation = 90, reload;
|
||||
public class PointDefenseBuild extends ReloadTurretBuild{
|
||||
public @Nullable Bullet target;
|
||||
|
||||
@Override
|
||||
@@ -76,14 +67,18 @@ public class PointDefenseTurret extends Block{
|
||||
target = null;
|
||||
}
|
||||
|
||||
if(acceptCoolant){
|
||||
updateCooling();
|
||||
}
|
||||
|
||||
//look at target
|
||||
if(target != null && target.within(this, range) && target.team != team && target.type() != null && target.type().hittable){
|
||||
float dest = angleTo(target);
|
||||
rotation = Angles.moveToward(rotation, dest, rotateSpeed * edelta());
|
||||
reload -= edelta();
|
||||
reload += edelta();
|
||||
|
||||
//shoot when possible
|
||||
if(Angles.within(rotation, dest, shootCone) && reload <= 0f){
|
||||
if(Angles.within(rotation, dest, shootCone) && reload >= reloadTime){
|
||||
if(target.damage() > bulletDamage){
|
||||
target.damage(target.damage() - bulletDamage);
|
||||
}else{
|
||||
@@ -95,18 +90,13 @@ public class PointDefenseTurret extends Block{
|
||||
beamEffect.at(x + Tmp.v1.x, y + Tmp.v1.y, rotation, color, new Vec2().set(target));
|
||||
shootEffect.at(x + Tmp.v1.x, y + Tmp.v1.y, rotation, color);
|
||||
hitEffect.at(target.x, target.y, color);
|
||||
reload = reloadTime;
|
||||
reload = 0;
|
||||
}
|
||||
}else{
|
||||
target = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawSelect(){
|
||||
Drawf.dashCircle(x, y, range, Pal.accent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
Draw.rect(baseRegion, x, y);
|
||||
@@ -16,7 +16,7 @@ public class PowerTurret extends Turret{
|
||||
@Override
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
stats.add(BlockStat.damage, shootType.damage, StatUnit.none);
|
||||
stats.add(Stat.damage, shootType.damage, StatUnit.none);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package mindustry.world.blocks.defense.turrets;
|
||||
|
||||
import arc.math.*;
|
||||
import arc.util.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.consumers.*;
|
||||
import mindustry.world.meta.*;
|
||||
import mindustry.world.meta.values.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public abstract class ReloadTurret extends BaseTurret{
|
||||
public float reloadTime = 10f;
|
||||
|
||||
public ReloadTurret(String name){
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
||||
if(acceptCoolant){
|
||||
stats.add(Stat.booster, new BoosterListValue(reloadTime, consumes.<ConsumeLiquidBase>get(ConsumeType.liquid).amount, coolantMultiplier, true, l -> consumes.liquidfilters.get(l.id)));
|
||||
}
|
||||
}
|
||||
|
||||
public class ReloadTurretBuild extends BaseTurretBuild{
|
||||
public float reload;
|
||||
|
||||
protected void updateCooling(){
|
||||
float maxUsed = consumes.<ConsumeLiquidBase>get(ConsumeType.liquid).amount;
|
||||
|
||||
Liquid liquid = liquids.current();
|
||||
|
||||
float used = Math.min(Math.min(liquids.get(liquid), maxUsed * Time.delta), Math.max(0, ((reloadTime - reload) / coolantMultiplier) / liquid.heatCapacity)) * baseReloadSpeed();
|
||||
reload += used * liquid.heatCapacity * coolantMultiplier;
|
||||
liquids.remove(liquid, used);
|
||||
|
||||
if(Mathf.chance(0.06 * used)){
|
||||
coolEffect.at(x + Mathf.range(size * tilesize / 2f), y + Mathf.range(size * tilesize / 2f));
|
||||
}
|
||||
}
|
||||
|
||||
protected float baseReloadSpeed(){
|
||||
return efficiency();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package mindustry.world.blocks.defense;
|
||||
package mindustry.world.blocks.defense.turrets;
|
||||
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
@@ -9,12 +9,13 @@ import mindustry.annotations.Annotations.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.consumers.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class TractorBeamTurret extends Block{
|
||||
public class TractorBeamTurret extends BaseTurret{
|
||||
public final int timerTarget = timers++;
|
||||
public float retargetTime = 5f;
|
||||
|
||||
@@ -22,8 +23,6 @@ public class TractorBeamTurret extends Block{
|
||||
public @Load("@-laser") TextureRegion laser;
|
||||
public @Load("@-laser-end") TextureRegion laserEnd;
|
||||
|
||||
public float range = 80f;
|
||||
public float rotateSpeed = 10;
|
||||
public float shootCone = 6f;
|
||||
public float laserWidth = 0.6f;
|
||||
public float force = 0.3f;
|
||||
@@ -35,14 +34,11 @@ public class TractorBeamTurret extends Block{
|
||||
public TractorBeamTurret(String name){
|
||||
super(name);
|
||||
|
||||
update = true;
|
||||
solid = true;
|
||||
outlineIcon = true;
|
||||
}
|
||||
rotateSpeed = 10f;
|
||||
coolantMultiplier = 1f;
|
||||
|
||||
@Override
|
||||
public void drawPlace(int x, int y, int rotation, boolean valid){
|
||||
Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.accent);
|
||||
//disabled due to version mismatch problems
|
||||
acceptCoolant = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -54,17 +50,16 @@ public class TractorBeamTurret extends Block{
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
||||
stats.add(BlockStat.shootRange, range / tilesize, StatUnit.blocks);
|
||||
stats.add(BlockStat.targetsAir, targetAir);
|
||||
stats.add(BlockStat.targetsGround, targetGround);
|
||||
stats.add(BlockStat.damage, damage * 60f, StatUnit.perSecond);
|
||||
stats.add(Stat.targetsAir, targetAir);
|
||||
stats.add(Stat.targetsGround, targetGround);
|
||||
stats.add(Stat.damage, damage * 60f, StatUnit.perSecond);
|
||||
}
|
||||
|
||||
public class TractorBeamBuild extends Building{
|
||||
public float rotation = 90;
|
||||
public class TractorBeamBuild extends BaseTurretBuild{
|
||||
public @Nullable Unit target;
|
||||
public float lastX, lastY, strength;
|
||||
public boolean any;
|
||||
public float coolant = 1f;
|
||||
|
||||
@Override
|
||||
public void updateTile(){
|
||||
@@ -74,6 +69,23 @@ public class TractorBeamTurret extends Block{
|
||||
target = Units.closestEnemy(team, x, y, range, u -> u.checkTarget(targetAir, targetGround));
|
||||
}
|
||||
|
||||
//consume coolant
|
||||
if(target != null && acceptCoolant){
|
||||
float maxUsed = consumes.<ConsumeLiquidBase>get(ConsumeType.liquid).amount;
|
||||
|
||||
Liquid liquid = liquids.current();
|
||||
|
||||
float used = Math.min(Math.min(liquids.get(liquid), maxUsed * Time.delta), Math.max(0, (1f / coolantMultiplier) / liquid.heatCapacity));
|
||||
|
||||
liquids.remove(liquid, used);
|
||||
|
||||
if(Mathf.chance(0.06 * used)){
|
||||
coolEffect.at(x + Mathf.range(size * tilesize / 2f), y + Mathf.range(size * tilesize / 2f));
|
||||
}
|
||||
|
||||
coolant = 1f + (used * liquid.heatCapacity * coolantMultiplier);
|
||||
}
|
||||
|
||||
//look at target
|
||||
if(target != null && target.within(this, range) && target.team() != team && target.type.flying && efficiency() > 0.01f){
|
||||
any = true;
|
||||
@@ -98,8 +110,8 @@ public class TractorBeamTurret extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawSelect(){
|
||||
Drawf.dashCircle(x, y, range, Pal.accent);
|
||||
public float efficiency() {
|
||||
return super.efficiency() * coolant;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -21,15 +21,13 @@ import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.logic.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.*;
|
||||
import mindustry.world.consumers.*;
|
||||
import mindustry.world.meta.*;
|
||||
import mindustry.world.meta.values.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public abstract class Turret extends Block{
|
||||
public abstract class Turret extends ReloadTurret{
|
||||
//after being logic-controlled and this amount of time passes, the turret will resume normal AI
|
||||
public final static float logicControlCooldown = 60 * 2;
|
||||
|
||||
@@ -45,8 +43,6 @@ public abstract class Turret extends Block{
|
||||
public int maxAmmo = 30;
|
||||
public int ammoPerShot = 1;
|
||||
public float ammoEjectBack = 1f;
|
||||
public float range = 50f;
|
||||
public float reloadTime = 10f;
|
||||
public float inaccuracy = 0f;
|
||||
public float velocityInaccuracy = 0f;
|
||||
public int shots = 1;
|
||||
@@ -54,7 +50,6 @@ public abstract class Turret extends Block{
|
||||
public float recoilAmount = 1f;
|
||||
public float restitution = 0.02f;
|
||||
public float cooldown = 0.02f;
|
||||
public float rotateSpeed = 5f; //in degrees per tick
|
||||
public float shootCone = 8f;
|
||||
public float shootShake = 0f;
|
||||
public float xRand = 0f;
|
||||
@@ -64,11 +59,7 @@ public abstract class Turret extends Block{
|
||||
public boolean alternate = false;
|
||||
public boolean targetAir = true;
|
||||
public boolean targetGround = true;
|
||||
public boolean acceptCoolant = true;
|
||||
/** How much reload is lowered by for each unit of liquid of heat capacity. */
|
||||
public float coolantMultiplier = 5f;
|
||||
/** Effect displayed when coolant is used. */
|
||||
public Effect coolEffect = Fx.fuelburn;
|
||||
|
||||
public Sortf unitSort = Unit::dst2;
|
||||
|
||||
protected Vec2 tr = new Vec2();
|
||||
@@ -108,15 +99,10 @@ public abstract class Turret extends Block{
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
||||
stats.add(BlockStat.shootRange, range / tilesize, StatUnit.blocks);
|
||||
stats.add(BlockStat.inaccuracy, (int)inaccuracy, StatUnit.degrees);
|
||||
stats.add(BlockStat.reload, 60f / reloadTime * shots, StatUnit.none);
|
||||
stats.add(BlockStat.targetsAir, targetAir);
|
||||
stats.add(BlockStat.targetsGround, targetGround);
|
||||
|
||||
if(acceptCoolant){
|
||||
stats.add(BlockStat.booster, new BoosterListValue(reloadTime, consumes.<ConsumeLiquidBase>get(ConsumeType.liquid).amount, coolantMultiplier, true, l -> consumes.liquidfilters.get(l.id)));
|
||||
}
|
||||
stats.add(Stat.inaccuracy, (int)inaccuracy, StatUnit.degrees);
|
||||
stats.add(Stat.reload, 60f / reloadTime * shots, StatUnit.none);
|
||||
stats.add(Stat.targetsAir, targetAir);
|
||||
stats.add(Stat.targetsGround, targetGround);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -134,32 +120,22 @@ public abstract class Turret extends Block{
|
||||
return new TextureRegion[]{baseRegion, region};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawPlace(int x, int y, int rotation, boolean valid){
|
||||
Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.placing);
|
||||
}
|
||||
|
||||
public static abstract class AmmoEntry{
|
||||
public int amount;
|
||||
|
||||
public abstract BulletType type();
|
||||
}
|
||||
|
||||
public class TurretBuild extends Building implements ControlBlock, Ranged{
|
||||
public class TurretBuild extends ReloadTurretBuild implements ControlBlock{
|
||||
public Seq<AmmoEntry> ammo = new Seq<>();
|
||||
public int totalAmmo;
|
||||
public float reload, rotation = 90, recoil, heat, logicControlTime = -1;
|
||||
public float recoil, heat, logicControlTime = -1;
|
||||
public int shotCounter;
|
||||
public boolean logicShooting = false;
|
||||
public @Nullable Posc target;
|
||||
public Vec2 targetPos = new Vec2();
|
||||
public BlockUnitc unit = Nulls.blockUnit;
|
||||
|
||||
@Override
|
||||
public float range(){
|
||||
return range;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void created(){
|
||||
unit = (BlockUnitc)UnitTypes.block.create(team);
|
||||
@@ -197,8 +173,8 @@ public abstract class Turret extends Block{
|
||||
case ammo -> totalAmmo;
|
||||
case ammoCapacity -> maxAmmo;
|
||||
case rotation -> rotation;
|
||||
case shootX -> targetPos.x;
|
||||
case shootY -> targetPos.y;
|
||||
case shootX -> World.conv(targetPos.x);
|
||||
case shootY -> World.conv(targetPos.y);
|
||||
case shooting -> (isControlled() ? unit.isShooting() : logicControlled() ? logicShooting : validateTarget()) ? 1 : 0;
|
||||
default -> super.sense(sensor);
|
||||
};
|
||||
@@ -301,11 +277,6 @@ public abstract class Turret extends Block{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawSelect(){
|
||||
Drawf.dashCircle(x, y, range, team.color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleLiquid(Building source, Liquid liquid, float amount){
|
||||
if(acceptCoolant && liquids.currentAmount() <= 0.001f){
|
||||
@@ -315,20 +286,6 @@ public abstract class Turret extends Block{
|
||||
super.handleLiquid(source, liquid, amount);
|
||||
}
|
||||
|
||||
protected void updateCooling(){
|
||||
float maxUsed = consumes.<ConsumeLiquidBase>get(ConsumeType.liquid).amount;
|
||||
|
||||
Liquid liquid = liquids.current();
|
||||
|
||||
float used = Math.min(Math.min(liquids.get(liquid), maxUsed * Time.delta), Math.max(0, ((reloadTime - reload) / coolantMultiplier) / liquid.heatCapacity)) * baseReloadSpeed();
|
||||
reload += used * liquid.heatCapacity * coolantMultiplier;
|
||||
liquids.remove(liquid, used);
|
||||
|
||||
if(Mathf.chance(0.06 * used)){
|
||||
coolEffect.at(x + Mathf.range(size * tilesize / 2f), y + Mathf.range(size * tilesize / 2f));
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean validateTarget(){
|
||||
return !Units.invalidateTarget(target, team, x, y) || isControlled() || logicControlled();
|
||||
}
|
||||
@@ -453,10 +410,6 @@ public abstract class Turret extends Block{
|
||||
ammoUseEffect.at(x - Angles.trnsx(rotation, ammoEjectBack), y - Angles.trnsy(rotation, ammoEjectBack), rotation);
|
||||
}
|
||||
|
||||
protected float baseReloadSpeed(){
|
||||
return efficiency();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Writes write){
|
||||
super.write(write);
|
||||
|
||||
@@ -52,7 +52,7 @@ public class Conveyor extends Block implements Autotiler{
|
||||
super.setStats();
|
||||
|
||||
//have to add a custom calculated speed, since the actual movement speed is apparently not linear
|
||||
stats.add(BlockStat.itemsMoved, displayedSpeed, StatUnit.itemsSecond);
|
||||
stats.add(Stat.itemsMoved, displayedSpeed, StatUnit.itemsSecond);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -202,7 +202,7 @@ public class ItemBridge extends Block{
|
||||
|
||||
for(int i = 1; i <= range; i++){
|
||||
for(int j = 0; j < 4; j++){
|
||||
Tile other = tile.getNearby(Geometry.d4[j].x * i, Geometry.d4[j].y * i);
|
||||
Tile other = tile.nearby(Geometry.d4[j].x * i, Geometry.d4[j].y * i);
|
||||
if(linkValid(tile, other)){
|
||||
boolean linked = other.pos() == link;
|
||||
|
||||
@@ -336,16 +336,18 @@ public class ItemBridge extends Block{
|
||||
|
||||
Tile other = world.tile(link);
|
||||
|
||||
if(items.total() >= itemCapacity) return false;
|
||||
|
||||
if(linked(source)) return true;
|
||||
|
||||
if(linkValid(tile, other)){
|
||||
int rel = relativeTo(other);
|
||||
int rel2 = relativeTo(Edges.getFacingEdge(source, this));
|
||||
|
||||
if(rel == rel2) return false;
|
||||
}else{
|
||||
return linked(source) && items.total() < itemCapacity;
|
||||
return rel != rel2;
|
||||
}
|
||||
|
||||
return items.total() < itemCapacity;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -359,16 +361,18 @@ public class ItemBridge extends Block{
|
||||
|
||||
Tile other = world.tile(link);
|
||||
|
||||
if(!(liquids.current() == liquid || liquids.get(liquids.current()) < 0.2f)) return false;
|
||||
|
||||
if(linked(source)) return true;
|
||||
|
||||
if(linkValid(tile, other)){
|
||||
int rel = relativeTo(other.x, other.y);
|
||||
int rel2 = relativeTo(Edges.getFacingEdge(source, this));
|
||||
|
||||
if(rel == rel2) return false;
|
||||
}else if(!(linked(source))){
|
||||
return false;
|
||||
return rel != rel2;
|
||||
}
|
||||
|
||||
return (liquids.current() == liquid || liquids.get(liquids.current()) < 0.2f);
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean linked(Building source){
|
||||
|
||||
@@ -87,7 +87,7 @@ public class PayloadConveyor extends Block{
|
||||
}
|
||||
|
||||
int ntrns = 1 + size/2;
|
||||
Tile next = tile.getNearby(Geometry.d4(rotation).x * ntrns, Geometry.d4(rotation).y * ntrns);
|
||||
Tile next = tile.nearby(Geometry.d4(rotation).x * ntrns, Geometry.d4(rotation).y * ntrns);
|
||||
blocked = (next != null && next.solid() && !next.block().outputsPayload) || (this.next != null && (this.next.rotation + 2)%4 == rotation);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package mindustry.world.blocks.distribution;
|
||||
|
||||
import arc.math.*;
|
||||
import arc.util.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
public class Router extends Block{
|
||||
@@ -20,10 +23,30 @@ public class Router extends Block{
|
||||
noUpdateDisabled = true;
|
||||
}
|
||||
|
||||
public class RouterBuild extends Building{
|
||||
public class RouterBuild extends Building implements ControlBlock{
|
||||
public Item lastItem;
|
||||
public Tile lastInput;
|
||||
public float time;
|
||||
public @Nullable BlockUnitc unit;
|
||||
|
||||
@Override
|
||||
public Unit unit(){
|
||||
if(unit == null){
|
||||
unit = (BlockUnitc)UnitTypes.block.create(team);
|
||||
unit.tile(this);
|
||||
}
|
||||
return (Unit)unit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canControl(){
|
||||
return size == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldAutoTarget(){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTile(){
|
||||
@@ -72,6 +95,23 @@ public class Router extends Block{
|
||||
}
|
||||
|
||||
public Building getTileTarget(Item item, Tile from, boolean set){
|
||||
if(unit != null && isControlled()){
|
||||
unit.health(health);
|
||||
unit.ammo(unit.type().ammoCapacity * (items.total() > 0 ? 1f : 0f));
|
||||
unit.team(team);
|
||||
|
||||
int angle = Mathf.mod((int)((angleTo(unit.aimX(), unit.aimY()) + 45) / 90), 4);
|
||||
|
||||
if(unit.isShooting()){
|
||||
Building other = nearby(angle);
|
||||
if(other != null && other.acceptItem(this, item)){
|
||||
return other;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
int counter = rotation;
|
||||
for(int i = 0; i < proximity.size; i++){
|
||||
Building other = proximity.get((i + counter) % proximity.size);
|
||||
|
||||
@@ -53,7 +53,7 @@ public class StackConveyor extends Block implements Autotiler{
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
||||
stats.add(BlockStat.itemsMoved, Mathf.round(itemCapacity * speed * 60), StatUnit.itemsSecond);
|
||||
stats.add(Stat.itemsMoved, Mathf.round(itemCapacity * speed * 60), StatUnit.itemsSecond);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -183,7 +183,7 @@ public class Floor extends Block{
|
||||
|
||||
for(int i = 0; i < 8; i++){
|
||||
Point2 point = Geometry.d8[i];
|
||||
Tile other = tile.getNearby(point);
|
||||
Tile other = tile.nearby(point);
|
||||
if(other != null && other.floor().cacheLayer == layer && other.floor().edges() != null){
|
||||
if(!blended.getAndSet(other.floor().id)){
|
||||
blenders.add(other.floor());
|
||||
@@ -200,7 +200,7 @@ public class Floor extends Block{
|
||||
|
||||
for(int i = 0; i < 8; i++){
|
||||
Point2 point = Geometry.d8[i];
|
||||
Tile other = tile.getNearby(point);
|
||||
Tile other = tile.nearby(point);
|
||||
if(other != null && doEdge(other.floor()) && other.floor().cacheLayer == cacheLayer && other.floor().edges() != null){
|
||||
if(!blended.getAndSet(other.floor().id)){
|
||||
blenders.add(other.floor());
|
||||
@@ -217,7 +217,7 @@ public class Floor extends Block{
|
||||
for(Block block : blenders){
|
||||
for(int i = 0; i < 8; i++){
|
||||
Point2 point = Geometry.d8[i];
|
||||
Tile other = tile.getNearby(point);
|
||||
Tile other = tile.nearby(point);
|
||||
if(other != null && other.floor() == block){
|
||||
TextureRegion region = edge((Floor)block, 1 - point.x, 1 - point.y);
|
||||
Draw.rect(region, tile.worldx(), tile.worldy());
|
||||
@@ -229,7 +229,7 @@ public class Floor extends Block{
|
||||
//'new' style of edges with shadows instead of colors, not used currently
|
||||
protected void drawEdgesFlat(Tile tile, boolean sameLayer){
|
||||
for(int i = 0; i < 4; i++){
|
||||
Tile other = tile.getNearby(i);
|
||||
Tile other = tile.nearby(i);
|
||||
if(other != null && doEdge(other.floor())){
|
||||
Color color = other.floor().mapColor;
|
||||
Draw.color(color.r, color.g, color.b, 1f);
|
||||
|
||||
@@ -21,7 +21,7 @@ public class StaticTree extends StaticWall{
|
||||
float oy = 0;
|
||||
|
||||
for(int i = 0; i < 4; i++){
|
||||
if(tile.getNearby(i) != null && tile.getNearby(i).block() instanceof StaticWall){
|
||||
if(tile.nearby(i) != null && tile.nearby(i).block() instanceof StaticWall){
|
||||
|
||||
if(i == 0){
|
||||
r.setWidth(r.width - crop);
|
||||
|
||||
@@ -99,7 +99,7 @@ public class BlockForge extends PayloadAcceptor{
|
||||
public void buildConfiguration(Table table){
|
||||
Seq<Block> blocks = Vars.content.blocks().select(b -> b.isVisible() && b.size <= 2);
|
||||
|
||||
ItemSelection.buildTable(table, blocks, () -> recipe, block -> recipe = block);
|
||||
ItemSelection.buildTable(table, blocks, () -> recipe, this::configure);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -14,7 +14,7 @@ public class LiquidJunction extends LiquidBlock{
|
||||
@Override
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
stats.remove(BlockStat.liquidCapacity);
|
||||
stats.remove(Stat.liquidCapacity);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -117,8 +117,8 @@ public class LogicBlock extends Block{
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
||||
stats.add(BlockStat.linkRange, range / 8, StatUnit.blocks);
|
||||
stats.add(BlockStat.instructions, instructionsPerTick * 60, StatUnit.perSecond);
|
||||
stats.add(Stat.linkRange, range / 8, StatUnit.blocks);
|
||||
stats.add(Stat.instructions, instructionsPerTick * 60, StatUnit.perSecond);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -279,10 +279,13 @@ public class LogicBlock extends Block{
|
||||
|
||||
//store link objects
|
||||
executor.links = new Building[links.count(l -> l.valid && l.active)];
|
||||
executor.linkIds.clear();
|
||||
int index = 0;
|
||||
for(LogicLink link : links){
|
||||
if(link.active && link.valid){
|
||||
executor.links[index ++] = world.build(link.x, link.y);
|
||||
Building build = world.build(link.x, link.y);
|
||||
executor.links[index ++] = build;
|
||||
if(build != null) executor.linkIds.add(build.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ public class LogicDisplay extends Block{
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
||||
stats.add(BlockStat.displaySize, "@x@", displaySize, displaySize);
|
||||
stats.add(Stat.displaySize, "@x@", displaySize, displaySize);
|
||||
}
|
||||
|
||||
public class LogicDisplayBuild extends Building{
|
||||
|
||||
@@ -18,7 +18,7 @@ public class MemoryBlock extends Block{
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
||||
stats.add(BlockStat.memoryCapacity, memoryCapacity, StatUnit.none);
|
||||
stats.add(Stat.memoryCapacity, memoryCapacity, StatUnit.none);
|
||||
}
|
||||
|
||||
public class MemoryBuild extends Building{
|
||||
|
||||
@@ -20,7 +20,7 @@ public class Battery extends PowerDistributor{
|
||||
super(name);
|
||||
outputsPower = true;
|
||||
consumesPower = true;
|
||||
flags = EnumSet.of(BlockFlag.powerRes);
|
||||
flags = EnumSet.of(BlockFlag.battery);
|
||||
}
|
||||
|
||||
public class BatteryBuild extends Building{
|
||||
|
||||
@@ -55,7 +55,7 @@ public class ImpactReactor extends PowerGenerator{
|
||||
super.setStats();
|
||||
|
||||
if(hasItems){
|
||||
stats.add(BlockStat.productionTime, itemDuration / 60f, StatUnit.seconds);
|
||||
stats.add(Stat.productionTime, itemDuration / 60f, StatUnit.seconds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ public class ItemLiquidGenerator extends PowerGenerator{
|
||||
super.setStats();
|
||||
|
||||
if(hasItems){
|
||||
stats.add(BlockStat.productionTime, itemDuration / 60f, StatUnit.seconds);
|
||||
stats.add(Stat.productionTime, itemDuration / 60f, StatUnit.seconds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.io.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
@@ -47,6 +48,7 @@ public class NuclearReactor extends PowerGenerator{
|
||||
hasItems = true;
|
||||
hasLiquids = true;
|
||||
rebuildable = false;
|
||||
flags = EnumSet.of(BlockFlag.reactor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -54,7 +56,7 @@ public class NuclearReactor extends PowerGenerator{
|
||||
super.setStats();
|
||||
|
||||
if(hasItems){
|
||||
stats.add(BlockStat.productionTime, itemDuration / 60f, StatUnit.seconds);
|
||||
stats.add(Stat.productionTime, itemDuration / 60f, StatUnit.seconds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,13 +12,13 @@ import mindustry.world.meta.*;
|
||||
public class PowerGenerator extends PowerDistributor{
|
||||
/** The amount of power produced per tick in case of an efficiency of 1.0, which represents 100%. */
|
||||
public float powerProduction;
|
||||
public BlockStat generationType = BlockStat.basePowerGeneration;
|
||||
public Stat generationType = Stat.basePowerGeneration;
|
||||
|
||||
public PowerGenerator(String name){
|
||||
super(name);
|
||||
sync = true;
|
||||
baseExplosiveness = 5f;
|
||||
flags = EnumSet.of(BlockFlag.producer);
|
||||
flags = EnumSet.of(BlockFlag.generator);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user