Merge remote-tracking branch 'origin/master'

This commit is contained in:
Anuken
2024-03-30 09:53:15 -04:00
62 changed files with 2515 additions and 1361 deletions

View File

@@ -3895,7 +3895,7 @@ public class UnitTypes{
x = 43f * i / 4f;
particles = parts;
//visual only, the middle one does the actual suppressing
display = active = false;
active = false;
}});
}

View File

@@ -6,6 +6,7 @@ import mindustry.gen.*;
import mindustry.type.*;
public abstract class Ability implements Cloneable{
protected static final float descriptionWidth = 350f;
/** If false, this ability does not show in unit stats. */
public boolean display = true;
//the one and only data variable that is synced.
@@ -16,7 +17,16 @@ public abstract class Ability implements Cloneable{
public void death(Unit unit){}
public void init(UnitType type){}
public void displayBars(Unit unit, Table bars){}
public void addStats(Table t){}
public void addStats(Table t){
if(Core.bundle.has(getBundle() + ".description")){
t.add(Core.bundle.get(getBundle() + ".description")).wrap().width(descriptionWidth);
t.row();
}
}
public String abilityStat(String stat, Object... values){
return Core.bundle.format("ability.stat." + stat, values);
}
public Ability copy(){
try{
@@ -29,7 +39,11 @@ public abstract class Ability implements Cloneable{
/** @return localized ability name; mods should override this. */
public String localized(){
return Core.bundle.get(getBundle());
}
public String getBundle(){
var type = getClass();
return Core.bundle.get("ability." + (type.isAnonymousClass() ? type.getSuperclass() : type).getSimpleName().replace("Ability", "").toLowerCase());
return "ability." + (type.isAnonymousClass() ? type.getSuperclass() : type).getSimpleName().replace("Ability", "").toLowerCase();
}
}

View File

@@ -4,11 +4,10 @@ import arc.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.scene.ui.layout.Table;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.world.meta.*;
public class ArmorPlateAbility extends Ability{
public TextureRegion plateRegion;
@@ -39,7 +38,8 @@ public class ArmorPlateAbility extends Ability{
@Override
public void addStats(Table t){
t.add("[lightgray]" + Stat.healthMultiplier.localized() + ": [white]" + Math.round(healthMultiplier * 100f) + 100 + "%");
super.addStats(t);
t.add(abilityStat("damagereduction", Strings.autoFixed(-healthMultiplier * 100f, 1)));
}
@Override

View File

@@ -14,7 +14,6 @@ import mindustry.game.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.world.meta.*;
import static mindustry.Vars.*;
@@ -53,23 +52,29 @@ public class EnergyFieldAbility extends Ability{
@Override
public void addStats(Table t){
t.add(Core.bundle.format("bullet.damage", damage));
if(displayHeal){
t.add(Core.bundle.get(getBundle() + ".healdescription")).wrap().width(descriptionWidth);
}else{
t.add(Core.bundle.get(getBundle() + ".description")).wrap().width(descriptionWidth);
}
t.row();
t.add("[lightgray]" + Stat.reload.localized() + ": [white]" + Strings.autoFixed(60f / reload, 2) + " " + StatUnit.perSecond.localized());
t.row();
t.add("[lightgray]" + Stat.shootRange.localized() + ": [white]" + Strings.autoFixed(range / tilesize, 2) + " " + StatUnit.blocks.localized());
t.row();
t.add(Core.bundle.format("ability.energyfield.maxtargets", maxTargets));
t.add(Core.bundle.format("bullet.range", Strings.autoFixed(range / tilesize, 2)));
t.row();
t.add(abilityStat("firingrate", Strings.autoFixed(60f / reload, 2)));
t.row();
t.add(abilityStat("maxtargets", maxTargets));
t.row();
t.add(Core.bundle.format("bullet.damage", damage));
if(status != StatusEffects.none){
t.row();
t.add((status.hasEmoji() ? status.emoji() : "") + "[stat]" + status.localizedName);
}
if(displayHeal){
t.row();
t.add(Core.bundle.format("bullet.healpercent", Strings.autoFixed(healPercent, 2)));
t.row();
t.add(Core.bundle.format("ability.energyfield.sametypehealmultiplier", Math.round(sameTypeHealMult * 100f)));
}
if(status != StatusEffects.none){
t.row();
t.add(status.emoji() + " " + status.localizedName);
t.add(abilityStat("sametypehealmultiplier", (sameTypeHealMult < 1f ? "[negstat]" : "") + Strings.autoFixed(sameTypeHealMult * 100f, 2)));
}
}

View File

@@ -1,5 +1,6 @@
package mindustry.entities.abilities;
import arc.*;
import arc.func.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
@@ -12,7 +13,6 @@ import mindustry.content.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.ui.*;
import mindustry.world.meta.*;
import static mindustry.Vars.*;
@@ -73,14 +73,14 @@ public class ForceFieldAbility extends Ability{
@Override
public void addStats(Table t){
t.add("[lightgray]" + Stat.health.localized() + ": [white]" + Math.round(max));
super.addStats(t);
t.add(Core.bundle.format("bullet.range", Strings.autoFixed(radius / tilesize, 2)));
t.row();
t.add("[lightgray]" + Stat.shootRange.localized() + ": [white]" + Strings.autoFixed(radius / tilesize, 2) + " " + StatUnit.blocks.localized());
t.add(abilityStat("shield", Strings.autoFixed(max, 2)));
t.row();
t.add("[lightgray]" + Stat.repairSpeed.localized() + ": [white]" + Strings.autoFixed(regen * 60f, 2) + StatUnit.perSecond.localized());
t.row();
t.add("[lightgray]" + Stat.cooldownTime.localized() + ": [white]" + Strings.autoFixed(cooldown / 60f, 2) + " " + StatUnit.seconds.localized());
t.add(abilityStat("repairspeed", Strings.autoFixed(regen * 60f, 2)));
t.row();
t.add(abilityStat("cooldown", Strings.autoFixed(cooldown / 60f, 2)));
}
@Override

View File

@@ -1,6 +1,7 @@
package mindustry.entities.abilities;
import arc.math.*;
import arc.scene.ui.layout.*;
import arc.util.noise.*;
import mindustry.content.*;
import mindustry.entities.*;
@@ -16,6 +17,12 @@ public class LiquidExplodeAbility extends Ability{
public float radAmountScale = 5f, radScale = 1f;
public float noiseMag = 6.5f, noiseScl = 5f;
@Override
public void addStats(Table t){
super.addStats(t);
t.add((liquid.hasEmoji() ? liquid.emoji() : "") + "[stat]" + liquid.localizedName);
}
@Override
public void death(Unit unit){
//TODO what if noise is radial, so it looks like a splat?

View File

@@ -1,6 +1,7 @@
package mindustry.entities.abilities;
import arc.math.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.entities.*;
@@ -17,6 +18,14 @@ public class LiquidRegenAbility extends Ability{
public float slurpEffectChance = 0.4f;
public Effect slurpEffect = Fx.heal;
@Override
public void addStats(Table t){
super.addStats(t);
t.add((liquid.hasEmoji() ? liquid.emoji() : "") + "[stat]" + liquid.localizedName);
t.row();
t.add(abilityStat("slurpheal", Strings.autoFixed(regenPerSlurp, 2)));
}
@Override
public void update(Unit unit){
//TODO timer?

View File

@@ -5,12 +5,15 @@ import arc.audio.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.bullet.*;
import mindustry.gen.*;
import static mindustry.Vars.*;
public class MoveLightningAbility extends Ability{
/** Lightning damage */
public float damage = 35f;
@@ -63,7 +66,15 @@ public class MoveLightningAbility extends Ability{
this.maxSpeed = maxSpeed;
this.color = color;
}
@Override
public void addStats(Table t){
super.addStats(t);
t.add(abilityStat("minspeed", Strings.autoFixed(minSpeed * 60f / tilesize, 2)));
t.row();
t.add(Core.bundle.format("bullet.damage", damage));
}
@Override
public void update(Unit unit){
float scl = Mathf.clamp((unit.vel().len() - minSpeed) / (maxSpeed - minSpeed));

View File

@@ -1,10 +1,8 @@
package mindustry.entities.abilities;
import arc.Core;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.gen.*;
import mindustry.world.meta.*;
public class RegenAbility extends Ability{
/** Amount healed as percent per tick. */
@@ -14,13 +12,16 @@ public class RegenAbility extends Ability{
@Override
public void addStats(Table t){
if(amount > 0.01f){
t.add("[lightgray]" + Stat.repairSpeed.localized() + ": [white]" + Strings.autoFixed(amount * 60f, 2) + StatUnit.perSecond.localized());
t.row();
}
super.addStats(t);
if(percentAmount > 0.01f){
t.add(Core.bundle.format("bullet.healpercent", Strings.autoFixed(percentAmount * 60f, 2)) + StatUnit.perSecond.localized()); //stupid but works
boolean flat = amount >= 0.001f;
boolean percent = percentAmount >= 0.001f;
if(flat || percent){
t.add(abilityStat("regen",
(flat ? Strings.autoFixed(amount * 60f, 2) + (percent ? " [lightgray]+[stat] " : "") : "")
+ (percent ? Strings.autoFixed(percentAmount * 60f, 2) + "%" : "")
));
}
}

View File

@@ -1,13 +1,13 @@
package mindustry.entities.abilities;
import arc.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.gen.*;
import mindustry.world.meta.*;
import static mindustry.Vars.tilesize;
import static mindustry.Vars.*;
public class RepairFieldAbility extends Ability{
public float amount = 1, reload = 100, range = 60;
@@ -28,9 +28,10 @@ public class RepairFieldAbility extends Ability{
@Override
public void addStats(Table t){
t.add("[lightgray]" + Stat.repairSpeed.localized() + ": [white]" + Strings.autoFixed(amount * 60f / reload, 2) + StatUnit.perSecond.localized());
super.addStats(t);
t.add(Core.bundle.format("bullet.range", Strings.autoFixed(range / tilesize, 2)));
t.row();
t.add("[lightgray]" + Stat.shootRange.localized() + ": [white]" + Strings.autoFixed(range / tilesize, 2) + " " + StatUnit.blocks.localized());
t.add(abilityStat("repairspeed", Strings.autoFixed(amount * 60f / reload, 2)));
}
@Override

View File

@@ -13,7 +13,6 @@ import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.meta.*;
public class ShieldArcAbility extends Ability{
private static Unit paramUnit;
@@ -69,12 +68,12 @@ public class ShieldArcAbility extends Ability{
@Override
public void addStats(Table t){
t.add("[lightgray]" + Stat.health.localized() + ": [white]" + Math.round(max));
super.addStats(t);
t.add(abilityStat("shield", Strings.autoFixed(max, 2)));
t.row();
t.add("[lightgray]" + Stat.repairSpeed.localized() + ": [white]" + Strings.autoFixed(regen * 60f, 2) + StatUnit.perSecond.localized());
t.row();
t.add("[lightgray]" + Stat.cooldownTime.localized() + ": [white]" + Strings.autoFixed(cooldown / 60f, 2) + " " + StatUnit.seconds.localized());
t.add(abilityStat("repairspeed", Strings.autoFixed(regen * 60f, 2)));
t.row();
t.add(abilityStat("cooldown", Strings.autoFixed(cooldown / 60f, 2)));
}
@Override

View File

@@ -1,14 +1,13 @@
package mindustry.entities.abilities;
import arc.Core;
import arc.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.gen.*;
import mindustry.world.meta.*;
import static mindustry.Vars.tilesize;
import static mindustry.Vars.*;
public class ShieldRegenFieldAbility extends Ability{
public float amount = 1, max = 100f, reload = 100, range = 60;
@@ -30,12 +29,12 @@ public class ShieldRegenFieldAbility extends Ability{
@Override
public void addStats(Table t){
t.add("[lightgray]" + Core.bundle.get("waves.shields") + ": [white]" + Math.round(max)); //extremely stupid usage
super.addStats(t);
t.add(Core.bundle.format("bullet.range", Strings.autoFixed(range / tilesize, 2)));
t.row();
t.add("[lightgray]" + Stat.shootRange.localized() + ": [white]" + Strings.autoFixed(range / tilesize, 2) + " " + StatUnit.blocks.localized());
t.row();
t.add("[lightgray]" + Stat.reload.localized() + ": [white]" + Strings.autoFixed(60f / reload, 2) + " " + StatUnit.perSecond.localized());
t.add(abilityStat("firingrate", Strings.autoFixed(60f / reload, 2)));
t.row();
t.add(abilityStat("shield", Strings.autoFixed(max, 2)));
}
@Override

View File

@@ -27,7 +27,8 @@ public class SpawnDeathAbility extends Ability{
@Override
public void addStats(Table t){
t.add((randAmount > 0 ? amount + "-" + (amount + randAmount) : amount) + " " + unit.emoji() + " " + unit.localizedName);
super.addStats(t);
t.add("[stat]" + (randAmount > 0 ? amount + "x-" + (amount + randAmount) : amount) + "x[] " + (unit.hasEmoji() ? unit.emoji() : "") + "[stat]" + unit.localizedName);
}
@Override

View File

@@ -1,15 +1,15 @@
package mindustry.entities.abilities;
import arc.*;
import arc.math.*;
import arc.scene.ui.layout.Table;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.gen.*;
import mindustry.type.*;
import mindustry.world.meta.*;
import static mindustry.Vars.tilesize;
import static mindustry.Vars.*;
public class StatusFieldAbility extends Ability{
public StatusEffect effect;
@@ -33,11 +33,12 @@ public class StatusFieldAbility extends Ability{
@Override
public void addStats(Table t){
t.add("[lightgray]" + Stat.reload.localized() + ": [white]" + Strings.autoFixed(60f / reload, 2) + " " + StatUnit.perSecond.localized());
super.addStats(t);
t.add(Core.bundle.format("bullet.range", Strings.autoFixed(range / tilesize, 2)));
t.row();
t.add("[lightgray]" + Stat.shootRange.localized() + ": [white]" + Strings.autoFixed(range / tilesize, 2) + " " + StatUnit.blocks.localized());
t.add(abilityStat("firingrate", Strings.autoFixed(60f / reload, 2)));
t.row();
t.add(effect.emoji() + " " + effect.localizedName);
t.add((effect.hasEmoji() ? effect.emoji() : "") + "[stat]" + effect.localizedName);
}
@Override

View File

@@ -1,12 +1,17 @@
package mindustry.entities.abilities;
import arc.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.entities.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
import static mindustry.Vars.*;
public class SuppressionFieldAbility extends Ability{
protected static Rand rand = new Rand();
@@ -33,6 +38,19 @@ public class SuppressionFieldAbility extends Ability{
protected float timer;
@Override
public void init(UnitType type){
if(!active) display = false;
}
@Override
public void addStats(Table t){
super.addStats(t);
t.add(Core.bundle.format("bullet.range", Strings.autoFixed(range / tilesize, 2)));
t.row();
t.add(abilityStat("duration", Strings.autoFixed(reload / 60f, 2)));
}
@Override
public void update(Unit unit){
if(!active) return;

View File

@@ -12,7 +12,6 @@ import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.world.meta.*;
import static mindustry.Vars.*;
@@ -36,9 +35,10 @@ public class UnitSpawnAbility extends Ability{
@Override
public void addStats(Table t){
t.add("[lightgray]" + Stat.buildTime.localized() + ": [white]" + Strings.autoFixed(spawnTime / 60f, 2) + " " + StatUnit.seconds.localized());
super.addStats(t);
t.add(abilityStat("buildtime", Strings.autoFixed(spawnTime / 60f, 2)));
t.row();
t.add(unit.emoji() + " " + unit.localizedName);
t.add((unit.hasEmoji() ? unit.emoji() : "") + "[stat]" + unit.localizedName);
}
@Override

View File

@@ -176,6 +176,8 @@ public class BulletType extends Content implements Cloneable{
public float fragLifeMin = 1f, fragLifeMax = 1f;
/** Random offset of frag bullets from the parent bullet. */
public float fragOffsetMin = 1f, fragOffsetMax = 7f;
/** How many times this bullet can release frag bullets, if pierce = true. */
public int pierceFragCap = -1;
/** Bullet that is created at a fixed interval. */
public @Nullable BulletType intervalBullet;
@@ -509,12 +511,13 @@ public class BulletType extends Content implements Cloneable{
}
public void createFrags(Bullet b, float x, float y){
if(fragBullet != null && (fragOnAbsorb || !b.absorbed)){
if(fragBullet != null && (fragOnAbsorb || !b.absorbed) && !(b.frags >= pierceFragCap && pierceFragCap > 0)){
for(int i = 0; i < fragBullets; i++){
float len = Mathf.random(fragOffsetMin, fragOffsetMax);
float a = b.rotation() + Mathf.range(fragRandomSpread / 2) + fragAngle + ((i - fragBullets/2) * fragSpread);
fragBullet.create(b, x + Angles.trnsx(a, len), y + Angles.trnsy(a, len), a, Mathf.random(fragVelocityMin, fragVelocityMax), Mathf.random(fragLifeMin, fragLifeMax));
}
b.frags++;
}
}

View File

@@ -45,6 +45,7 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
transient @Nullable Mover mover;
transient boolean absorbed, hit;
transient @Nullable Trail trail;
transient int frags;
@Override
public void getCollisions(Cons<QuadTree> consumer){

View File

@@ -60,6 +60,11 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{
}
}
@Override
public void destroy(){
if(Vars.state.rules.unitPayloadsExplode) payloads.each(Payload::destroyed);
}
float payloadUsed(){
return payloads.sumf(p -> p.size() * p.size());
}

View File

@@ -59,6 +59,8 @@ public class Rules{
public boolean unitAmmo = false;
/** EXPERIMENTAL! If true, blocks will update in units and share power. */
public boolean unitPayloadUpdate = false;
/** If true, units' payloads are destroy()ed when the unit is destroyed. */
public boolean unitPayloadsExplode = false;
/** Whether cores add to unit limit */
public boolean unitCapVariable = true;
/** If true, unit spawn points are shown. */

View File

@@ -233,6 +233,7 @@ public class CustomRulesDialog extends BaseDialog{
title("@rules.title.unit");
check("@rules.unitcapvariable", b -> rules.unitCapVariable = b, () -> rules.unitCapVariable);
check("@rules.unitpayloadsexplode", b -> rules.unitPayloadsExplode = b, () -> rules.unitPayloadsExplode);
numberi("@rules.unitcap", f -> rules.unitCap = f, () -> rules.unitCap, -999, 999);
number("@rules.unitdamagemultiplier", f -> rules.unitDamageMultiplier = f, () -> rules.unitDamageMultiplier);
number("@rules.unitcrashdamagemultiplier", f -> rules.unitCrashDamageMultiplier = f, () -> rules.unitCrashDamageMultiplier);

View File

@@ -51,6 +51,11 @@ public class BuildPayload implements Payload{
build.updatePayload(unitHolder, buildingHolder);
}
@Override
public void destroyed(){
build.onDestroyed();
}
@Override
public ItemStack[] requirements(){
return build.block.requirements;

View File

@@ -54,6 +54,8 @@ public interface Payload extends Position{
return 0f;
}
default void destroyed(){};
/** writes the payload for saving. */
void write(Writes write);

View File

@@ -151,6 +151,12 @@ public class PayloadBlock extends Block{
}
}
@Override
public void onDestroyed(){
if(payload != null) payload.destroyed();
super.onDestroyed();
}
public boolean blends(int direction){
return PayloadBlock.blends(this, direction);
}

View File

@@ -190,6 +190,12 @@ public class PayloadConveyor extends Block{
super.draw();
}
@Override
public void onDestroyed(){
if(item != null) item.destroyed();
super.onDestroyed();
}
@Override
public void draw(){
super.draw();

View File

@@ -374,17 +374,23 @@ public class StatValues{
public static StatValue abilities(Seq<Ability> abilities){
return table -> {
table.row();
table.table(t -> abilities.each(ability -> {
if(ability.display){
t.row();
t.table(Styles.grayPanel, a -> {
a.add("[accent]" + ability.localized()).padBottom(4);
a.row();
a.left().top().defaults().left();
ability.addStats(a);
}).pad(5).margin(10).growX();
}
}));
table.table(t -> {
int count = 0;
for(Ability ability : abilities){
if(ability.display){
t.table(Styles.grayPanel, a -> {
a.add("[accent]" + ability.localized()).padBottom(4).center().top().expandX();
a.row();
a.left().top().defaults().left();
ability.addStats(a);
}).pad(5).margin(10).growX().top().uniformX();
if((++count) == 2){
count = 0;
t.row();
}
}
};
});
};
}
@@ -496,7 +502,7 @@ public class StatValues{
}
if(type.status != StatusEffects.none){
sep(bt, (type.status.minfo.mod == null ? type.status.emoji() : "") + "[stat]" + type.status.localizedName + (type.status.reactive ? "" : "[lightgray] ~ [stat]" + ((int)(type.statusDuration / 60f)) + "[lightgray] " + Core.bundle.get("unit.seconds")));
sep(bt, (type.status.hasEmoji() ? type.status.emoji() : "") + "[stat]" + type.status.localizedName + (type.status.reactive ? "" : "[lightgray] ~ [stat]" + ((int)(type.statusDuration / 60f)) + "[lightgray] " + Core.bundle.get("unit.seconds")));
}
if(type.intervalBullet != null){
@@ -554,4 +560,4 @@ public class StatValues{
private static TextureRegion icon(UnlockableContent t){
return t.uiIcon;
}
}
}