This commit is contained in:
EggleEgg 2026-01-19 03:47:02 +02:00 committed by GitHub
commit b61dbea530
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 161 additions and 19 deletions

View file

@ -1089,7 +1089,7 @@ stat.buildspeedmultiplier = Build Speed Multiplier
stat.reactive = Reacts
stat.immunities = Immunities
stat.healing = Healing
stat.efficiency = [stat]{0}% Efficiency
stat.efficiency = {0}% Efficiency
ability.forcefield = Force Field
ability.forcefield.description = Projects a force shield that absorbs bullets
@ -1147,6 +1147,7 @@ bar.cargounitcap = Cargo Unit Cap Reached
bar.drillspeed = Drill Speed: {0}/s
bar.pumpspeed = Pump Speed: {0}/s
bar.efficiency = Efficiency: {0}%
bar.yield = Yield: +{0}%
bar.boost = Boost: +{0}%
bar.powerbuffer = Batteries: {0}/{1}
bar.powerbalance = Power: {0}/s

View file

@ -1090,6 +1090,7 @@ public class Blocks{
hasLiquids = false;
itemCapacity = 30;
boostScale = 0.15f;
outputScale = 0.15f;
drawer = new DrawMulti(new DrawDefault(), new DrawFlame(Color.valueOf("ffef99")));
ambientSound = Sounds.loopSmelter;
ambientSoundVolume = 0.07f;

View file

@ -1,6 +1,7 @@
package mindustry.world.blocks.production;
import arc.*;
import arc.struct.*;
import mindustry.game.*;
import mindustry.graphics.*;
import mindustry.ui.*;
@ -11,12 +12,15 @@ import mindustry.world.meta.*;
public class AttributeCrafter extends GenericCrafter{
public Attribute attribute = Attribute.heat;
public float baseEfficiency = 1f;
public float boostScale = 1f;
public float maxBoost = 1f;
public float minEfficiency = -1f;
public float displayEfficiencyScale = 1f;
public boolean displayEfficiency = true;
public boolean displayScaledOutput = true;
public boolean scaleLiquidConsumption = false;
/** Scaled output (yield) multiplier, scales with attribute. <=0 to disable. */
public float outputScale = 0f;
/** Scaled efficiency (speed) multiplier, scales with attribute. <=0 to disable. */
public float boostScale = 1f;
public AttributeCrafter(String name){
super(name);
@ -26,23 +30,39 @@ public class AttributeCrafter extends GenericCrafter{
public void drawPlace(int x, int y, int rotation, boolean valid){
super.drawPlace(x, y, rotation, valid);
if(!displayEfficiency) return;
if((!displayEfficiency || boostScale <= 0f) && (!displayScaledOutput || outputScale <= 0f)) return;
drawPlaceText(Core.bundle.format("bar.efficiency",
(int)((baseEfficiency + Math.min(maxBoost, boostScale * sumAttribute(attribute, x, y))) * 100f)), x, y, valid);
drawPlaceText(
(displayEfficiency && boostScale > 0f ?
Core.bundle.format("bar.efficiency",
(int)((baseEfficiency + Math.min(maxBoost, boostScale * sumAttribute(attribute, x, y))) * 100f))
: "") +
(displayScaledOutput && outputScale > 0f ? "\n" +
Core.bundle.format("bar.yield",
(int)(Math.min(maxBoost, outputScale * sumAttribute(attribute, x, y)) * 100f))
: ""), x, y, valid);
}
@Override
public void setBars(){
super.setBars();
if(!displayEfficiency) return;
if((!displayEfficiency || boostScale <= 0f) && (!displayScaledOutput || outputScale <= 0f)) return;
addBar("efficiency", (AttributeCrafterBuild entity) ->
if(displayEfficiency && boostScale > 0f){
addBar("efficiency", (AttributeCrafterBuild entity) ->
new Bar(
() -> Core.bundle.format("bar.efficiency", (int)(entity.efficiencyMultiplier() * 100 * displayEfficiencyScale)),
() -> Core.bundle.format("bar.efficiency", (int)(entity.efficiencyMultiplier() * 100)),
() -> Pal.lightOrange,
entity::efficiencyMultiplier));
}
if(displayScaledOutput && outputScale > 0f){
addBar("yield", (AttributeCrafterBuild entity) ->
new Bar(
() -> Core.bundle.format("bar.yield", (int)((entity.outputMultiplier() - baseEfficiency) * 100)),
() -> Pal.lightOrange,
entity::outputMultiplier));
}
}
@Override
@ -54,18 +74,29 @@ public class AttributeCrafter extends GenericCrafter{
@Override
public void setStats(){
super.setStats();
stats.add(baseEfficiency <= 0.0001f ? Stat.tiles : Stat.affinities, attribute, floating, boostScale * size * size, !displayEfficiency);
if(outputScale > 0f){
stats.add(baseEfficiency <= 0.0001f ? Stat.tiles :
Stat.affinities, attribute, floating, boostScale * size * size, outputScale * size * size, Seq.with(outputItems), craftTime, !displayEfficiency);
}else{
stats.add(baseEfficiency <= 0.0001f ? Stat.tiles : Stat.affinities, attribute, floating, boostScale * size * size, !displayEfficiency);
}
}
public class AttributeCrafterBuild extends GenericCrafterBuild{
public float attrsum;
public float accumulator;
public float scaledOutput;
public int scaledInt;
@Override
public float getProgressIncrease(float base){
return super.getProgressIncrease(base) * efficiencyMultiplier();
}
public float outputMultiplier(){
return baseEfficiency + Math.min(maxBoost, outputScale * attrsum) + attribute.env();
}
public float efficiencyMultiplier(){
return baseEfficiency + Math.min(maxBoost, boostScale * attrsum) + attribute.env();
}
@ -75,6 +106,23 @@ public class AttributeCrafter extends GenericCrafter{
return scaleLiquidConsumption ? efficiencyMultiplier() : super.efficiencyScale();
}
@Override
public float scaleOutput(float amount, boolean item, boolean accumulate){
scaledOutput = amount * outputMultiplier();
if(item){
if(accumulate){
accumulator += scaledOutput;
scaledInt = (int)(accumulator);
accumulator -= scaledInt;
}else{
scaledInt = (int)(accumulator + scaledOutput);
}
}
return outputScale > 0f ? Math.min(itemCapacity, scaledInt) : amount;
}
@Override
public void pickedUp(){
attrsum = 0f;

View file

@ -193,7 +193,7 @@ public class GenericCrafter extends Block{
public boolean shouldConsume(){
if(outputItems != null){
for(var output : outputItems){
if(items.get(output.item) + output.amount > itemCapacity){
if(items.get(output.item) + scaleOutput(output.amount, true, false) > itemCapacity){
return false;
}
}
@ -263,7 +263,7 @@ public class GenericCrafter extends Block{
if(outputLiquids != null){
max = 0f;
for(var s : outputLiquids){
float value = (liquidCapacity - liquids.get(s.liquid)) / (s.amount * edelta());
float value = (liquidCapacity - liquids.get(s.liquid)) / (scaleOutput(s.amount) * edelta());
scaling = Math.min(scaling, value);
max = Math.max(max, value);
}
@ -287,12 +287,21 @@ public class GenericCrafter extends Block{
return totalProgress;
}
public float scaleOutput(float amount){
return scaleOutput(amount, false, false);
}
public float scaleOutput(float amount, boolean item, boolean accumulate){
return amount;
}
public void craft(){
consume();
if(outputItems != null){
for(var output : outputItems){
for(int i = 0; i < output.amount; i++){
float maxOutput = scaleOutput(output.amount, true, true);
for(int i = 0; i < maxOutput; i++){
offload(output.item);
}
}

View file

@ -225,7 +225,7 @@ public class StatValues{
}
/** Displays an item with a specified amount. */
private static Stack stack(TextureRegion region, int amount, @Nullable UnlockableContent content, boolean tooltip){
private static Stack stack(TextureRegion region, float amount, @Nullable UnlockableContent content, boolean tooltip){
Stack stack = new Stack();
stack.add(new Table(o -> {
@ -236,7 +236,7 @@ public class StatValues{
if(amount != 0){
stack.add(new Table(t -> {
t.left().bottom();
t.add(amount >= 1000 ? UI.formatAmount(amount) : amount + "").style(Styles.outlineLabel);
t.add(amount >= 1000 ? UI.formatAmount((int)amount) : fixValue(amount)).style(Styles.outlineLabel);
t.pack();
}));
}
@ -259,7 +259,7 @@ public class StatValues{
return stack(item.uiIcon, amount, item);
}
public static Stack stack(UnlockableContent item, int amount, boolean tooltip){
public static Stack stack(UnlockableContent item, float amount, boolean tooltip){
return stack(item.uiIcon, amount, item, tooltip);
}
@ -294,6 +294,13 @@ public class StatValues{
return t;
}
public static Table displayItem(Item item, float amount, float timePeriod, boolean showName){
Table t = new Table();
t.add(stack(item, amount, !showName));
t.add((showName ? item.localizedName + "\n" : "") + "[lightgray]" + Strings.autoFixed(amount / (timePeriod / 60f), 3) + StatUnit.perSecond.localized()).padLeft(8).padRight(5).style(Styles.outlineLabel);
return t;
}
/** Displays the item with a "/sec" qualifier based on the time period, in ticks. */
public static Table displayItemPercent(Item item, int percent, boolean showName){
Table t = new Table();
@ -320,6 +327,10 @@ public class StatValues{
return blocks(attr, floating, scale, startZero, true);
}
public static StatValue blocks(Attribute attr, boolean floating, float scale1, float scale2, @Nullable Seq<ItemStack> outputs, float timePeriod, boolean startZero){
return blocks(attr, floating, scale1, scale2, outputs, timePeriod, startZero, true);
}
public static StatValue blocks(Attribute attr, boolean floating, float scale, boolean startZero, boolean checkFloors){
return table -> table.table(c -> {
Runnable[] rebuild = {null};
@ -364,6 +375,74 @@ public class StatValues{
});
});
}
public static StatValue blocks(Attribute attr, boolean floating, float scaleEff, float scaleAmount, @Nullable Seq<ItemStack> outputs, float timePeriod, boolean startZero, boolean checkFloors) {
return table -> {
if(table.getCells().size > 0) table.getCells().peek().growX();
table.row();
table.table(c -> {
Runnable[] rebuild = {null};
Map[] lastMap = {null};
rebuild[0] = () -> {
c.clearChildren();
c.left();
if(state.isGame()){
var blocks = Vars.content.blocks()
.select(block -> (!checkFloors || block instanceof Floor) && indexer.isBlockPresent(block) && block.attributes.get(attr) != 0 && !((block instanceof Floor f && f.isDeep()) && !floating))
.with(s -> s.sort(f -> f.attributes.get(attr)));
if(blocks.any()){
for(var block : blocks){
c.table(Styles.grayPanel, b -> {
float effiency = 1f + block.attributes.get(attr) * scaleEff;
b.image(block.uiIcon).size(40f).pad(10f).left().scaling(Scaling.fit);
b.table(center -> {
center.left();
if(outputs != null && outputs.any()){
for(ItemStack output : outputs){
float scaled = output.amount * (1f + block.attributes.get(attr) * scaleAmount);
center.table(it -> {
it.left();
it.add(displayItem(output.item, scaled, timePeriod / effiency , true)).left().padLeft(6f);
}).padRight(8f);
}
}else{
center.add("@none");
}
}).left().grow();
b.add((effiency < 1f ? "[negstat]" : "[stat]") + Core.bundle.format("stat.efficiency", fixValue(effiency * 100f))).right().pad(10f).padRight(15f);
}).growX().pad(5).row();
}
}else{
c.add("@none.inmap");
}
}else{
c.add("@stat.showinmap");
}
};
rebuild[0].run();
//rebuild when map changes.
c.update(() -> {
Map current = state.isGame() ? state.map : null;
if(current != lastMap[0]){
rebuild[0].run();
lastMap[0] = current;
}
});
}).growX().colspan(table.getColumns()).row();
};
}
public static StatValue content(Seq<UnlockableContent> list){
return content(list, i -> true);
}
@ -479,7 +558,7 @@ public class StatValues{
c.table(Styles.grayPanel, b -> {
b.image(item.uiIcon).size(40).pad(10f).left().scaling(Scaling.fit);
b.add(item.localizedName + (timePeriod > 0 ? "\n[lightgray]" + Strings.autoFixed(time, time < 0.01f ? 4 : 2) + StatUnit.perSecond.localized() : "")).left().grow();
b.add(Core.bundle.format("stat.efficiency", fixValue(efficiency.get(item) * 100f))).right().pad(10f).padRight(15f);
b.add("[stat]" + Core.bundle.format("stat.efficiency", fixValue(efficiency.get(item) * 100f))).right().pad(10f).padRight(15f);
}).growX().pad(5).row();
}
}).growX().colspan(table.getColumns()).row();
@ -494,7 +573,7 @@ public class StatValues{
for(Liquid liquid : content.liquids().select(l -> filter.get(l) && l.unlockedNow() && !l.isHidden())){
c.table(Styles.grayPanel, b -> {
b.add(displayLiquid(liquid, amount, true)).pad(10f).left().grow();
b.add(Core.bundle.format("stat.efficiency", fixValue(efficiency.get(liquid) * 100f))).right().pad(10f).padRight(15f);
b.add("[stat]" + Core.bundle.format("stat.efficiency", fixValue(efficiency.get(liquid) * 100f))).right().pad(10f).padRight(15f);
}).growX().pad(5).row();
}
}).growX().colspan(table.getColumns()).row();

View file

@ -80,6 +80,10 @@ public class Stats{
add(stat, StatValues.blocks(attr, floating, scale, startZero));
}
public void add(Stat stat, Attribute attr, boolean floating, float scale1, float scale2, @Nullable Seq<ItemStack> outputs, float timePeriod, boolean startZero){
add(stat, StatValues.blocks(attr, floating, scale1, scale2, outputs, timePeriod, startZero));
}
/** Adds a single string value with this stat. */
public void add(Stat stat, String format, Object... args){
add(stat, StatValues.string(format, args));