New efficiency system as consValid replacement

This commit is contained in:
Anuken
2022-02-22 21:39:53 -05:00
parent 2bd892d880
commit fe0e6ed6da
51 changed files with 141 additions and 252 deletions

View File

@@ -74,12 +74,17 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
transient float visualLiquid;
//TODO save efficiency too!
transient boolean consValid;
//transient boolean consValid;
@Nullable PowerModule power;
@Nullable ItemModule items;
@Nullable LiquidModule liquids;
/** Base efficiency. Takes the minimum value of all consumers. */
transient float efficiency = 1f;
/** Same as efficiency, but for optional consumers only. */
transient float optionalEfficiency = 1f;
public transient float healSuppressionTime = -1f;
public transient float lastHealTime = -120f * 10f;
@@ -169,7 +174,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
if(items != null) items.write(write);
if(power != null) power.write(write);
if(liquids != null) liquids.write(write);
write.bool(consValid);
write.bool(false);
}
public final void readBase(Reads read){
@@ -183,6 +188,9 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
int moduleBits = moduleBitmask();
boolean legacy = true;
//TODO new version with efficiency instead of consValid
//new version
if((rot & 0b10000000) != 0){
byte ver = read.b(); //version of entity save
if(ver >= 1){
@@ -203,7 +211,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
if((moduleBits & 1) != 0) (items == null ? new ItemModule() : items).read(read, legacy);
if((moduleBits & 2) != 0) (power == null ? new PowerModule() : power).read(read, legacy);
if((moduleBits & 4) != 0) (liquids == null ? new LiquidModule() : liquids).read(read, legacy);
if((moduleBits & 8) != 0) consValid = read.bool();
if((moduleBits & 8) != 0) read.bool();
}
public int moduleBitmask(){
@@ -490,7 +498,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
return BlockStatus.noOutput;
}
if(!consValid || !productionValid()){
if(efficiency <= 0 || !productionValid()){
return BlockStatus.noInput;
}
@@ -1585,11 +1593,6 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}
}
//TODO remove
public float efficiency(){
return efficiency;
}
//TODO probably should not have a shouldConsume() check? should you even *use* consValid?
public void consume(){
@@ -1599,7 +1602,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}
public boolean canConsume(){
return consValid && enabled;
return efficiency > 0;
}
/** Scaled delta. */
@@ -1613,142 +1616,62 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}
//TODO save/load this, new building version
/** Base efficiency. If this entity has non-buffered power, returns the power %, otherwise returns 1. */
private transient float efficiency = 1f;
//why?
transient float efficiencyMultiplier = 1f;
//TODO remove?
@Deprecated
private transient boolean consOptionalValid = false;
@Deprecated
public boolean consOptionalValid(){
return consValid && consOptionalValid;
}
//TODO unit tests:
//- 50% power efficiency -> 50% liquid consumption
//- 50% liquid consumption -> other liquid or item consumer runs at 50% efficiency
//- same as above but with overdrive and timeScale = 2 and differing delta values
/*
SCENARIOS:
1.
- liquid at 50% satisfied
- liquid at 100% satisfied
- item at 100% satisfied
result:
- efficiency = 50%
- all consumers should consume at 50%
2.
- liquid at 50% satisfied
- power at 100% satisfied
result:
- efficiency = 50%
- power will still consume 100% - SHOULD IT?
3.
- liquid at 50% satisfied
- item at 200% satisfied (boosted)
result: ???
4.
- item at 200% satisfied
- liquid at 200% satisfied
result:
- 200% efficiency (why?)
- will consume at *normal rate*
5.
- item at 200% satisfied
- liquid at 100% satisfied (required, no boost)
result:
- averaging efficiency would lead to 150%, but this is WRONG. it should be 200% - how?
6.
- item at 200%
- liquid at 50%
result:
- 100% efficiency (2 * 0.5)
- consumption of liquid at 50% (how?)
- ...but consumption of item at 100% rate (how?)
*/
//TODO test with overdraw, e.g. requesting 20/frame on a block with only 10 capacity
//- should lead to 50% efficiency, for example - make sure all blocks have, at minimum, 10x their capacity per frame - should last for a second at least
/** Called after efficiency is updated but before consumers are updated. Use to apply your own multiplier. */
public void updateEfficiencyMultiplier(){
}
public void updateConsumption(){
//everything is valid when cheating
if(cheating() || !block.hasConsumers){
consValid = true;
consOptionalValid = true;
if(!block.hasConsumers || cheating()){
efficiency = optionalEfficiency = 1f;
return;
}
//disabled -> nothing works
if(!enabled){
efficiency = 0f;
consValid = consOptionalValid = false;
efficiency = optionalEfficiency = 0f;
return;
}
boolean prevValid = consValid;
consValid = true;
//consOptionalValid = true;
boolean docons = shouldConsume() && productionValid();
//TODO why check for old state?
boolean prevValid = efficiency > 0, update = shouldConsume() && productionValid();
float minEfficiency = 1f;
var nonOptional = block.nonOptionalConsumers;
//assume efficiency is 1 for the calculations below
efficiency = 1f;
//average
efficiency = optionalEfficiency = 1f;
//first pass: get the minimum efficiency of any consumer
for(var cons : nonOptional){
for(var cons : block.nonOptionalConsumers){
minEfficiency = Math.min(minEfficiency, cons.efficiency(self()));
//consValid &= cons.valid(self());
}
efficiencyMultiplier = 1f;
updateEfficiencyMultiplier();
//same for optionals
for(var cons : block.optionalConsumers){
optionalEfficiency = Math.min(optionalEfficiency, cons.efficiency(self()));
}
//efficiency is now this minimum value
efficiency = minEfficiency;
consValid = efficiency > 0;
optionalEfficiency = Math.min(optionalEfficiency, minEfficiency);
updateEfficiencyMultiplier();
//second pass: update every consumer based on efficiency
//TODO item consumption fraction array
if(docons && prevValid && minEfficiency > 0){
for(var cons : nonOptional){
//TODO different array for update = true?
if(cons.update){
cons.update(self());
}
}
}
//TODO optionals
/*
for(Consume cons : block.optionalConsumers){
if(docons && cons.update && prevValid && cons.valid(self())){
if(update && prevValid && efficiency > 0){
for(var cons : block.updateConsumers){
cons.update(self());
}
consOptionalValid &= cons.valid(self());
}*/
}
}
public void updateTile(){

View File

@@ -196,7 +196,7 @@ public class SectorInfo{
var pads = indexer.getFlagged(state.rules.defaultTeam, BlockFlag.launchPad);
//disable export when launch pads are disabled, or there aren't any active ones
if(pads.size == 0 || !pads.contains(t -> t.consValid)){
if(pads.size == 0 || !pads.contains(t -> t.efficiency > 0)){
export.clear();
}

View File

@@ -295,8 +295,8 @@ public class SectorDamage{
}
//point defense turrets act as flat health right now
if(build.block instanceof PointDefenseTurret && build.consValid){
sumHealth += 150f * build.timeScale();
if(build.block instanceof PointDefenseTurret){
sumHealth += 150f * build.timeScale() * build.efficiency;
}
if(build.block instanceof ForceProjector f){

View File

@@ -303,7 +303,7 @@ public class Block extends UnlockableContent implements Senseable{
/** Consumption filters. */
public boolean[] itemFilter, liquidFilter;
/** Array of consumers used by this block. Only populated after init(). */
public Consume[] consumers = {}, optionalConsumers = {}, nonOptionalConsumers = {};
public Consume[] consumers = {}, optionalConsumers = {}, nonOptionalConsumers = {}, updateConsumers = {};
/** Set to true if this block has any consumers in its array. */
public boolean hasConsumers;
/** The single power consumer, if applicable. */
@@ -1092,6 +1092,7 @@ public class Block extends UnlockableContent implements Senseable{
consumers = consumeBuilder.toArray(Consume.class);
optionalConsumers = consumeBuilder.select(consume -> consume.optional && !consume.ignore()).toArray(Consume.class);
nonOptionalConsumers = consumeBuilder.select(consume -> !consume.optional && !consume.ignore()).toArray(Consume.class);
updateConsumers = consumeBuilder.select(consume -> consume.update && !consume.ignore()).toArray(Consume.class);
hasConsumers = consumers.length > 0;
itemFilter = new boolean[content.items().size];
liquidFilter = new boolean[content.liquids().size];

View File

@@ -56,7 +56,7 @@ public class Accelerator extends Block{
@Override
public void updateTile(){
super.updateTile();
heat = Mathf.lerpDelta(heat, consValid ? 1f : 0f, 0.05f);
heat = Mathf.lerpDelta(heat, efficiency, 0.05f);
statusLerp = Mathf.lerpDelta(statusLerp, power.status, 0.05f);
}
@@ -101,14 +101,14 @@ public class Accelerator extends Block{
@Override
public Cursor getCursor(){
return !state.isCampaign() || !consValid ? SystemCursor.arrow : super.getCursor();
return !state.isCampaign() || efficiency <= 0f ? SystemCursor.arrow : super.getCursor();
}
@Override
public void buildConfiguration(Table table){
deselect();
if(!state.isCampaign() || !consValid) return;
if(!state.isCampaign() || efficiency <= 0f) return;
ui.planet.showPlanetLaunch(state.rules.sector, sector -> {
//TODO cutscene, etc...

View File

@@ -126,7 +126,7 @@ public class LaunchPad extends Block{
if(!state.isCampaign()) return;
//increment launchCounter then launch when full and base conditions are met
if((launchCounter += edelta()) >= launchTime && consValid && items.total() >= itemCapacity){
if((launchCounter += edelta()) >= launchTime && items.total() >= itemCapacity){
//if there are item requirements, use those.
consume();
launchSound.at(x, y);

View File

@@ -81,7 +81,7 @@ public class BaseShield extends Block{
@Override
public void updateTile(){
smoothRadius = Mathf.lerpDelta(smoothRadius, radius * efficiency(), 0.05f);
smoothRadius = Mathf.lerpDelta(smoothRadius, radius * efficiency, 0.05f);
float rad = radius();

View File

@@ -107,8 +107,8 @@ public class BuildTurret extends BaseTurret{
checkSuppression();
unit.buildSpeedMultiplier(efficiency() * timeScale);
unit.speedMultiplier(efficiency() * timeScale);
unit.buildSpeedMultiplier(efficiency * timeScale);
unit.speedMultiplier(efficiency * timeScale);
warmup = Mathf.lerpDelta(warmup, unit.activelyBuilding() ? 1f : 0f, 0.1f);
@@ -202,14 +202,9 @@ public class BuildTurret extends BaseTurret{
unit.buildSpeedMultiplier(Math.max(unit.buildSpeedMultiplier(), 0.00001f));
}
@Override
public float efficiency(){
return super.efficiency() * (isHealSuppressed() ? 0f : 1f);
}
@Override
public boolean shouldConsume(){
return super.shouldConsume() && unit.activelyBuilding();
return super.shouldConsume() && unit.activelyBuilding() && !isHealSuppressed();
}
@Override

View File

@@ -137,7 +137,7 @@ public class DirectionalForceProjector extends Block{
Fx.reactorsmoke.at(x + Mathf.range(tilesize / 2f), y + Mathf.range(tilesize / 2f));
}
warmup = Mathf.lerpDelta(warmup, efficiency(), 0.1f);
warmup = Mathf.lerpDelta(warmup, efficiency, 0.1f);
//TODO aaaaaaaaaaaaAAAAAAAAAAAAAAaa
if(buildup > 0 && false){

View File

@@ -152,7 +152,7 @@ public class ForceProjector extends Block{
phaseHeat = Mathf.lerpDelta(phaseHeat, Mathf.num(phaseValid), 0.1f);
if(phaseValid && !broken && timer(timerUse, phaseUseTime) && efficiency() > 0){
if(phaseValid && !broken && timer(timerUse, phaseUseTime) && efficiency > 0){
consume();
}
@@ -162,7 +162,7 @@ public class ForceProjector extends Block{
Fx.reactorsmoke.at(x + Mathf.range(tilesize / 2f), y + Mathf.range(tilesize / 2f));
}
warmup = Mathf.lerpDelta(warmup, efficiency(), 0.1f);
warmup = Mathf.lerpDelta(warmup, efficiency, 0.1f);
if(buildup > 0){
float scale = !broken ? cooldownNormal : cooldownBrokenBase;

View File

@@ -78,13 +78,13 @@ public class MendProjector extends Block{
public void updateTile(){
boolean canHeal = !checkSuppression();
smoothEfficiency = Mathf.lerpDelta(smoothEfficiency, efficiency(), 0.08f);
heat = Mathf.lerpDelta(heat, consValid && canHeal ? 1f : 0f, 0.08f);
smoothEfficiency = Mathf.lerpDelta(smoothEfficiency, efficiency, 0.08f);
heat = Mathf.lerpDelta(heat, efficiency > 0 && canHeal ? 1f : 0f, 0.08f);
charge += heat * delta();
phaseHeat = Mathf.lerpDelta(phaseHeat, Mathf.num(consOptionalValid()), 0.1f);
phaseHeat = Mathf.lerpDelta(phaseHeat, optionalEfficiency, 0.1f);
if(consOptionalValid() && timer(timerUse, useTime) && efficiency() > 0 && canHeal){
if(optionalEfficiency > 0 && timer(timerUse, useTime) && canHeal){
consume();
}
@@ -93,7 +93,7 @@ public class MendProjector extends Block{
charge = 0f;
indexer.eachBlock(this, realRange, b -> b.damaged() && !b.isHealSuppressed(), other -> {
other.heal(other.maxHealth() * (healPercent + phaseHeat * phaseBoost) / 100f * efficiency());
other.heal(other.maxHealth() * (healPercent + phaseHeat * phaseBoost) / 100f * efficiency);
other.recentlyHealed();
Fx.healBlockFull.at(other.x, other.y, other.block.size, baseColor);
});

View File

@@ -97,12 +97,12 @@ public class OverdriveProjector extends Block{
@Override
public void updateTile(){
smoothEfficiency = Mathf.lerpDelta(smoothEfficiency, efficiency(), 0.08f);
heat = Mathf.lerpDelta(heat, consValid ? 1f : 0f, 0.08f);
smoothEfficiency = Mathf.lerpDelta(smoothEfficiency, efficiency, 0.08f);
heat = Mathf.lerpDelta(heat, efficiency > 0 ? 1f : 0f, 0.08f);
charge += heat * Time.delta;
if(hasBoost){
phaseHeat = Mathf.lerpDelta(phaseHeat, Mathf.num(consOptionalValid()), 0.1f);
phaseHeat = Mathf.lerpDelta(phaseHeat, optionalEfficiency, 0.1f);
}
if(charge >= reload){
@@ -112,13 +112,13 @@ public class OverdriveProjector extends Block{
indexer.eachBlock(this, realRange, other -> other.block.canOverdrive, other -> other.applyBoost(realBoost(), reload + 1f));
}
if(timer(timerUse, useTime) && efficiency() > 0 && consValid){
if(timer(timerUse, useTime) && efficiency > 0){
consume();
}
}
public float realBoost(){
return consValid ? (speedBoost + phaseHeat * speedBoostPhase) * efficiency() : 0f;
return (speedBoost + phaseHeat * speedBoostPhase) * efficiency;
}
@Override

View File

@@ -112,7 +112,7 @@ public class RegenProjector extends Block{
}
//TODO should warmup depend on didRegen?
warmup = Mathf.approachDelta(warmup, consValid && didRegen ? 1f : 0f, 1f / 70f);
warmup = Mathf.approachDelta(warmup, didRegen ? 1f : 0f, 1f / 70f);
totalTime += warmup * Time.delta;
didRegen = false;
@@ -121,13 +121,13 @@ public class RegenProjector extends Block{
return;
}
if(consValid){
if(consOptionalValid() && (optionalTimer += Time.delta) >= optionalUseTime){
if(efficiency > 0){
if((optionalTimer += Time.delta * optionalEfficiency) >= optionalUseTime){
consume();
optionalUseTime = 0f;
}
float healAmount = (consOptionalValid() ? optionalMultiplier : 1f) * healPercent;
float healAmount = Mathf.lerp(1f, optionalMultiplier, optionalEfficiency) * healPercent;
//use Math.max to prevent stacking
for(var build : targets){

View File

@@ -60,7 +60,7 @@ public class ContinuousTurret extends Turret{
super.updateTile();
//TODO unclean way of calculating ammo fraction to display
float ammoFract = efficiency();
float ammoFract = efficiency;
if(findConsumer(f -> f instanceof ConsumeLiquidBase) instanceof ConsumeLiquid cons){
ammoFract = Math.min(ammoFract, liquids.get(cons.liquid) / liquidCapacity);
}
@@ -110,7 +110,7 @@ public class ContinuousTurret extends Turret{
@Override
protected void turnToTarget(float targetRot){
rotation = Angles.moveToward(rotation, targetRot, efficiency() * rotateSpeed * delta());
rotation = Angles.moveToward(rotation, targetRot, efficiency * rotateSpeed * delta());
}
@Override

View File

@@ -58,7 +58,7 @@ public class LaserTurret extends PowerTurret{
bullet.time = bullet.type.lifetime * bullet.type.optimalLifeFract;
heat = 1f;
recoil = recoilAmount;
bulletLife -= Time.delta / Math.max(efficiency(), 0.00001f);
bulletLife -= Time.delta / Math.max(efficiency, 0.00001f);
if(bulletLife <= 0f){
bullet = null;
}
@@ -93,7 +93,7 @@ public class LaserTurret extends PowerTurret{
return;
}
if(reload <= 0 && (consValid || cheating()) && !charging && shootWarmup >= minWarmup){
if(reload <= 0 && efficiency > 0 && !charging && shootWarmup >= minWarmup){
BulletType type = peekAmmo();
shoot(type);
@@ -104,7 +104,7 @@ public class LaserTurret extends PowerTurret{
@Override
protected void turnToTarget(float targetRot){
rotation = Angles.moveToward(rotation, targetRot, efficiency() * rotateSpeed * delta() * (bulletLife > 0f ? firingMoveFract : 1f));
rotation = Angles.moveToward(rotation, targetRot, efficiency * rotateSpeed * delta() * (bulletLife > 0f ? firingMoveFract : 1f));
}
@Override

View File

@@ -45,7 +45,7 @@ public class ReloadTurret extends BaseTurret{
}
protected float baseReloadSpeed(){
return efficiency();
return efficiency;
}
}
}

View File

@@ -76,6 +76,7 @@ public class TractorBeamTurret extends BaseTurret{
@Override
public void updateTile(){
float eff = efficiency * coolantMultiplier, edelta = eff * delta();
//retarget
if(timer(timerTarget, retargetTime)){
@@ -102,13 +103,13 @@ public class TractorBeamTurret extends BaseTurret{
any = false;
//look at target
if(target != null && target.within(this, range + target.hitSize/2f) && target.team() != team && target.checkTarget(targetAir, targetGround) && efficiency() > 0.02f){
if(target != null && target.within(this, range + target.hitSize/2f) && target.team() != team && target.checkTarget(targetAir, targetGround) && efficiency > 0.02f){
if(!headless){
control.sound.loop(shootSound, this, shootSoundVolume);
}
float dest = angleTo(target);
rotation = Angles.moveToward(rotation, dest, rotateSpeed * edelta());
rotation = Angles.moveToward(rotation, dest, rotateSpeed * edelta);
lastX = target.x;
lastY = target.y;
strength = Mathf.lerpDelta(strength, 1f, 0.1f);
@@ -116,7 +117,7 @@ public class TractorBeamTurret extends BaseTurret{
//shoot when possible
if(Angles.within(rotation, dest, shootCone)){
if(damage > 0){
target.damageContinuous(damage * efficiency());
target.damageContinuous(damage * eff);
}
if(status != StatusEffects.none){
@@ -124,7 +125,7 @@ public class TractorBeamTurret extends BaseTurret{
}
any = true;
target.impulseNet(Tmp.v1.set(this).sub(target).limit((force + (1f - target.dst(this) / range) * scaledForce) * edelta()));
target.impulseNet(Tmp.v1.set(this).sub(target).limit((force + (1f - target.dst(this) / range) * scaledForce) * edelta));
}
}else{
strength = Mathf.lerpDelta(strength, 0, 0.1f);
@@ -136,11 +137,6 @@ public class TractorBeamTurret extends BaseTurret{
return super.shouldConsume() && target != null;
}
@Override
public float efficiency(){
return super.efficiency() * coolantMultiplier;
}
@Override
public void draw(){
Draw.rect(baseRegion, x, y);
@@ -156,7 +152,7 @@ public class TractorBeamTurret extends BaseTurret{
Drawf.laser(team, laser, laserStart, laserEnd,
x + Angles.trnsx(ang, shootLength), y + Angles.trnsy(ang, shootLength),
lastX, lastY, strength * efficiency() * laserWidth);
lastX, lastY, strength * efficiency * laserWidth);
Draw.mixcol();
}

View File

@@ -200,7 +200,7 @@ public class Turret extends ReloadTurret{
public float estimateDps(){
if(!hasAmmo()) return 0f;
return shots / reloadTime * 60f * peekAmmo().estimateDPS() * efficiency() * timeScale;
return shots / reloadTime * 60f * peekAmmo().estimateDPS() * efficiency * timeScale;
}
@Override
@@ -431,11 +431,10 @@ public class Turret extends ReloadTurret{
}
@Override
public float efficiency(){
public void updateEfficiencyMultiplier(){
if(heatRequirement > 0){
return Math.min(heatReq / heatRequirement, maxHeatEfficiency) * super.efficiency();
efficiency *= Math.min(heatReq / heatRequirement, maxHeatEfficiency);
}
return super.efficiency();
}
/** Consume ammo and return a type. */

View File

@@ -320,7 +320,7 @@ public class ItemBridge extends Block{
inc.add(pos);
}
warmup = Mathf.approachDelta(warmup, efficiency(), 1f / 30f);
warmup = Mathf.approachDelta(warmup, efficiency, 1f / 30f);
updateTransport(other.build);
}
}

View File

@@ -153,7 +153,7 @@ public class MassDriver extends Block{
}
//skip when there's no power
if(!consValid){
if(efficiency <= 0f){
return;
}
@@ -165,7 +165,7 @@ public class MassDriver extends Block{
}
//align to shooter rotation
rotation = Angles.moveToward(rotation, angleTo(currentShooter()), rotateSpeed * efficiency());
rotation = Angles.moveToward(rotation, angleTo(currentShooter()), rotateSpeed * efficiency);
}else if(state == DriverState.shooting){
//if there's nothing to shoot at OR someone wants to shoot at this thing, bail
if(!hasLink || (!waitingShooters.isEmpty() && (itemCapacity - items.total() >= minDistribute))){
@@ -185,7 +185,7 @@ public class MassDriver extends Block{
if(reload <= 0.0001f){
//align to target location
rotation = Angles.moveToward(rotation, targetRotation, rotateSpeed * efficiency());
rotation = Angles.moveToward(rotation, targetRotation, rotateSpeed * efficiency);
//fire when it's the first in the queue and angles are ready.
if(other.currentShooter() == this &&
@@ -326,7 +326,7 @@ public class MassDriver extends Block{
}
protected boolean shooterValid(Building other){
return other instanceof MassDriverBuild entity && other.isValid() && other.consValid && entity.block == block && entity.link == pos() && within(other, range);
return other instanceof MassDriverBuild entity && other.isValid() && other.efficiency > 0 && entity.block == block && entity.link == pos() && within(other, range);
}
protected boolean linkValid(){

View File

@@ -34,7 +34,7 @@ public class StackConveyor extends Block implements Autotiler{
public float glowAlpha = 1f;
public Color glowColor = Pal.redLight;
public float baseEfficiency = 1f;
public float baseEfficiency = 0f;
public float speed = 0f;
public boolean outputRouter = true;
/** (minimum) amount of loading docks needed to fill a line. */
@@ -248,15 +248,12 @@ public class StackConveyor extends Block implements Autotiler{
return state != stateLoad;
}
@Override
public float efficiency(){
return baseEfficiency + (power == null ? 0f : power.status);
}
@Override
public void updateTile(){
float eff = enabled ? (efficiency + baseEfficiency) : 0f;
//reel in crater
if(cooldown > 0f) cooldown = Mathf.clamp(cooldown - speed * edelta(), 0f, recharge);
if(cooldown > 0f) cooldown = Mathf.clamp(cooldown - speed * eff * delta(), 0f, recharge);
//indicates empty state
if(link == -1) return;

View File

@@ -25,12 +25,13 @@ public class StackRouter extends DuctRouter{
@Override
public void updateTile(){
float eff = enabled ? (efficiency + baseEfficiency) : 0f;
float cap = speed;
if(!unloading && current != null && items.total() >= itemCapacity){
if(progress < cap){
//when items are full, begin offload timer
progress += edelta();
progress += eff;
}
if(progress >= cap){
@@ -78,12 +79,6 @@ public class StackRouter extends DuctRouter{
}
}
@Override
public float efficiency(){
if(!enabled) return 0;
return baseEfficiency + (power == null ? 0 : power.status);
}
@Override
public boolean acceptItem(Building source, Item item){
return !unloading && (current == null || item == current) && items.total() < itemCapacity &&

View File

@@ -44,7 +44,7 @@ public class HeatProducer extends GenericCrafter{
super.updateTile();
//heat approaches target at the same speed regardless of efficiency
heat = Mathf.approachDelta(heat, heatOutput * efficiency() * Mathf.num(consValid), warmupRate * delta());
heat = Mathf.approachDelta(heat, heatOutput * efficiency, warmupRate * delta());
}
@Override

View File

@@ -484,7 +484,7 @@ public class LogicBlock extends Block{
}
if(enabled && executor.initialized()){
accumulator += edelta() * ipt * (consValid ? 1 : 0);
accumulator += edelta() * ipt * efficiency;
if(accumulator > maxInstructionScale * ipt) accumulator = maxInstructionScale * ipt;

View File

@@ -88,7 +88,7 @@ public abstract class BlockProducer extends PayloadBlock{
public void updateTile(){
super.updateTile();
var recipe = recipe();
boolean produce = recipe != null && consValid && payload == null;
boolean produce = recipe != null && efficiency > 0 && payload == null;
if(produce){
progress += buildSpeed * edelta();

View File

@@ -142,7 +142,7 @@ public class PayloadLoader extends PayloadBlock{
//load up items
if(payload.block().hasItems && items.any()){
if(efficiency() > 0.01f && timer(timerLoad, loadTime / efficiency())){
if(efficiency > 0.01f && timer(timerLoad, loadTime / efficiency)){
//load up items a set amount of times
for(int j = 0; j < itemsLoaded && items.any(); j++){

View File

@@ -188,7 +188,7 @@ public class PayloadMassDriver extends PayloadBlock{
!(
current instanceof PayloadDriverBuild entity &&
current.isValid() &&
entity.consValid && entity.block == block &&
entity.efficiency > 0 && entity.block == block &&
entity.link == pos() && within(current, range)
)){
waitingShooters.removeFirst();
@@ -219,7 +219,7 @@ public class PayloadMassDriver extends PayloadBlock{
}
//skip when there's no power
if(!consValid){
if(efficiency <= 0f){
return;
}
@@ -235,7 +235,7 @@ public class PayloadMassDriver extends PayloadBlock{
}
//align to shooter rotation
turretRotation = Angles.moveToward(turretRotation, angleTo(currentShooter()), rotateSpeed * efficiency());
turretRotation = Angles.moveToward(turretRotation, angleTo(currentShooter()), rotateSpeed * efficiency);
}else if(state == shooting){
//if there's nothing to shoot at OR someone wants to shoot at this thing, bail
if(!hasLink || (!waitingShooters.isEmpty() && payload == null)){
@@ -269,7 +269,7 @@ public class PayloadMassDriver extends PayloadBlock{
if(reload <= 0){
//align to target location
turretRotation = Angles.moveToward(turretRotation, targetRotation, rotateSpeed * efficiency());
turretRotation = Angles.moveToward(turretRotation, targetRotation, rotateSpeed * efficiency);
//fire when it's the first in the queue and angles are ready.
if(other.currentShooter() == this &&

View File

@@ -64,7 +64,7 @@ public class PayloadUnloader extends PayloadLoader{
//unload items
if(payload.block().hasItems && !full()){
if(efficiency() > 0.01f && timer(timerLoad, loadTime / efficiency())){
if(efficiency > 0.01f && timer(timerLoad, loadTime / efficiency)){
//load up items a set amount of times
for(int j = 0; j < itemsLoaded && !full(); j++){
for(int i = 0; i < items.length(); i++){

View File

@@ -56,7 +56,7 @@ public class PayloadVoid extends PayloadBlock{
@Override
public void updateTile(){
super.updateTile();
if(moveInPayload(false) && consValid){
if(moveInPayload(false) && efficiency > 0){
payload = null;
incinerateEffect.at(this);
incinerateSound.at(this);

View File

@@ -69,7 +69,7 @@ public class ConsumeGenerator extends PowerGenerator{
}
public class ConsumeGeneratorBuild extends GeneratorBuild{
public float warmup, totalTime;
public float warmup, totalTime, efficiencyMultiplier = 1f;
@Override
public void updateEfficiencyMultiplier(){
@@ -84,7 +84,7 @@ public class ConsumeGenerator extends PowerGenerator{
@Override
public void updateTile(){
boolean valid = consValid;
boolean valid = efficiency > 0;
warmup = Mathf.lerpDelta(warmup, valid ? 1f : 0f, 0.05f);

View File

@@ -76,7 +76,7 @@ public class ImpactReactor extends PowerGenerator{
@Override
public void updateTile(){
if(consValid && power.status >= 0.99f){
if(efficiency > 0 && power.status >= 0.99f){
boolean prevOut = getPowerProduction() <= consPower.requestedPower(this);
warmup = Mathf.lerpDelta(warmup, 1f, warmupSpeed * timeScale);

View File

@@ -73,7 +73,7 @@ public class LightBlock extends Block{
public void draw(){
super.draw();
Draw.blend(Blending.additive);
Draw.color(Tmp.c1.set(color), efficiency() * 0.3f);
Draw.color(Tmp.c1.set(color), efficiency * 0.3f);
Draw.rect(topRegion, x, y);
Draw.color();
Draw.blend();
@@ -94,7 +94,7 @@ public class LightBlock extends Block{
@Override
public void drawLight(){
Drawf.light(team, x, y, lightRadius * Math.min(smoothTime, 2f), Tmp.c1.set(color), brightness * efficiency());
Drawf.light(team, x, y, lightRadius * Math.min(smoothTime, 2f), Tmp.c1.set(color), brightness * efficiency);
}
@Override

View File

@@ -213,7 +213,7 @@ public class BeamDrill extends Block{
if(lasers[0] == null) updateLasers();
warmup = Mathf.approachDelta(warmup, Mathf.num(consValid), 1f / 60f);
warmup = Mathf.approachDelta(warmup, Mathf.num(efficiency > 0), 1f / 60f);
lastItem = null;
boolean multiple = false;
int dx = Geometry.d4x(rotation), dy = Geometry.d4y(rotation), facingAmount = 0;
@@ -249,15 +249,8 @@ public class BeamDrill extends Block{
lastItem = null;
}
float multiplier = 1f;
if(consOptionalValid()){
boostWarmup = Mathf.lerpDelta(boostWarmup, 1f, 0.1f);
multiplier *= optionalBoostIntensity;
}else{
boostWarmup = Mathf.lerpDelta(boostWarmup, 0f, 0.1f);
}
float multiplier = Mathf.lerp(1f, optionalBoostIntensity, optionalEfficiency);
boostWarmup = Mathf.lerpDelta(boostWarmup, optionalEfficiency, 0.1f);
lastDrillSpeed = (facingAmount * multiplier * timeScale) / drillTime;
time += edelta() * multiplier;

View File

@@ -58,10 +58,10 @@ public class BurstDrill extends Drill{
smoothProgress = Mathf.lerpDelta(smoothProgress, progress / (drillTime - 20f), 0.1f);
if(items.total() <= itemCapacity - dominantItems && dominantItems > 0 && consValid){
if(items.total() <= itemCapacity - dominantItems && dominantItems > 0 && efficiency > 0){
warmup = Mathf.approachDelta(warmup, progress / drillTime, 0.01f);
float speed = efficiency();
float speed = efficiency;
timeDrilled += speedCurve.apply(progress / drillTime) * speed;

View File

@@ -228,12 +228,12 @@ public class Drill extends Block{
@Override
public boolean shouldAmbientSound(){
return efficiency() > 0.01f && items.total() < itemCapacity;
return efficiency > 0.01f && items.total() < itemCapacity;
}
@Override
public float ambientVolume(){
return efficiency() * (size * size) / 4f;
return efficiency * (size * size) / 4f;
}
@Override
@@ -273,15 +273,8 @@ public class Drill extends Block{
timeDrilled += warmup * delta();
if(items.total() < itemCapacity && dominantItems > 0 && consValid){
float speed = 1f;
if(consOptionalValid()){
speed = liquidBoostIntensity;
}
speed *= efficiency(); // Drill slower when not at full power
if(items.total() < itemCapacity && dominantItems > 0 && efficiency > 0){
float speed = Mathf.lerp(1f, liquidBoostIntensity, optionalEfficiency) * efficiency;
lastDrillSpeed = (speed * dominantItems * warmup) / (drillTime + hardnessDrillMultiplier * dominantItem.hardness);
warmup = Mathf.approachDelta(warmup, speed, warmupSpeed);

View File

@@ -28,14 +28,14 @@ public class Fracker extends SolidPump{
@Override
public void updateTile(){
if(consValid){
if(efficiency > 0){
if(accumulator >= itemUseTime){
consume();
accumulator -= itemUseTime;
}
super.updateTile();
accumulator += delta() * efficiency();
accumulator += delta() * efficiency;
}else{
warmup = Mathf.lerpDelta(warmup, 0f, 0.02f);
lastPump = 0f;

View File

@@ -187,7 +187,7 @@ public class GenericCrafter extends Block{
@Override
public void updateTile(){
if(consValid){
if(efficiency > 0){
progress += getProgressIncrease(craftTime);
warmup = Mathf.approachDelta(warmup, warmupTarget(), warmupSpeed);
@@ -282,7 +282,7 @@ public class GenericCrafter extends Block{
@Override
public boolean shouldAmbientSound(){
return consValid;
return efficiency > 0;
}
@Override

View File

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

View File

@@ -38,7 +38,7 @@ public class ItemIncinerator extends Block{
@Override
public BlockStatus status(){
return consValid ? BlockStatus.active : BlockStatus.noInput;
return efficiency > 0 ? BlockStatus.active : BlockStatus.noInput;
}
@Override
@@ -62,7 +62,7 @@ public class ItemIncinerator extends Block{
@Override
public boolean acceptItem(Building source, Item item){
return consValid;
return efficiency > 0;
}
}
}

View File

@@ -152,7 +152,7 @@ public class Pump extends LiquidBlock{
@Override
public void updateTile(){
if(consValid && liquidDrop != null){
if(efficiency > 0 && liquidDrop != null){
float maxPump = Math.min(liquidCapacity - liquids.get(liquidDrop), amount * pumpAmount * edelta());
liquids.add(liquidDrop, maxPump);

View File

@@ -64,7 +64,7 @@ public class Separator extends Block{
@Override
public boolean shouldAmbientSound(){
return consValid;
return efficiency > 0;
}
@Override
@@ -94,7 +94,7 @@ public class Separator extends Block{
public void updateTile(){
totalProgress += warmup * delta();
if(consValid){
if(efficiency > 0){
progress += getProgressIncrease(craftTime);
warmup = Mathf.lerpDelta(warmup, 1f, 0.02f);
}else{

View File

@@ -50,7 +50,7 @@ public class SolidPump extends Pump{
addBar("efficiency", (SolidPumpBuild entity) -> new Bar(() -> Core.bundle.formatFloat("bar.pumpspeed",
entity.lastPump * 60, 1),
() -> Pal.ammo,
() -> entity.warmup * entity.efficiency()));
() -> entity.warmup * entity.efficiency));
}
@Override
@@ -121,8 +121,8 @@ public class SolidPump extends Pump{
public void updateTile(){
float fraction = Math.max(validTiles + boost + (attribute == null ? 0 : attribute.env()), 0);
if(consValid && typeLiquid() < liquidCapacity - 0.001f){
float maxPump = Math.min(liquidCapacity - typeLiquid(), pumpAmount * delta() * fraction * efficiency());
if(efficiency > 0 && typeLiquid() < liquidCapacity - 0.001f){
float maxPump = Math.min(liquidCapacity - typeLiquid(), pumpAmount * delta() * fraction * efficiency);
liquids.add(result, maxPump);
lastPump = maxPump / Time.delta;
warmup = Mathf.lerpDelta(warmup, 1f, 0.02f);

View File

@@ -149,7 +149,7 @@ public class WallCrafter extends Block{
boolean cons = shouldConsume();
warmup = Mathf.approachDelta(warmup, Mathf.num(consValid), 1f / 40f);
warmup = Mathf.approachDelta(warmup, Mathf.num(efficiency > 0), 1f / 40f);
float dx = Geometry.d4x(rotation) * 0.5f, dy = Geometry.d4y(rotation) * 0.5f;
float eff = getEfficiency(tile.x, tile.y, rotation, dest -> {
@@ -163,7 +163,7 @@ public class WallCrafter extends Block{
}
}, null);
lastEfficiency = eff * timeScale * efficiency();
lastEfficiency = eff * timeScale * efficiency;
if(cons && (time += edelta() * eff) >= drillTime){
items.add(output, 1);

View File

@@ -60,7 +60,7 @@ public class DroneCenter extends Block{
units.removeAll(u -> !u.isAdded() || u.dead);
droneWarmup = Mathf.lerpDelta(droneWarmup, units.size < unitsSpawned ? efficiency() : 0f, 0.1f);
droneWarmup = Mathf.lerpDelta(droneWarmup, units.size < unitsSpawned ? efficiency : 0f, 0.1f);
totalDroneProgress += droneWarmup * Time.delta;
if(readTarget != 0){

View File

@@ -219,7 +219,7 @@ public class Reconstructor extends UnitBlock{
moveOutPayload();
}else{ //update progress
if(moveInPayload()){
if(consValid){
if(efficiency > 0){
valid = true;
progress += edelta() * state.rules.unitBuildSpeed(team);
}

View File

@@ -172,7 +172,7 @@ public class RepairPoint extends Block{
public void updateTile(){
float multiplier = 1f;
if(acceptCoolant){
multiplier = consOptionalValid() ? 1f + liquids.current().heatCapacity * coolantMultiplier : 1f;
multiplier = 1f + liquids.current().heatCapacity * coolantMultiplier * optionalEfficiency;
}
if(target != null && (target.dead() || target.dst(this) - target.hitSize/2f > repairRadius || target.health() >= target.maxHealth())){
@@ -185,13 +185,13 @@ public class RepairPoint extends Block{
boolean healed = false;
if(target != null && consValid){
if(target != null && efficiency > 0){
float angle = Angles.angle(x, y, target.x + offset.x, target.y + offset.y);
if(Angles.angleDist(angle, rotation) < 30f){
healed = true;
target.heal(repairSpeed * strength * edelta() * multiplier);
}
rotation = Mathf.slerpDelta(rotation, angle, 0.5f * efficiency() * timeScale);
rotation = Mathf.slerpDelta(rotation, angle, 0.5f * efficiency * timeScale);
}
strength = Mathf.lerpDelta(strength, healed ? 1f : 0f, 0.08f * Time.delta);
@@ -209,7 +209,7 @@ public class RepairPoint extends Block{
@Override
public BlockStatus status(){
return Mathf.equal(efficiency(), 0f, 0.01f) ? BlockStatus.noInput : super.status();
return Mathf.equal(efficiency, 0f, 0.01f) ? BlockStatus.noInput : super.status();
}
@Override

View File

@@ -327,8 +327,8 @@ public class UnitAssembler extends PayloadBlock{
units.clear();
}
powerWarmup = Mathf.lerpDelta(powerWarmup, efficiency() > 0.0001f ? 1f : 0f, 0.1f);
droneWarmup = Mathf.lerpDelta(droneWarmup, units.size < dronesCreated ? efficiency() : 0f, 0.1f);
powerWarmup = Mathf.lerpDelta(powerWarmup, efficiency > 0.0001f ? 1f : 0f, 0.1f);
droneWarmup = Mathf.lerpDelta(droneWarmup, units.size < dronesCreated ? efficiency : 0f, 0.1f);
totalDroneProgress += droneWarmup * delta();
if(units.size < dronesCreated && (droneProgress += edelta() / droneConstructTime) >= 1f){
@@ -375,8 +375,8 @@ public class UnitAssembler extends PayloadBlock{
var plan = plan();
//check if all requirements are met
if(!wasOccupied && consValid && Units.canCreate(team, plan.unit)){
warmup = Mathf.lerpDelta(warmup, efficiency(), 0.1f);
if(!wasOccupied && efficiency > 0 && Units.canCreate(team, plan.unit)){
warmup = Mathf.lerpDelta(warmup, efficiency, 0.1f);
if((progress += edelta() * eff / plan.time) >= 1f){
Call.assemblerUnitSpawned(tile);
@@ -523,7 +523,7 @@ public class UnitAssembler extends PayloadBlock{
/** @return true if this block is ready to produce units, e.g. requirements met */
public boolean ready(){
return consValid && !wasOccupied;
return efficiency > 0 && !wasOccupied;
}
public void yeetPayload(Payload payload){

View File

@@ -128,7 +128,7 @@ public class UnitAssemblerModule extends PayloadBlock{
findLink();
}
if(moveInPayload() && link != null && link.moduleFits(block, x, y, rotation) && !link.wasOccupied && link.acceptPayload(this, payload) && consValid){
if(moveInPayload() && link != null && link.moduleFits(block, x, y, rotation) && !link.wasOccupied && link.acceptPayload(this, payload) && efficiency > 0){
link.yeetPayload(payload);
payload = null;
}

View File

@@ -93,7 +93,7 @@ public class UnitCargoLoader extends Block{
readUnitId = -1;
}
warmup = Mathf.approachDelta(warmup, efficiency(), 1f / 60f);
warmup = Mathf.approachDelta(warmup, efficiency, 1f / 60f);
readyness = Mathf.approachDelta(readyness, unit != null ? 1f : 0f, 1f / 60f);
if(unit == null && Units.canCreate(team, unitType)){

View File

@@ -244,7 +244,7 @@ public class UnitFactory extends UnitBlock{
currentPlan = -1;
}
if(consValid && currentPlan != -1){
if(efficiency > 0 && currentPlan != -1){
time += edelta() * speedScl * Vars.state.rules.unitBuildSpeed(team);
progress += edelta() * Vars.state.rules.unitBuildSpeed(team);
speedScl = Mathf.lerpDelta(speedScl, 1f, 0.05f);
@@ -263,7 +263,7 @@ public class UnitFactory extends UnitBlock{
return;
}
if(progress >= plan.time && consValid){
if(progress >= plan.time){
progress %= 1f;
Unit unit = plan.unit.create(team);

View File

@@ -25,9 +25,6 @@ public class ItemModule extends BlockModule{
protected int total;
protected int takeRotation;
/** A value >0 in an index array indicates that a corresponding item is currently being consumed. 1 indicates an entire item. */
public float[] itemConsumption = new float[items.length];
private @Nullable WindowedMean[] flow;
public ItemModule copy(){