Merge branch 'master' of https://github.com/Anuken/Mindustry into 7.0-features
Conflicts: core/src/mindustry/content/Blocks.java
This commit is contained in:
@@ -73,7 +73,8 @@ public class Vars implements Loadable{
|
||||
/** URL to the JSON file containing all the BE servers. Only queried in BE. */
|
||||
public static final String serverJsonBeURL = "https://raw.githubusercontent.com/Anuken/Mindustry/master/servers_be.json";
|
||||
/** URL to the JSON file containing all the stable servers. */
|
||||
public static final String serverJsonURL = "https://raw.githubusercontent.com/Anuken/Mindustry/master/servers_v6.json";
|
||||
//TODO this uses BE servers until full v7 release, there's no point in displaying v6 at all
|
||||
public static final String serverJsonURL = "https://raw.githubusercontent.com/Anuken/Mindustry/master/servers_be.json";
|
||||
/** URL of the github issue report template.*/
|
||||
public static final String reportIssueURL = "https://github.com/Anuken/Mindustry/issues/new?labels=bug&template=bug_report.md";
|
||||
/** list of built-in servers.*/
|
||||
|
||||
@@ -15,7 +15,7 @@ import static mindustry.Vars.*;
|
||||
|
||||
public class LogicAI extends AIController{
|
||||
/** Minimum delay between item transfers. */
|
||||
public static final float transferDelay = 60f * 2f;
|
||||
public static final float transferDelay = 60f * 1.5f;
|
||||
/** Time after which the unit resets its controlled and reverts to a normal unit. */
|
||||
public static final float logicControlTimeout = 10f * 60f;
|
||||
|
||||
|
||||
@@ -1168,22 +1168,24 @@ public class Blocks implements ContentList{
|
||||
reloadTime = 200f;
|
||||
range = 440f;
|
||||
consumes.power(1.75f);
|
||||
bullet = new MassDriverBolt();
|
||||
}};
|
||||
|
||||
//special transport blocks
|
||||
|
||||
duct = new Duct("duct"){{
|
||||
requirements(Category.distribution, with(Items.graphite, 5, Items.copper, 5));
|
||||
speed = 5f;
|
||||
requirements(Category.distribution, with(Items.graphite, 5, Items.metaglass, 2));
|
||||
speed = 4f;
|
||||
}};
|
||||
|
||||
ductRouter = new DuctRouter("duct-router"){{
|
||||
requirements(Category.distribution, with(Items.graphite, 10, Items.copper, 5));
|
||||
speed = 5f;
|
||||
requirements(Category.distribution, with(Items.graphite, 10, Items.metaglass, 4));
|
||||
speed = 4f;
|
||||
}};
|
||||
|
||||
ductBridge = new DuctBridge("duct-bridge"){{
|
||||
requirements(Category.distribution, with(Items.graphite, 20, Items.copper, 15));
|
||||
requirements(Category.distribution, with(Items.graphite, 20, Items.metaglass, 8));
|
||||
speed = 4f;
|
||||
}};
|
||||
|
||||
//endregion
|
||||
@@ -2048,7 +2050,7 @@ public class Blocks implements ContentList{
|
||||
requirements(Category.units, with(Items.copper, 150, Items.lead, 130, Items.metaglass, 120));
|
||||
plans = Seq.with(
|
||||
new UnitPlan(UnitTypes.risso, 60f * 45f, with(Items.silicon, 20, Items.metaglass, 35)),
|
||||
new UnitPlan(UnitTypes.retusa, 60f * 60f, with(Items.silicon, 15, Items.metaglass, 25, Items.titanium, 20))
|
||||
new UnitPlan(UnitTypes.retusa, 60f * 50f, with(Items.silicon, 15, Items.metaglass, 25, Items.titanium, 20))
|
||||
);
|
||||
size = 3;
|
||||
consumes.power(1.2f);
|
||||
@@ -2090,7 +2092,8 @@ public class Blocks implements ContentList{
|
||||
new UnitType[]{UnitTypes.poly, UnitTypes.mega},
|
||||
new UnitType[]{UnitTypes.minke, UnitTypes.bryde},
|
||||
new UnitType[]{UnitTypes.pulsar, UnitTypes.quasar},
|
||||
new UnitType[]{UnitTypes.atrax, UnitTypes.spiroct}
|
||||
new UnitType[]{UnitTypes.atrax, UnitTypes.spiroct},
|
||||
new UnitType[]{UnitTypes.oxynoe, UnitTypes.cyerce}
|
||||
);
|
||||
}};
|
||||
|
||||
@@ -2111,7 +2114,8 @@ public class Blocks implements ContentList{
|
||||
new UnitType[]{UnitTypes.fortress, UnitTypes.scepter},
|
||||
new UnitType[]{UnitTypes.bryde, UnitTypes.sei},
|
||||
new UnitType[]{UnitTypes.mega, UnitTypes.quad},
|
||||
new UnitType[]{UnitTypes.quasar, UnitTypes.vela}
|
||||
new UnitType[]{UnitTypes.quasar, UnitTypes.vela},
|
||||
new UnitType[]{UnitTypes.cyerce, UnitTypes.aegires}
|
||||
);
|
||||
}};
|
||||
|
||||
@@ -2132,7 +2136,8 @@ public class Blocks implements ContentList{
|
||||
new UnitType[]{UnitTypes.scepter, UnitTypes.reign},
|
||||
new UnitType[]{UnitTypes.sei, UnitTypes.omura},
|
||||
new UnitType[]{UnitTypes.quad, UnitTypes.oct},
|
||||
new UnitType[]{UnitTypes.vela, UnitTypes.corvus}
|
||||
new UnitType[]{UnitTypes.vela, UnitTypes.corvus},
|
||||
new UnitType[]{UnitTypes.aegires, UnitTypes.navanax}
|
||||
);
|
||||
}};
|
||||
|
||||
@@ -2149,7 +2154,7 @@ public class Blocks implements ContentList{
|
||||
requirements(Category.units, with(Items.silicon, 70, Items.thorium, 60, Items.plastanium, 60));
|
||||
size = 2;
|
||||
length = 6f;
|
||||
repairSpeed = 5f;
|
||||
repairSpeed = 4f;
|
||||
repairRadius = 140f;
|
||||
powerUse = 5f;
|
||||
beamWidth = 1.1f;
|
||||
|
||||
@@ -36,7 +36,7 @@ public class Bullets implements ContentList{
|
||||
waterShot, cryoShot, slagShot, oilShot, heavyWaterShot, heavyCryoShot, heavySlagShot, heavyOilShot,
|
||||
|
||||
//environment, misc.
|
||||
damageLightning, damageLightningGround, fireball, basicFlame, pyraFlame, driverBolt;
|
||||
damageLightning, damageLightningGround, fireball, basicFlame, pyraFlame;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
@@ -510,7 +510,5 @@ public class Bullets implements ContentList{
|
||||
statusDuration = 60f * 4f;
|
||||
damage = 0.2f;
|
||||
}};
|
||||
|
||||
driverBolt = new MassDriverBolt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -855,6 +855,7 @@ public class Fx{
|
||||
if(Fire.regions[0] == null) return;
|
||||
alpha(e.fout());
|
||||
rect(Fire.regions[((int)(e.rotation + e.fin() * Fire.frames)) % Fire.frames], e.x, e.y);
|
||||
Drawf.light(e.x, e.y, 50f + Mathf.absin(5f, 5f), Pal.lightFlame, 0.6f * e.fout());
|
||||
}),
|
||||
|
||||
fire = new Effect(50f, e -> {
|
||||
@@ -962,7 +963,7 @@ public class Fx{
|
||||
}),
|
||||
|
||||
overdriven = new Effect(20f, e -> {
|
||||
color(Pal.accent);
|
||||
color(e.color);
|
||||
|
||||
randLenVectors(e.id, 2, 1f + e.fin() * 2f, (x, y) -> {
|
||||
Fill.square(e.x + x, e.y + y, e.fout() * 2.3f + 0.5f);
|
||||
@@ -970,7 +971,7 @@ public class Fx{
|
||||
}),
|
||||
|
||||
overclocked = new Effect(50f, e -> {
|
||||
color(Pal.accent);
|
||||
color(e.color);
|
||||
|
||||
Fill.square(e.x, e.y, e.fslope() * 2f, 45f);
|
||||
}),
|
||||
|
||||
@@ -53,7 +53,9 @@ public class TechTree implements ContentList{
|
||||
node(titaniumConveyor, Seq.with(new SectorComplete(craters)), () -> {
|
||||
node(phaseConveyor, () -> {
|
||||
node(massDriver, () -> {
|
||||
node(payloadPropulsionTower, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -233,7 +235,9 @@ public class TechTree implements ContentList{
|
||||
});
|
||||
|
||||
node(repairPoint, () -> {
|
||||
node(repairTurret, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -416,6 +420,18 @@ public class TechTree implements ContentList{
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(retusa, () -> {
|
||||
node(oxynoe, () -> {
|
||||
node(cyerce, () -> {
|
||||
node(aegires, () -> {
|
||||
node(navanax, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1375,7 +1375,7 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
shrinkX = shrinkY = 0.7f;
|
||||
|
||||
speed = 0.001f;
|
||||
speed = 0f;
|
||||
collides = false;
|
||||
|
||||
healPercent = 15f;
|
||||
@@ -1759,7 +1759,7 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
armor = 3f;
|
||||
|
||||
buildSpeed = 2f;
|
||||
buildSpeed = 1.5f;
|
||||
|
||||
weapons.add(new RepairBeamWeapon("repair-beam-weapon-center"){{
|
||||
x = 0f;
|
||||
@@ -1810,7 +1810,7 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
shrinkX = shrinkY = 0f;
|
||||
|
||||
speed = 0.001f;
|
||||
speed = 0f;
|
||||
|
||||
splashDamage = 50f;
|
||||
splashDamageRadius = 40f;
|
||||
@@ -1833,7 +1833,7 @@ public class UnitTypes implements ContentList{
|
||||
trailY = -4f;
|
||||
trailScl = 1.9f;
|
||||
|
||||
buildSpeed = 2.5f;
|
||||
buildSpeed = 2f;
|
||||
|
||||
weapons.add(new Weapon("plasma-mount-weapon"){{
|
||||
|
||||
@@ -1906,7 +1906,7 @@ public class UnitTypes implements ContentList{
|
||||
trailY = -9f;
|
||||
trailScl = 2f;
|
||||
|
||||
buildSpeed = 3f;
|
||||
buildSpeed = 2f;
|
||||
|
||||
weapons.add(new RepairBeamWeapon("repair-beam-weapon-center"){{
|
||||
x = 11f;
|
||||
@@ -1936,7 +1936,6 @@ public class UnitTypes implements ContentList{
|
||||
ejectEffect = Fx.none;
|
||||
bullet = new FlakBulletType(2.5f, 25){{
|
||||
sprite = "missile-large";
|
||||
collides = false;
|
||||
//for targeting
|
||||
collidesGround = collidesAir = true;
|
||||
explodeRange = 40f;
|
||||
@@ -1950,9 +1949,9 @@ public class UnitTypes implements ContentList{
|
||||
lightColor = Pal.heal;
|
||||
|
||||
splashDamageRadius = 30f;
|
||||
splashDamage = 28f;
|
||||
splashDamage = 25f;
|
||||
|
||||
lifetime = 90f;
|
||||
lifetime = 80f;
|
||||
backColor = Pal.heal;
|
||||
frontColor = Color.white;
|
||||
|
||||
@@ -1976,17 +1975,17 @@ public class UnitTypes implements ContentList{
|
||||
weaveMag = 1f;
|
||||
|
||||
trailColor = Pal.heal;
|
||||
trailParam = 5f;
|
||||
trailInterval = 3f;
|
||||
trailWidth = 4.5f;
|
||||
trailLength = 29;
|
||||
|
||||
fragBullets = 7;
|
||||
fragVelocityMin = 0.3f;
|
||||
|
||||
fragBullet = new MissileBulletType(3.9f, 12){{
|
||||
fragBullet = new MissileBulletType(3.9f, 11){{
|
||||
homingPower = 0.2f;
|
||||
weaveMag = 4;
|
||||
weaveScale = 4;
|
||||
lifetime = 70f;
|
||||
lifetime = 60f;
|
||||
shootEffect = Fx.shootHeal;
|
||||
smokeEffect = Fx.hitLaser;
|
||||
splashDamage = 13f;
|
||||
@@ -1998,12 +1997,14 @@ public class UnitTypes implements ContentList{
|
||||
lightRadius = 40f;
|
||||
lightOpacity = 0.7f;
|
||||
|
||||
trailInterval = 2f;
|
||||
trailParam = 3f;
|
||||
trailColor = Pal.heal;
|
||||
trailWidth = 2.5f;
|
||||
trailLength = 20;
|
||||
trailChance = -1f;
|
||||
|
||||
healPercent = 2.8f;
|
||||
collidesTeam = true;
|
||||
backColor = Pal.heal;
|
||||
trailColor = Pal.heal;
|
||||
|
||||
despawnEffect = Fx.none;
|
||||
hitEffect = new ExplosionEffect(){{
|
||||
@@ -2043,7 +2044,7 @@ public class UnitTypes implements ContentList{
|
||||
trailY = -17f;
|
||||
trailScl = 3.2f;
|
||||
|
||||
buildSpeed = 3.5f;
|
||||
buildSpeed = 3f;
|
||||
|
||||
abilities.add(new EnergyFieldAbility(35f, 65f, 180f){{
|
||||
repair = 35f;
|
||||
@@ -2084,7 +2085,7 @@ public class UnitTypes implements ContentList{
|
||||
trailY = -32f;
|
||||
trailScl = 3.5f;
|
||||
|
||||
buildSpeed = 3.8f;
|
||||
buildSpeed = 3.5f;
|
||||
|
||||
for(float mountY : new float[]{-117/4f, 50/4f}){
|
||||
for(float sign : Mathf.signs){
|
||||
@@ -2112,8 +2113,8 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
bullet = new ContinuousLaserBulletType(){{
|
||||
maxRange = 90f;
|
||||
damage = 25f;
|
||||
length = 90f;
|
||||
damage = 26f;
|
||||
length = 95f;
|
||||
hitEffect = Fx.hitMeltHeal;
|
||||
drawSize = 200f;
|
||||
lifetime = 155f;
|
||||
@@ -2160,7 +2161,7 @@ public class UnitTypes implements ContentList{
|
||||
timeIncrease = 3f;
|
||||
timeDuration = 60f * 20f;
|
||||
powerDamageScl = 3f;
|
||||
damage = 40;
|
||||
damage = 50;
|
||||
hitColor = lightColor = Pal.heal;
|
||||
lightRadius = 70f;
|
||||
clipSize = 250f;
|
||||
@@ -2176,7 +2177,7 @@ public class UnitTypes implements ContentList{
|
||||
trailWidth = 6f;
|
||||
trailColor = Pal.heal;
|
||||
trailInterval = 3f;
|
||||
splashDamage = 40f;
|
||||
splashDamage = 60f;
|
||||
splashDamageRadius = rad;
|
||||
hitShake = 4f;
|
||||
trailRotation = true;
|
||||
|
||||
@@ -184,6 +184,13 @@ public class Logic implements ApplicationListener{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//heal all cores on game start
|
||||
for(TeamData team : state.teams.getActive()){
|
||||
for(var entity : team.cores){
|
||||
entity.heal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void reset(){
|
||||
|
||||
@@ -385,7 +385,7 @@ public class Renderer implements ApplicationListener{
|
||||
lines[i + 3] = (byte)255;
|
||||
}
|
||||
Pixmap fullPixmap = new Pixmap(w, h);
|
||||
Buffers.copy(lines, 0, fullPixmap.getPixels(), lines.length);
|
||||
Buffers.copy(lines, 0, fullPixmap.pixels, lines.length);
|
||||
Fi file = screenshotDirectory.child("screenshot-" + Time.millis() + ".png");
|
||||
PixmapIO.writePng(file, fullPixmap);
|
||||
fullPixmap.dispose();
|
||||
|
||||
@@ -401,8 +401,14 @@ public class BulletType extends Content implements Cloneable{
|
||||
//pierceBuilding is not enabled by default, because a bullet may want to *not* pierce buildings
|
||||
}
|
||||
|
||||
if(lightningType == null){
|
||||
lightningType = !collidesAir ? Bullets.damageLightningGround : Bullets.damageLightning;
|
||||
if(lightning > 0){
|
||||
if(status == StatusEffects.none){
|
||||
status = StatusEffects.shocked;
|
||||
}
|
||||
|
||||
if(lightningType == null){
|
||||
lightningType = !collidesAir ? Bullets.damageLightningGround : Bullets.damageLightning;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,7 +451,7 @@ public class BulletType extends Content implements Cloneable{
|
||||
bullet.owner = owner;
|
||||
bullet.team = team;
|
||||
bullet.time = 0f;
|
||||
bullet.vel.trns(angle, speed * velocityScl);
|
||||
bullet.initVel(angle, speed * velocityScl);
|
||||
if(backMove){
|
||||
bullet.set(x - bullet.vel.x * Time.delta, y - bullet.vel.y * Time.delta);
|
||||
}else{
|
||||
@@ -462,7 +468,7 @@ public class BulletType extends Content implements Cloneable{
|
||||
}
|
||||
bullet.add();
|
||||
|
||||
if(keepVelocity && owner instanceof Velc v) bullet.vel.add(v.vel().x, v.vel().y);
|
||||
if(keepVelocity && owner instanceof Velc v) bullet.vel.add(v.vel());
|
||||
return bullet;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@ public class ContinuousLaserBulletType extends BulletType{
|
||||
public boolean largeHit = true;
|
||||
|
||||
public ContinuousLaserBulletType(float damage){
|
||||
super(0.001f, damage);
|
||||
this.damage = damage;
|
||||
this.speed = 0f;
|
||||
|
||||
hitEffect = Fx.hitBeam;
|
||||
despawnEffect = Fx.none;
|
||||
|
||||
@@ -21,7 +21,8 @@ public class LaserBulletType extends BulletType{
|
||||
public boolean largeHit = false;
|
||||
|
||||
public LaserBulletType(float damage){
|
||||
super(0.01f, damage);
|
||||
this.damage = damage;
|
||||
this.speed = 0f;
|
||||
|
||||
hitEffect = Fx.hitLaserBlast;
|
||||
hitColor = colors[2];
|
||||
|
||||
@@ -12,8 +12,8 @@ public class LightningBulletType extends BulletType{
|
||||
public int lightningLength = 25, lightningLengthRand = 0;
|
||||
|
||||
public LightningBulletType(){
|
||||
super(0.0001f, 1f);
|
||||
|
||||
damage = 1f;
|
||||
speed = 0f;
|
||||
lifetime = 1;
|
||||
despawnEffect = Fx.none;
|
||||
hitEffect = Fx.hitLancer;
|
||||
|
||||
@@ -16,6 +16,7 @@ public class RailBulletType extends BulletType{
|
||||
public float updateEffectSeg = 20f;
|
||||
|
||||
public RailBulletType(){
|
||||
speed = 0f;
|
||||
pierceBuilding = true;
|
||||
pierce = true;
|
||||
reflectable = false;
|
||||
@@ -23,7 +24,6 @@ public class RailBulletType extends BulletType{
|
||||
despawnEffect = Fx.none;
|
||||
collides = false;
|
||||
lifetime = 1f;
|
||||
speed = 0.01f;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -57,7 +57,7 @@ public class RailBulletType extends BulletType{
|
||||
Damage.collideLine(b, b.team, b.type.hitEffect, b.x, b.y, b.rotation(), length, false, false);
|
||||
float resultLen = b.fdata;
|
||||
|
||||
Vec2 nor = Tmp.v1.set(b.vel).nor();
|
||||
Vec2 nor = Tmp.v1.trns(b.rotation(), 1f).nor();
|
||||
for(float i = 0; i <= resultLen; i += updateEffectSeg){
|
||||
updateEffect.at(b.x + nor.x * i, b.y + nor.y * i, b.rotation());
|
||||
}
|
||||
@@ -70,8 +70,8 @@ public class RailBulletType extends BulletType{
|
||||
|
||||
@Override
|
||||
public void hitEntity(Bullet b, Hitboxc entity, float health){
|
||||
handle(b, entity, health);
|
||||
super.hitEntity(b, entity, health);
|
||||
handle(b, entity, health);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,7 +17,7 @@ public class SapBulletType extends BulletType{
|
||||
public float width = 0.4f;
|
||||
|
||||
public SapBulletType(){
|
||||
speed = 0.0001f;
|
||||
speed = 0f;
|
||||
despawnEffect = Fx.none;
|
||||
pierce = true;
|
||||
collides = false;
|
||||
|
||||
@@ -19,7 +19,7 @@ public class ShrapnelBulletType extends BulletType{
|
||||
public float serrationLenScl = 10f, serrationWidth = 4f, serrationSpacing = 8f, serrationSpaceOffset = 80f, serrationFadeOffset = 0.5f;
|
||||
|
||||
public ShrapnelBulletType(){
|
||||
speed = 0.01f;
|
||||
speed = 0f;
|
||||
hitEffect = Fx.hitLancer;
|
||||
shootEffect = smokeEffect = Fx.lightningShoot;
|
||||
lifetime = 10f;
|
||||
|
||||
@@ -2,7 +2,6 @@ package mindustry.entities.comp;
|
||||
|
||||
import arc.func.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
@@ -22,11 +21,16 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
|
||||
@Import Team team;
|
||||
@Import Entityc owner;
|
||||
@Import float x, y, damage;
|
||||
@Import Vec2 vel;
|
||||
|
||||
IntSeq collided = new IntSeq(6);
|
||||
Object data;
|
||||
BulletType type;
|
||||
float fdata;
|
||||
|
||||
@ReadOnly
|
||||
private float rotation;
|
||||
|
||||
transient boolean absorbed, hit;
|
||||
transient @Nullable Trail trail;
|
||||
|
||||
@@ -149,17 +153,20 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
|
||||
type.drawLight(self());
|
||||
}
|
||||
|
||||
public void initVel(float angle, float amount){
|
||||
vel.trns(angle, amount);
|
||||
rotation = angle;
|
||||
}
|
||||
|
||||
/** Sets the bullet's rotation in degrees. */
|
||||
@Override
|
||||
public void rotation(float angle){
|
||||
vel().setAngle(angle);
|
||||
vel.setAngle(rotation = angle);
|
||||
}
|
||||
|
||||
/** @return the bullet's rotation. */
|
||||
@Override
|
||||
public float rotation(){
|
||||
float angle = Mathf.atan2(vel().x, vel().y) * Mathf.radiansToDegrees;
|
||||
if(angle < 0) angle += 360;
|
||||
return angle;
|
||||
return vel.isZero(0.001f) ? rotation : vel.angle();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ abstract class FireComp implements Timedc, Posc, Syncc, Drawc{
|
||||
baseFlammability = -1, puddleFlammability, damageTimer = Mathf.random(40f),
|
||||
spreadTimer = Mathf.random(spreadDelay), fireballTimer = Mathf.random(fireballDelay),
|
||||
warmup = 0f,
|
||||
animation = Mathf.random(frames);
|
||||
animation = Mathf.random(frames - 1);
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
@@ -116,8 +116,10 @@ abstract class FireComp implements Timedc, Posc, Syncc, Drawc{
|
||||
|
||||
Draw.alpha(Mathf.clamp(warmup / warmupDuration));
|
||||
Draw.z(Layer.effect);
|
||||
Draw.rect(regions[(int)animation], x, y);
|
||||
Draw.rect(regions[Math.min((int)animation, regions.length - 1)], x, y);
|
||||
Draw.reset();
|
||||
|
||||
Drawf.light(x, y, 50f + Mathf.absin(5f, 5f), Pal.lightFlame, 0.6f * Mathf.clamp(warmup / warmupDuration));
|
||||
}
|
||||
|
||||
@Replace
|
||||
|
||||
@@ -45,6 +45,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
|
||||
transient String lastText = "";
|
||||
transient float textFadeTime;
|
||||
transient private Unit lastReadUnit = Nulls.unit;
|
||||
transient @Nullable Unit justSwitchFrom, justSwitchTo;
|
||||
|
||||
public boolean isBuilder(){
|
||||
return unit.canBuild();
|
||||
@@ -100,6 +101,16 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
|
||||
|
||||
@Override
|
||||
public void afterSync(){
|
||||
//fix rubberbanding:
|
||||
//when the player recs a unit that they JUST transitioned away from, use the new unit instead
|
||||
//reason: we know the server is lying here, essentially skip the unit snapshot because we know the client's information is more recent
|
||||
if(isLocal() && unit == justSwitchFrom && justSwitchFrom != null && justSwitchTo != null){
|
||||
unit = justSwitchTo;
|
||||
}else{
|
||||
justSwitchFrom = null;
|
||||
justSwitchTo = null;
|
||||
}
|
||||
|
||||
//simulate a unit change after sync
|
||||
Unit set = unit;
|
||||
unit = lastReadUnit;
|
||||
@@ -149,6 +160,13 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
|
||||
|
||||
}
|
||||
|
||||
public void checkSpawn(){
|
||||
CoreBuild core = bestCore();
|
||||
if(core != null){
|
||||
core.requestSpawn(self());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(){
|
||||
//clear unit upon removal
|
||||
@@ -171,6 +189,11 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
|
||||
}
|
||||
|
||||
public void unit(Unit unit){
|
||||
//refuse to switch when the unit was just transitioned from
|
||||
if(isLocal() && unit == justSwitchFrom && justSwitchFrom != null && justSwitchTo != null){
|
||||
return;
|
||||
}
|
||||
|
||||
if(unit == null) throw new IllegalArgumentException("Unit cannot be null. Use clearUnit() instead.");
|
||||
if(this.unit == unit) return;
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@ import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.environment.*;
|
||||
|
||||
//just a proof of concept
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@Component
|
||||
abstract class WaterMoveComp implements Posc, Velc, Hitboxc, Flyingc, Unitc{
|
||||
@Import float x, y, rotation;
|
||||
@@ -32,7 +33,7 @@ abstract class WaterMoveComp implements Posc, Velc, Hitboxc, Flyingc, Unitc{
|
||||
|
||||
int sign = i == 0 ? -1 : 1;
|
||||
float cx = Angles.trnsx(rotation - 90, type.trailX * sign, type.trailY) + x, cy = Angles.trnsy(rotation - 90, type.trailX * sign, type.trailY) + y;
|
||||
t.update(cx, cy);
|
||||
t.update(cx, cy, world.floorWorld(cx, cy).isLiquid ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -144,6 +144,14 @@ public class MinimapRenderer{
|
||||
public void update(Tile tile){
|
||||
if(world.isGenerating() || !state.isGame()) return;
|
||||
|
||||
if(tile.build != null && tile.isCenter()){
|
||||
tile.getLinkedTiles(other -> {
|
||||
if(!other.isCenter()){
|
||||
update(other);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
int color = colorFor(tile);
|
||||
pixmap.set(tile.x, pixmap.height - 1 - tile.y, color);
|
||||
|
||||
|
||||
@@ -26,6 +26,10 @@ public class MultiPacker implements Disposable{
|
||||
return null;
|
||||
}
|
||||
|
||||
public PixmapPacker getPacker(PageType type){
|
||||
return packers[type.ordinal()];
|
||||
}
|
||||
|
||||
public boolean has(String name){
|
||||
for(var page : PageType.all){
|
||||
if(packers[page.ordinal()].getRect(name) != null){
|
||||
@@ -70,8 +74,9 @@ public class MultiPacker implements Disposable{
|
||||
//main page (sprites.png) - all sprites for units, weapons, placeable blocks, effects, bullets, etc
|
||||
//environment page (sprites2.png) - all sprites for things in the environmental cache layer
|
||||
//editor page (sprites3.png) - all sprites needed for rendering in the editor, including block icons and a few minor sprites
|
||||
//zone page (sprites4.png) - zone previews
|
||||
//ui page (sprites5.png) - content icons, white icons and UI elements
|
||||
//zone page (sprites4.png) - zone preview
|
||||
//rubble page - scorch textures for unit deaths & wrecks
|
||||
//ui page (sprites5.png) - content icons, white icons, fonts and UI elements
|
||||
public enum PageType{
|
||||
main(4096),
|
||||
environment,
|
||||
|
||||
@@ -40,6 +40,7 @@ public class Trail{
|
||||
float[] items = points.items;
|
||||
int i = points.size - 3;
|
||||
float x1 = items[i], y1 = items[i + 1], w1 = items[i + 2], w = w1 * width / (points.size/3) * i/3f * 2f;
|
||||
if(w1 <= 0.001f) return;
|
||||
Draw.rect("hcircle", x1, y1, w, w, -Mathf.radDeg * lastAngle + 180f);
|
||||
Draw.reset();
|
||||
}
|
||||
@@ -56,6 +57,7 @@ public class Trail{
|
||||
float size = width / (points.size/3);
|
||||
float z1 = lastAngle;
|
||||
float z2 = -Angles.angleRad(x2, y2, lx, ly);
|
||||
if(w1 <= 0.001f || w2 <= 0.001f) continue;
|
||||
|
||||
float cx = Mathf.sin(z1) * i/3f * size * w1, cy = Mathf.cos(z1) * i/3f * size * w1,
|
||||
nx = Mathf.sin(z2) * (i/3f + 1) * size * w2, ny = Mathf.cos(z2) * (i/3f + 1) * size * w2;
|
||||
|
||||
@@ -229,8 +229,10 @@ public class DesktopInput extends InputHandler{
|
||||
if(on != null){
|
||||
Call.unitControl(player, on);
|
||||
shouldShoot = false;
|
||||
recentRespawnTimer = 1f;
|
||||
}else if(build != null){
|
||||
Call.buildingControlSelect(player, build);
|
||||
recentRespawnTimer = 1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,9 +240,10 @@ public class DesktopInput extends InputHandler{
|
||||
if(!player.dead() && !state.isPaused() && !scene.hasField()){
|
||||
updateMovement(player.unit());
|
||||
|
||||
if(Core.input.keyDown(Binding.respawn)){
|
||||
Call.unitClear(player);
|
||||
if(Core.input.keyTap(Binding.respawn)){
|
||||
controlledType = null;
|
||||
recentRespawnTimer = 1f;
|
||||
Call.unitClear(player);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
public Group uiGroup;
|
||||
public boolean isBuilding = true, buildWasAutoPaused = false, wasShooting = false;
|
||||
public @Nullable UnitType controlledType;
|
||||
public float recentRespawnTimer;
|
||||
|
||||
public @Nullable Schematic lastSchematic;
|
||||
public GestureDetector detector;
|
||||
@@ -375,15 +376,27 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
throw new ValidateException(player, "Player cannot control a unit.");
|
||||
}
|
||||
|
||||
//TODO problem:
|
||||
//1. server send snapshot
|
||||
//2. client requests to control unit, becomes unit locally
|
||||
//3. snapshot arrives, client now thinks they're in the old unit (!!!)
|
||||
//4. server gets packet that player is in the right unit
|
||||
//5. server sends snapshot
|
||||
//6. client gets snapshot, realizes that they are actually in the unit they selected
|
||||
//7. client gets switched to new unit -> rubberbanding (!!!)
|
||||
|
||||
//clear player unit when they possess a core
|
||||
if(unit == null){ //just clear the unit (is this used?)
|
||||
player.clearUnit();
|
||||
//make sure it's AI controlled, so players can't overwrite each other
|
||||
}else if(unit.isAI() && unit.team == player.team() && !unit.dead){
|
||||
if(!net.client()){
|
||||
player.unit(unit);
|
||||
if(net.client() && player.isLocal()){
|
||||
player.justSwitchFrom = player.unit();
|
||||
player.justSwitchTo = unit;
|
||||
}
|
||||
|
||||
player.unit(unit);
|
||||
|
||||
Time.run(Fx.unitSpirit.lifetime, () -> Fx.unitControl.at(unit.x, unit.y, 0f, unit));
|
||||
if(!player.dead()){
|
||||
Fx.unitSpirit.at(player.x, player.y, 0f, unit);
|
||||
@@ -393,12 +406,14 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
Events.fire(new UnitControlEvent(player, unit));
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.both, forward = true)
|
||||
@Remote(targets = Loc.both, called = Loc.server, forward = true)
|
||||
public static void unitClear(Player player){
|
||||
if(player == null) return;
|
||||
|
||||
//problem: this gets called on both ends. it shouldn't be.
|
||||
Fx.spawn.at(player);
|
||||
player.clearUnit();
|
||||
player.checkSpawn();
|
||||
player.deathTimer = Player.deathDelay + 1f; //for instant respawn
|
||||
}
|
||||
|
||||
@@ -419,7 +434,6 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
player.unit().commandNearby(new CircleFormation());
|
||||
Fx.commandSend.at(player, player.unit().type.commandRadius);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Eachable<BuildPlan> allRequests(){
|
||||
@@ -434,10 +448,6 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
return !selectRequests.isEmpty();
|
||||
}
|
||||
|
||||
public OverlayFragment getFrag(){
|
||||
return frag;
|
||||
}
|
||||
|
||||
public void update(){
|
||||
player.typing = ui.chatfrag.shown();
|
||||
|
||||
@@ -451,7 +461,9 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
|
||||
wasShooting = player.shooting;
|
||||
|
||||
if(!player.dead()){
|
||||
//only reset the controlled type and control a unit after the timer runs out
|
||||
//essentially, this means the client waits for ~1 second after controlling something before trying to control something else automatically
|
||||
if(!player.dead() && (recentRespawnTimer -= Time.delta / 70f) <= 0f && player.justSwitchFrom != player.unit()){
|
||||
controlledType = player.unit().type;
|
||||
}
|
||||
|
||||
@@ -461,6 +473,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
if(unit != null){
|
||||
//only trying controlling once a second to prevent packet spam
|
||||
if(!net.client() || controlInterval.get(0, 70f)){
|
||||
recentRespawnTimer = 1f;
|
||||
Call.unitControl(player, unit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -614,8 +614,10 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
//control a unit/block detected on first tap of double-tap
|
||||
if(unitTapped != null){
|
||||
Call.unitControl(player, unitTapped);
|
||||
recentRespawnTimer = 1f;
|
||||
}else if(buildingTapped != null){
|
||||
Call.buildingControlSelect(player, buildingTapped);
|
||||
recentRespawnTimer = 1f;
|
||||
}else if(!tryBeginMine(cursor)){
|
||||
tileTapped(linked.build);
|
||||
}
|
||||
@@ -856,8 +858,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
|
||||
boolean omni = unit.type.omniMovement;
|
||||
boolean allowHealing = type.canHeal;
|
||||
boolean validHealTarget = allowHealing && target instanceof Building && ((Building)target).isValid() && target.team() == unit.team &&
|
||||
((Building)target).damaged() && target.within(unit, type.range);
|
||||
boolean validHealTarget = allowHealing && target instanceof Building b && b.isValid() && target.team() == unit.team && b.damaged() && target.within(unit, type.range);
|
||||
boolean boosted = (unit instanceof Mechc && unit.isFlying());
|
||||
|
||||
//reset target if:
|
||||
@@ -912,13 +913,8 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
unit.vel.approachDelta(Vec2.ZERO, unit.speed() * type.accel / 2f);
|
||||
}
|
||||
|
||||
float expansion = 3f;
|
||||
|
||||
unit.hitbox(rect);
|
||||
rect.x -= expansion;
|
||||
rect.y -= expansion;
|
||||
rect.width += expansion * 2f;
|
||||
rect.height += expansion * 2f;
|
||||
rect.grow(6f);
|
||||
|
||||
player.boosting = collisions.overlapsTile(rect) || !unit.within(targetPos, 85f);
|
||||
|
||||
@@ -927,7 +923,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
}else{
|
||||
unit.moveAt(Tmp.v2.trns(unit.rotation, movement.len()));
|
||||
if(!movement.isZero()){
|
||||
unit.vel.rotateTo(movement.angle(), unit.type.rotateSpeed * Math.max(Time.delta, 1));
|
||||
unit.rotation = Angles.moveToward(unit.rotation, movement.angle(), unit.type.rotateSpeed * Math.max(Time.delta, 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import mindustry.ctype.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
@@ -111,6 +112,18 @@ public class JsonIO{
|
||||
}
|
||||
});
|
||||
|
||||
json.setSerializer(Attribute.class, new Serializer<>(){
|
||||
@Override
|
||||
public void write(Json json, Attribute object, Class knownType){
|
||||
json.writeValue(object.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Attribute read(Json json, JsonValue jsonData, Class type){
|
||||
return Attribute.get(jsonData.asString());
|
||||
}
|
||||
});
|
||||
|
||||
json.setSerializer(Item.class, new Serializer<>(){
|
||||
@Override
|
||||
public void write(Json json, Item object, Class knownType){
|
||||
|
||||
@@ -112,7 +112,6 @@ public class LCanvas extends Table{
|
||||
|
||||
jumps.cullable = false;
|
||||
}).grow().get();
|
||||
//pane.setClip(false);
|
||||
pane.setFlickScroll(false);
|
||||
|
||||
//load old scroll percent
|
||||
|
||||
@@ -36,13 +36,20 @@ public enum LogicOp{
|
||||
abs("abs", a -> Math.abs(a)),
|
||||
log("log", Math::log),
|
||||
log10("log10", Math::log10),
|
||||
sin("sin", d -> Math.sin(d * 0.017453292519943295D)),
|
||||
cos("cos", d -> Math.cos(d * 0.017453292519943295D)),
|
||||
tan("tan", d -> Math.tan(d * 0.017453292519943295D)),
|
||||
floor("floor", Math::floor),
|
||||
ceil("ceil", Math::ceil),
|
||||
sqrt("sqrt", Math::sqrt),
|
||||
rand("rand", d -> Mathf.rand.nextDouble() * d);
|
||||
rand("rand", d -> Mathf.rand.nextDouble() * d),
|
||||
|
||||
sin("sin", d -> Math.sin(d * Mathf.doubleDegRad)),
|
||||
cos("cos", d -> Math.cos(d * Mathf.doubleDegRad)),
|
||||
tan("tan", d -> Math.tan(d * Mathf.doubleDegRad)),
|
||||
|
||||
asin("asin", d -> Math.asin(d) * Mathf.doubleRadDeg),
|
||||
acos("acos", d -> Math.acos(d) * Mathf.doubleRadDeg),
|
||||
atan("atan", d -> Math.atan(d) * Mathf.doubleRadDeg),
|
||||
|
||||
;
|
||||
|
||||
public static final LogicOp[] all = values();
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package mindustry.maps;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.ai.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
@@ -186,7 +185,6 @@ public class SectorDamage{
|
||||
|
||||
Tile start = spawns.first();
|
||||
|
||||
Time.mark();
|
||||
var field = pathfinder.getField(state.rules.waveTeam, Pathfinder.costGround, Pathfinder.fieldCore);
|
||||
Seq<Tile> path = new Seq<>();
|
||||
boolean found = false;
|
||||
|
||||
@@ -111,4 +111,23 @@ public abstract class FilterOption{
|
||||
table.add("@filter.option." + name);
|
||||
}
|
||||
}
|
||||
|
||||
static class ToggleOption extends FilterOption{
|
||||
final String name;
|
||||
final Boolp getter;
|
||||
final Boolc setter;
|
||||
|
||||
ToggleOption(String name, Boolp getter, Boolc setter){
|
||||
this.name = name;
|
||||
this.getter = getter;
|
||||
this.setter = setter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build(Table table){
|
||||
table.row();
|
||||
CheckBox check = table.check("@filter.option." + name, setter).growX().padBottom(5).padTop(5).center().get();
|
||||
check.changed(changed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,11 +15,13 @@ public class MirrorFilter extends GenerateFilter{
|
||||
private final Vec2 v1 = new Vec2(), v2 = new Vec2(), v3 = new Vec2();
|
||||
|
||||
int angle = 45;
|
||||
boolean rotate = false;
|
||||
|
||||
@Override
|
||||
public FilterOption[] options(){
|
||||
return Structs.arr(
|
||||
new SliderOption("angle", () -> angle, f -> angle = (int)f, 0, 360, 45)
|
||||
new SliderOption("angle", () -> angle, f -> angle = (int)f, 0, 360, 45),
|
||||
new ToggleOption("rotate", () -> rotate, f -> rotate = f)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -72,8 +74,8 @@ public class MirrorFilter extends GenerateFilter{
|
||||
}
|
||||
|
||||
void mirror(Vec2 p, float x0, float y0, float x1, float y1){
|
||||
//special case: uneven map mirrored at 45 degree angle
|
||||
if(in.width != in.height && angle % 90 != 0){
|
||||
//special case: uneven map mirrored at 45 degree angle (or someone might just want rotational symmetry)
|
||||
if((in.width != in.height && angle % 90 != 0) || rotate){
|
||||
p.x = in.width - p.x - 1;
|
||||
p.y = in.height - p.y - 1;
|
||||
}else{
|
||||
|
||||
@@ -61,6 +61,7 @@ public class ContentParser{
|
||||
});
|
||||
put(Interp.class, (type, data) -> field(Interp.class, data));
|
||||
put(CacheLayer.class, (type, data) -> field(CacheLayer.class, data));
|
||||
put(Attribute.class, (type, data) -> Attribute.get(data.asString()));
|
||||
put(Schematic.class, (type, data) -> {
|
||||
Object result = fieldOpt(Loadouts.class, data);
|
||||
if(result != null){
|
||||
|
||||
@@ -607,7 +607,8 @@ public class Mods implements Loadable{
|
||||
if(mod.root.child("content").exists()){
|
||||
Fi contentRoot = mod.root.child("content");
|
||||
for(ContentType type : ContentType.all){
|
||||
Fi folder = contentRoot.child(type.name().toLowerCase(Locale.ROOT) + "s");
|
||||
String lower = type.name().toLowerCase(Locale.ROOT);
|
||||
Fi folder = contentRoot.child(lower + (lower.endsWith("s") ? "" : "s"));
|
||||
if(folder.exists()){
|
||||
for(Fi file : folder.findAll(f -> f.extension().equals("json") || f.extension().equals("hjson"))){
|
||||
runs.add(new LoadRun(type, file, mod));
|
||||
|
||||
@@ -385,7 +385,6 @@ public class ArcNetProvider implements NetProvider{
|
||||
return readFramework(byteBuffer);
|
||||
}else{
|
||||
//read length int, followed by compressed lz4 data
|
||||
//TODO not thread safe!!!
|
||||
Packet packet = Net.newPacket(id);
|
||||
var buffer = decompressBuffer.get();
|
||||
int length = byteBuffer.getShort() & 0xffff;
|
||||
@@ -396,7 +395,7 @@ public class ArcNetProvider implements NetProvider{
|
||||
buffer.position(0).limit(length);
|
||||
buffer.put(byteBuffer.array(), byteBuffer.position(), length);
|
||||
buffer.position(0);
|
||||
packet.read(reads.get());
|
||||
packet.read(reads.get(), length);
|
||||
//move read packets forward
|
||||
byteBuffer.position(byteBuffer.position() + buffer.position());
|
||||
}else{
|
||||
@@ -405,7 +404,7 @@ public class ArcNetProvider implements NetProvider{
|
||||
|
||||
buffer.position(0);
|
||||
buffer.limit(length);
|
||||
packet.read(reads.get());
|
||||
packet.read(reads.get(), length);
|
||||
//move buffer forward based on bytes read by decompressor
|
||||
byteBuffer.position(byteBuffer.position() + read);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import arc.func.*;
|
||||
import arc.util.*;
|
||||
import arc.util.async.*;
|
||||
import arc.util.serialization.*;
|
||||
import mindustry.*;
|
||||
import mindustry.core.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
@@ -39,7 +40,7 @@ public class BeControl{
|
||||
public BeControl(){
|
||||
if(active()){
|
||||
Timer.schedule(() -> {
|
||||
if(checkUpdates && !mobile){
|
||||
if(Vars.clientLoaded && checkUpdates && !mobile){
|
||||
checkUpdate(t -> {});
|
||||
}
|
||||
}, updateInterval, updateInterval);
|
||||
|
||||
@@ -257,6 +257,7 @@ public class Net{
|
||||
* Call to handle a packet being received for the client.
|
||||
*/
|
||||
public void handleClientReceived(Packet object){
|
||||
object.handled();
|
||||
|
||||
if(object instanceof StreamBegin b){
|
||||
streams.put(b.id, currentStream = new StreamBuilder(b));
|
||||
@@ -291,6 +292,8 @@ public class Net{
|
||||
* Call to handle a packet being received for the server.
|
||||
*/
|
||||
public void handleServerReceived(NetConnection connection, Packet object){
|
||||
object.handled();
|
||||
|
||||
try{
|
||||
//handle object normally
|
||||
if(serverListeners.get(object.getClass()) != null){
|
||||
|
||||
@@ -2,7 +2,14 @@ package mindustry.net;
|
||||
|
||||
import arc.util.io.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public abstract class Packet{
|
||||
//internally used by generated code
|
||||
protected static final byte[] NODATA = {};
|
||||
protected static final ReusableByteInStream BAIS = new ReusableByteInStream();
|
||||
protected static final Reads READ = new Reads(new DataInputStream(BAIS));
|
||||
|
||||
//these are constants because I don't want to bother making an enum to mirror the annotation enum
|
||||
|
||||
/** Does not get handled unless client is connected. */
|
||||
@@ -15,6 +22,12 @@ public abstract class Packet{
|
||||
public void read(Reads read){}
|
||||
public void write(Writes write){}
|
||||
|
||||
public void read(Reads read, int length){
|
||||
read(read);
|
||||
}
|
||||
|
||||
public void handled(){}
|
||||
|
||||
public int getPriority(){
|
||||
return priorityNormal;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package mindustry.net;
|
||||
|
||||
import arc.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.io.*;
|
||||
import arc.util.serialization.*;
|
||||
import mindustry.core.*;
|
||||
@@ -131,8 +130,6 @@ public class Packets{
|
||||
crc.update(Base64Coder.decode(uuid), 0, b.length);
|
||||
buffer.l(crc.getValue());
|
||||
|
||||
Log.info("CRC value sent: @", Long.toHexString(crc.getValue()));
|
||||
|
||||
buffer.b(mobile ? (byte)1 : 0);
|
||||
buffer.i(color);
|
||||
buffer.b((byte)mods.size);
|
||||
|
||||
@@ -120,7 +120,7 @@ public class StatusEffect extends UnlockableContent{
|
||||
|
||||
if(effect != Fx.none && Mathf.chanceDelta(effectChance)){
|
||||
Tmp.v1.rnd(Mathf.range(unit.type.hitSize/2f));
|
||||
effect.at(unit.x + Tmp.v1.x, unit.y + Tmp.v1.y);
|
||||
effect.at(unit.x + Tmp.v1.x, unit.y + Tmp.v1.y, color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.audio.*;
|
||||
import mindustry.content.*;
|
||||
@@ -15,6 +17,7 @@ import mindustry.entities.bullet.*;
|
||||
import mindustry.entities.units.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@@ -119,6 +122,17 @@ public class Weapon implements Cloneable{
|
||||
this("");
|
||||
}
|
||||
|
||||
public void addStats(UnitType u, Table t){
|
||||
if(inaccuracy > 0){
|
||||
t.row();
|
||||
t.add("[lightgray]" + Stat.inaccuracy.localized() + ": [white]" + (int)inaccuracy + " " + StatUnit.degrees.localized());
|
||||
}
|
||||
t.row();
|
||||
t.add("[lightgray]" + Stat.reload.localized() + ": " + (mirror ? "2x " : "") + "[white]" + Strings.autoFixed(60f / reload * shots, 2));
|
||||
|
||||
StatValues.ammo(ObjectMap.of(u, bullet)).display(t);
|
||||
}
|
||||
|
||||
public float dps(){
|
||||
return (bullet.estimateDPS() / reload) * shots * 60f;
|
||||
}
|
||||
|
||||
@@ -5,12 +5,14 @@ import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.util.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.units.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.blocks.units.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
/**
|
||||
* Note that this weapon requires a bullet with a positive maxRange.
|
||||
@@ -47,6 +49,12 @@ public class RepairBeamWeapon extends Weapon{
|
||||
recoil = 0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStats(UnitType u, Table w){
|
||||
w.row();
|
||||
w.add("[lightgray]" + Stat.repairSpeed.localized() + ": " + (mirror ? "2x " : "") + "[white]" + (int)(repairSpeed * 60) + " " + StatUnit.perSecond.localized());
|
||||
}
|
||||
|
||||
@Override
|
||||
public float dps(){
|
||||
return 0f;
|
||||
|
||||
@@ -40,7 +40,7 @@ public class SearchBar{
|
||||
parent.pane(table -> {
|
||||
pane[0] = table;
|
||||
rebuild.get("");
|
||||
});
|
||||
}).get().setScrollingDisabled(true, false);
|
||||
return pane[0];
|
||||
}
|
||||
|
||||
@@ -54,9 +54,6 @@ public class SearchBar{
|
||||
|
||||
/** Match a list item with the search query, case insensitive */
|
||||
public static boolean matches(String query, String name){
|
||||
if(name == null || name.isEmpty()){
|
||||
return false;
|
||||
}
|
||||
return name.toLowerCase().contains(query);
|
||||
return name != null && !name.isEmpty() && name.toLowerCase().contains(query);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import arc.*;
|
||||
import arc.scene.ui.*;
|
||||
import arc.util.*;
|
||||
import mindustry.core.GameState.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
|
||||
@@ -43,7 +44,12 @@ public class BaseDialog extends Dialog{
|
||||
}
|
||||
|
||||
protected void onResize(Runnable run){
|
||||
resized(run);
|
||||
Events.on(ResizeEvent.class, event -> {
|
||||
if(isShown() && Core.scene.getDialog() == this){
|
||||
run.run();
|
||||
updateScrollFocus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void addCloseListener(){
|
||||
|
||||
@@ -127,7 +127,7 @@ public class ModsDialog extends BaseDialog{
|
||||
try{
|
||||
return d.parse(text);
|
||||
}catch(Exception e){
|
||||
throw new RuntimeException(e);
|
||||
return new Date();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -147,12 +147,11 @@ public class ModsDialog extends BaseDialog{
|
||||
}
|
||||
|
||||
void setup(){
|
||||
boolean squish = Core.graphics.isPortrait();
|
||||
float h = 110f;
|
||||
float w = squish ? 410f : 524f;
|
||||
float w = Math.min(Core.graphics.getWidth() / 1.1f, 520f);
|
||||
|
||||
cont.clear();
|
||||
cont.defaults().width(squish ? 480 : 560f).pad(4);
|
||||
cont.defaults().width(Math.min(Core.graphics.getWidth() / 1.2f, 520f)).pad(4);
|
||||
cont.add("@mod.reloadrequired").visible(mods::requiresReload).center().get().setAlignment(Align.center);
|
||||
cont.row();
|
||||
|
||||
|
||||
@@ -721,6 +721,7 @@ public class HudFragment extends Fragment{
|
||||
t.clicked(() -> {
|
||||
if(!player.dead() && mobile){
|
||||
Call.unitClear(player);
|
||||
control.input.recentRespawnTimer = 1f;
|
||||
control.input.controlledType = null;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -241,7 +241,6 @@ public class Tile implements Position, QuadTreeObject, Displayable{
|
||||
//assign entity and type to blocks, so they act as proxies for this one
|
||||
other.build = entity;
|
||||
other.block = block;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ public class MendProjector extends Block{
|
||||
group = BlockGroup.projectors;
|
||||
hasPower = true;
|
||||
hasItems = true;
|
||||
emitLight = true;
|
||||
lightRadius = 50f;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,7 +131,7 @@ public class MendProjector extends Block{
|
||||
|
||||
@Override
|
||||
public void drawLight(){
|
||||
Drawf.light(team, x, y, 50f * smoothEfficiency, baseColor, 0.7f * smoothEfficiency);
|
||||
Drawf.light(team, x, y, lightRadius * smoothEfficiency, baseColor, 0.7f * smoothEfficiency);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -39,6 +39,8 @@ public class OverdriveProjector extends Block{
|
||||
hasPower = true;
|
||||
hasItems = true;
|
||||
canOverdrive = false;
|
||||
emitLight = true;
|
||||
lightRadius = 50f;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -89,7 +91,7 @@ public class OverdriveProjector extends Block{
|
||||
|
||||
@Override
|
||||
public void drawLight(){
|
||||
Drawf.light(team, x, y, 50f * smoothEfficiency, baseColor, 0.7f * smoothEfficiency);
|
||||
Drawf.light(team, x, y, lightRadius * smoothEfficiency, baseColor, 0.7f * smoothEfficiency);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,6 +3,7 @@ package mindustry.world.blocks.defense;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
@@ -17,6 +18,8 @@ public class ShockMine extends Block{
|
||||
public int length = 10;
|
||||
public int tendrils = 6;
|
||||
public Color lightningColor = Pal.lancerLaser;
|
||||
public float teamAlpha = 0.3f;
|
||||
public @Load("@-team-top") TextureRegion teamRegion;
|
||||
|
||||
public ShockMine(String name){
|
||||
super(name);
|
||||
@@ -24,7 +27,6 @@ public class ShockMine extends Block{
|
||||
destructible = true;
|
||||
solid = false;
|
||||
targetable = false;
|
||||
rebuildable = false;
|
||||
}
|
||||
|
||||
public class ShockMineBuild extends Building{
|
||||
@@ -37,12 +39,16 @@ public class ShockMine extends Block{
|
||||
@Override
|
||||
public void draw(){
|
||||
super.draw();
|
||||
Draw.color(team.color);
|
||||
Draw.alpha(0.22f);
|
||||
Fill.rect(x, y, 2f, 2f);
|
||||
Draw.color(team.color, teamAlpha);
|
||||
Draw.rect(teamRegion, x, y);
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawCracks(){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unitOn(Unit unit){
|
||||
if(enabled && unit.team != team && timer(timerDamage, cooldown)){
|
||||
|
||||
@@ -6,6 +6,7 @@ import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.io.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.units.*;
|
||||
@@ -183,5 +184,25 @@ public class Duct extends Block implements Autotiler{
|
||||
next = front();
|
||||
nextc = next instanceof DuctBuild d ? d : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte version(){
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Writes write){
|
||||
super.write(write);
|
||||
write.b(recDir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(Reads read, byte revision){
|
||||
super.read(read, revision);
|
||||
if(revision >= 1){
|
||||
recDir = read.b();
|
||||
}
|
||||
current = items.first();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public class DuctBridge extends Block{
|
||||
public @Load("@-dir") TextureRegion dirRegion;
|
||||
|
||||
public int range = 4;
|
||||
public float moveDelay = 5f;
|
||||
public float speed = 5f;
|
||||
|
||||
public DuctBridge(String name){
|
||||
super(name);
|
||||
@@ -37,6 +37,7 @@ public class DuctBridge extends Block{
|
||||
group = BlockGroup.transportation;
|
||||
noUpdateDisabled = true;
|
||||
envEnabled = Env.space | Env.terrestrial | Env.underwater;
|
||||
drawArrow = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,6 +56,37 @@ public class DuctBridge extends Block{
|
||||
Placement.calculateNodes(points, this, rotation, (point, other) -> Math.max(Math.abs(point.x - other.x), Math.abs(point.y - other.y)) <= range);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawPlace(int x, int y, int rotation, boolean valid){
|
||||
super.drawPlace(x, y, rotation, valid);
|
||||
|
||||
int length = range;
|
||||
Building found = null;
|
||||
|
||||
//find the link
|
||||
for(int i = 1; i <= range; i++){
|
||||
Tile other = world.tile(x + Geometry.d4x(rotation) * i, y + Geometry.d4y(rotation) * i);
|
||||
|
||||
if(other != null && other.build instanceof DuctBridgeBuild build && build.team == player.team()){
|
||||
length = i;
|
||||
found = other.build;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Drawf.dashLine(Pal.placing,
|
||||
x * tilesize + Geometry.d4[rotation].x * (tilesize / 2f + 2),
|
||||
y * tilesize + Geometry.d4[rotation].y * (tilesize / 2f + 2),
|
||||
x * tilesize + Geometry.d4[rotation].x * (length) * tilesize,
|
||||
y * tilesize + Geometry.d4[rotation].y * (length) * tilesize
|
||||
);
|
||||
|
||||
if(found != null){
|
||||
Drawf.square(found.x, found.y, found.block.size * tilesize/2f + 2.5f, 0f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean positionsValid(int x1, int y1, int x2, int y2){
|
||||
if(x1 == x2){
|
||||
return Math.abs(y1 - y2) <= range;
|
||||
@@ -88,7 +120,6 @@ public class DuctBridge extends Block{
|
||||
Draw.rect(bridgeBotRegion, cx, cy, len, tilesize, angle);
|
||||
Draw.reset();
|
||||
Draw.alpha(Renderer.bridgeOpacity);
|
||||
//Draw.rect(bridgeTopRegion, cx, cy, len, tilesize, angle);
|
||||
|
||||
for(float i = 6f; i <= len + size * tilesize - 5f; i += 5f){
|
||||
Draw.rect(arrowRegion, x + Geometry.d4x(rotation) * i, y + Geometry.d4y(rotation) * i, angle);
|
||||
@@ -116,12 +147,12 @@ public class DuctBridge extends Block{
|
||||
link.occupied[rotation % 4] = this;
|
||||
if(items.any() && link.items.total() < link.block.itemCapacity){
|
||||
progress += edelta();
|
||||
while(progress > moveDelay){
|
||||
while(progress > speed){
|
||||
Item next = items.take();
|
||||
if(next != null && link.items.total() < link.block.itemCapacity){
|
||||
link.handleItem(this, next);
|
||||
}
|
||||
progress -= moveDelay;
|
||||
progress -= speed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ public class DuctRouter extends Block{
|
||||
if(current == null) return null;
|
||||
|
||||
for(int i = -1; i <= 1; i++){
|
||||
Building other = nearby(Mathf.mod(rotation + i + cdump, 4));
|
||||
Building other = nearby(Mathf.mod(rotation + (((i + cdump + 1) % 3) - 1), 4));
|
||||
if(other != null && other.team == team && other.acceptItem(this, current)){
|
||||
return other;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import arc.util.pooling.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.bullet.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.logic.*;
|
||||
@@ -28,6 +29,7 @@ public class MassDriver extends Block{
|
||||
public int minDistribute = 10;
|
||||
public float knockback = 4f;
|
||||
public float reloadTime = 100f;
|
||||
public MassDriverBolt bullet;
|
||||
public float bulletSpeed = 5.5f;
|
||||
public float bulletLifetime = 200f;
|
||||
public Effect shootEffect = Fx.shootBig2;
|
||||
@@ -287,7 +289,7 @@ public class MassDriver extends Block{
|
||||
|
||||
float angle = tile.angleTo(target);
|
||||
|
||||
Bullets.driverBolt.create(this, team,
|
||||
bullet.create(this, team,
|
||||
x + Angles.trnsx(angle, translation), y + Angles.trnsy(angle, translation),
|
||||
angle, -1f, bulletSpeed, bulletLifetime, data);
|
||||
|
||||
|
||||
@@ -57,6 +57,14 @@ public class PayloadConveyor extends Block{
|
||||
stats.add(Stat.payloadCapacity, (payloadLimit), StatUnit.blocksSquared);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
super.init();
|
||||
|
||||
//increase clip size for oversize loads
|
||||
clipSize = Math.max(clipSize, size * tilesize * 2.1f);
|
||||
}
|
||||
|
||||
public class PayloadConveyorBuild extends Building{
|
||||
public @Nullable Payload item;
|
||||
public float progress, itemRotation, animation;
|
||||
|
||||
@@ -13,7 +13,7 @@ import mindustry.world.*;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class PayloadBlock extends Block{
|
||||
public float payloadSpeed = 0.5f, payloadRotateSpeed = 5f;
|
||||
public float payloadSpeed = 0.7f, payloadRotateSpeed = 5f;
|
||||
|
||||
public @Load(value = "@-top", fallback = "factory-top-@size") TextureRegion topRegion;
|
||||
public @Load(value = "@-out", fallback = "factory-out-@size") TextureRegion outRegion;
|
||||
|
||||
@@ -122,7 +122,8 @@ public class PayloadMassDriver extends PayloadBlock{
|
||||
public float turretRotation = 90;
|
||||
public float reload = 0f, charge = 0f;
|
||||
public float targetSize = grabWidth*2f, curSize = targetSize;
|
||||
public float payLength = 0f;
|
||||
public float payLength = 0f, effectDelayTimer = -1f;
|
||||
public PayloadDriverBuild lastOther;
|
||||
public boolean loaded;
|
||||
public boolean charging;
|
||||
public PayloadDriverState state = idle;
|
||||
@@ -151,6 +152,16 @@ public class PayloadMassDriver extends PayloadBlock{
|
||||
targetSize = payload.size();
|
||||
}
|
||||
|
||||
boolean pos = effectDelayTimer > 0;
|
||||
effectDelayTimer -= Time.delta;
|
||||
if(effectDelayTimer <= 0 && pos && lastOther != null){
|
||||
var other = lastOther;
|
||||
float cx = Angles.trnsx(other.turretRotation, length), cy = Angles.trnsy(other.turretRotation, length);
|
||||
receiveEffect.at(x - cx/2f, y - cy/2f, turretRotation);
|
||||
reload = 1f;
|
||||
Effect.shake(shake, shake, this);
|
||||
}
|
||||
|
||||
charging = false;
|
||||
|
||||
if(hasLink){
|
||||
@@ -192,7 +203,7 @@ public class PayloadMassDriver extends PayloadBlock{
|
||||
payVector.setZero();
|
||||
payRotation = Angles.moveToward(payRotation, turretRotation + 180f, payloadRotateSpeed * delta());
|
||||
}
|
||||
}else{
|
||||
}else if(effectDelayTimer <= 0){
|
||||
moveOutPayload();
|
||||
}
|
||||
}
|
||||
@@ -270,26 +281,22 @@ public class PayloadMassDriver extends PayloadBlock{
|
||||
transferEffect.at(x + cx, y + cy, turretRotation, new PayloadMassDriverData(x + cx, y + cy, other.x - cx, other.y - cy, payload));
|
||||
Payload pay = payload;
|
||||
other.recPayload = payload;
|
||||
other.effectDelayTimer = transferEffect.lifetime;
|
||||
|
||||
Time.run(transferEffect.lifetime, () -> {
|
||||
receiveEffect.at(other.x - cx/2f, other.y - cy/2f, other.turretRotation);
|
||||
Effect.shake(shake, shake, this);
|
||||
//transfer payload
|
||||
other.handlePayload(this, pay);
|
||||
other.lastOther = this;
|
||||
other.payVector.set(-cx, -cy);
|
||||
other.payRotation = turretRotation;
|
||||
other.payLength = length;
|
||||
other.loaded = true;
|
||||
other.updatePayload();
|
||||
other.recPayload = null;
|
||||
|
||||
//transfer payload
|
||||
other.reload = 1f;
|
||||
other.handlePayload(this, pay);
|
||||
other.payVector.set(-cx, -cy);
|
||||
other.payRotation = turretRotation;
|
||||
other.payLength = length;
|
||||
other.loaded = true;
|
||||
other.updatePayload();
|
||||
other.recPayload = null;
|
||||
|
||||
if(other.waitingShooters.size != 0 && other.waitingShooters.first() == this){
|
||||
other.waitingShooters.removeFirst();
|
||||
}
|
||||
other.state = idle;
|
||||
});
|
||||
if(other.waitingShooters.size != 0 && other.waitingShooters.first() == this){
|
||||
other.waitingShooters.removeFirst();
|
||||
}
|
||||
other.state = idle;
|
||||
|
||||
//reset state after shooting immediately
|
||||
payload = null;
|
||||
@@ -341,8 +348,10 @@ public class PayloadMassDriver extends PayloadBlock{
|
||||
if(payload != null){
|
||||
updatePayload();
|
||||
|
||||
Draw.z(loaded ? Layer.blockOver + 0.2f : Layer.blockOver);
|
||||
payload.draw();
|
||||
if(effectDelayTimer <= 0){
|
||||
Draw.z(loaded ? Layer.blockOver + 0.2f : Layer.blockOver);
|
||||
payload.draw();
|
||||
}
|
||||
}
|
||||
|
||||
Draw.z(Layer.blockOver + 0.1f);
|
||||
@@ -443,12 +452,22 @@ public class PayloadMassDriver extends PayloadBlock{
|
||||
return Point2.unpack(link).sub(tile.x, tile.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte version(){
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Writes write){
|
||||
super.write(write);
|
||||
write.i(link);
|
||||
write.f(turretRotation);
|
||||
write.b((byte)state.ordinal());
|
||||
|
||||
write.f(reload);
|
||||
write.f(charge);
|
||||
write.bool(loaded);
|
||||
write.bool(charging);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -457,6 +476,13 @@ public class PayloadMassDriver extends PayloadBlock{
|
||||
link = read.i();
|
||||
turretRotation = read.f();
|
||||
state = PayloadDriverState.all[read.b()];
|
||||
|
||||
if(revision >= 1){
|
||||
reload = read.f();
|
||||
charge = read.f();
|
||||
loaded = read.bool();
|
||||
charging = read.bool();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,9 +24,11 @@ public class PayloadSource extends PayloadBlock{
|
||||
size = 3;
|
||||
update = true;
|
||||
outputsPayload = true;
|
||||
hasPower = true;
|
||||
hasPower = false;
|
||||
rotate = true;
|
||||
configurable = true;
|
||||
//make sure to display large units.
|
||||
clipSize = 120;
|
||||
|
||||
config(Block.class, (PayloadSourceBuild build, Block block) -> {
|
||||
if(canProduce(block) && build.block != block){
|
||||
@@ -45,6 +47,13 @@ public class PayloadSource extends PayloadBlock{
|
||||
build.scl = 0f;
|
||||
}
|
||||
});
|
||||
|
||||
configClear((PayloadSourceBuild build) -> {
|
||||
build.block = null;
|
||||
build.unit = null;
|
||||
build.payload = null;
|
||||
build.scl = 0f;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,6 +19,9 @@ public class PayloadVoid extends PayloadBlock{
|
||||
update = true;
|
||||
rotate = false;
|
||||
size = 3;
|
||||
payloadSpeed = 1.2f;
|
||||
//make sure to display large units.
|
||||
clipSize = 120;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,10 +4,10 @@ import arc.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.*;
|
||||
import arc.util.io.*;
|
||||
import mindustry.*;
|
||||
import mindustry.core.*;
|
||||
import mindustry.entities.EntityCollisions.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.game.EventType.*;
|
||||
@@ -69,14 +69,12 @@ public class UnitPayload implements Payload{
|
||||
//check if unit can be dumped here
|
||||
SolidPred solid = unit.solidity();
|
||||
if(solid != null){
|
||||
int tx = unit.tileX(), ty = unit.tileY();
|
||||
boolean nearEmpty = !solid.solid(tx, ty);
|
||||
for(Point2 p : Geometry.d4){
|
||||
nearEmpty |= !solid.solid(tx + p.x, ty + p.y);
|
||||
}
|
||||
Tmp.v1.trns(unit.rotation, 1f);
|
||||
|
||||
int tx = World.toTile(unit.x + Tmp.v1.x), ty = World.toTile(unit.y + Tmp.v1.y);
|
||||
|
||||
//cannot dump on solid blocks
|
||||
if(!nearEmpty) return false;
|
||||
if(solid.solid(tx, ty)) return false;
|
||||
}
|
||||
|
||||
//cannnot dump when there's a lot of overlap going on
|
||||
|
||||
@@ -49,7 +49,7 @@ public class PowerGraph{
|
||||
}
|
||||
|
||||
public float getPowerBalance(){
|
||||
return powerBalance.mean();
|
||||
return powerBalance.rawMean();
|
||||
}
|
||||
|
||||
public float getLastPowerNeeded(){
|
||||
|
||||
@@ -18,6 +18,13 @@ public class ThermalGenerator extends PowerGenerator{
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
super.init();
|
||||
//proper light clipping
|
||||
clipSize = Math.max(clipSize, 45f * size * 2f * 2f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
@@ -52,7 +59,7 @@ public class ThermalGenerator extends PowerGenerator{
|
||||
|
||||
@Override
|
||||
public void drawLight(){
|
||||
Drawf.light(team, x, y, (40f + Mathf.absin(10f, 5f)) * productionEfficiency * size, Color.scarlet, 0.4f);
|
||||
Drawf.light(team, x, y, (40f + Mathf.absin(10f, 5f)) * Math.min(productionEfficiency, 2f) * size, Color.scarlet, 0.4f);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,7 +4,6 @@ import mindustry.world.blocks.power.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
public class PowerSource extends PowerNode{
|
||||
|
||||
public float powerProduction = 10000f;
|
||||
|
||||
public PowerSource(String name){
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package mindustry.world.meta;
|
||||
|
||||
import arc.struct.*;
|
||||
import mindustry.*;
|
||||
|
||||
public class Attribute{
|
||||
public static Attribute[] all = {};
|
||||
public static ObjectMap<String, Attribute> map = new ObjectMap<>();
|
||||
|
||||
public static final Attribute
|
||||
/** Heat content. Used for thermal generator yield. */
|
||||
@@ -36,6 +38,11 @@ public class Attribute{
|
||||
return name;
|
||||
}
|
||||
|
||||
/** Never returns null, may throw an exception if not found. */
|
||||
public static Attribute get(String name){
|
||||
return map.getThrow(name, () -> new IllegalArgumentException("Unknown Attribute type: " + name));
|
||||
}
|
||||
|
||||
/** Automatically registers this attribute for use. Do not call after mod init. */
|
||||
public static Attribute add(String name){
|
||||
Attribute a = new Attribute(all.length, name);
|
||||
@@ -43,6 +50,7 @@ public class Attribute{
|
||||
all = new Attribute[all.length + 1];
|
||||
System.arraycopy(prev, 0, all, 0, a.id);
|
||||
all[a.id] = a;
|
||||
map.put(name, a);
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,15 +198,10 @@ public class StatValues{
|
||||
|
||||
table.image(region).size(60).scaling(Scaling.bounded).right().top();
|
||||
|
||||
table.table(Tex.underline, w -> {
|
||||
table.table(Tex.underline, w -> {
|
||||
w.left().defaults().padRight(3).left();
|
||||
|
||||
if(weapon.inaccuracy > 0){
|
||||
sep(w, "[lightgray]" + Stat.inaccuracy.localized() + ": [white]" + (int)weapon.inaccuracy + " " + StatUnit.degrees.localized());
|
||||
}
|
||||
sep(w, "[lightgray]" + Stat.reload.localized() + ": " + (weapon.mirror ? "2x " : "") + "[white]" + Strings.autoFixed(60f / weapon.reload * weapon.shots, 2));
|
||||
|
||||
ammo(ObjectMap.of(unit, weapon.bullet)).display(w);
|
||||
weapon.addStats(unit, w);
|
||||
}).padTop(-9).left();
|
||||
table.row();
|
||||
}
|
||||
@@ -275,10 +270,6 @@ public class StatValues{
|
||||
sep(bt, "@bullet.incendiary");
|
||||
}
|
||||
|
||||
if(type.status != StatusEffects.none){
|
||||
sep(bt, (type.minfo.mod == null ? type.status.emoji() : "") + "[stat]" + type.status.localizedName);
|
||||
}
|
||||
|
||||
if(type.homingPower > 0.01f){
|
||||
sep(bt, "@bullet.homing");
|
||||
}
|
||||
@@ -290,6 +281,10 @@ public class StatValues{
|
||||
if(type.fragBullet != null){
|
||||
sep(bt, "@bullet.frag");
|
||||
}
|
||||
|
||||
if(type.status != StatusEffects.none){
|
||||
sep(bt, (type.minfo.mod == null ? type.status.emoji() : "") + "[stat]" + type.status.localizedName);
|
||||
}
|
||||
}).padTop(unit ? 0 : -9).left().get().background(unit ? null : Tex.underline);
|
||||
|
||||
table.row();
|
||||
@@ -298,7 +293,6 @@ public class StatValues{
|
||||
}
|
||||
|
||||
//for AmmoListValue
|
||||
|
||||
private static void sep(Table table, String text){
|
||||
table.row();
|
||||
table.add(text);
|
||||
|
||||
Reference in New Issue
Block a user