Thermal generator now based on floor / Power restructuring

This commit is contained in:
Anuken 2019-01-26 12:48:15 -05:00
parent 7924051c0d
commit 4be675f977
18 changed files with 145 additions and 142 deletions

View File

@ -36,7 +36,7 @@ public class Blocks implements ContentList{
grass, shrub, rock, icerock, blackrock, rocks, cliffs, pine,
//crafting
siliconSmelter, graphitePress, plastaniumCompressor, phaseWeaver, surgeSmelter, pyratiteMixer, blastMixer, cryofluidMixer,
siliconSmelter, graphitePress, plastaniumCompressor, multiPress, phaseWeaver, surgeSmelter, pyratiteMixer, blastMixer, cryofluidMixer,
melter, separator, centrifuge, biomatterCompressor, pulverizer, incinerator,
//sandbox
@ -226,6 +226,33 @@ public class Blocks implements ContentList{
//endregion
//region crafting
graphitePress = new GenericCrafter("graphite-press"){{
requirements(Category.crafting, ItemStack.with(Items.copper, 300, Items.lead, 50));
craftEffect = Fx.pulverizeMedium;
output = Items.graphite;
craftTime = 90f;
size = 2;
hasItems = true;
consumes.item(Items.coal, 2);
}};
multiPress = new GenericCrafter("multi-press"){{
requirements(Category.crafting, ItemStack.with(Items.titanium, 200, Items.silicon, 50, Items.lead, 200, Items.graphite, 100));
craftEffect = Fx.pulverizeMedium;
output = Items.graphite;
craftTime = 30f;
size = 2;
hasItems = true;
hasLiquids = true;
consumes.power(0.2f);
consumes.item(Items.coal, 2);
consumes.liquid(Liquids.water, 0.1f);
}};
siliconSmelter = new PowerSmelter("silicon-smelter"){{
requirements(Category.crafting, ItemStack.with(Items.copper, 60, Items.lead, 50));
craftEffect = Fx.smeltsmoke;
@ -239,18 +266,6 @@ public class Blocks implements ContentList{
consumes.power(0.05f);
}};
graphitePress = new GenericCrafter("graphite-press"){{
requirements(Category.crafting, ItemStack.with(Items.copper, 200, Items.lead, 50));
craftEffect = Fx.pulverizeMedium;
output = Items.graphite;
craftTime = 90f;
size = 2;
hasItems = true;
consumes.item(Items.coal, 2);
}};
plastaniumCompressor = new PlastaniumCompressor("plastanium-compressor"){{
requirements(Category.crafting, ItemStack.with(Items.silicon, 160, Items.lead, 230, Items.graphite, 120, Items.titanium, 160));
hasItems = true;
@ -693,9 +708,8 @@ public class Blocks implements ContentList{
itemDuration = 40f;
}};
thermalGenerator = new LiquidHeatGenerator("thermal-generator"){{
thermalGenerator = new ThermalGenerator("thermal-generator"){{
requirements(Category.power, ItemStack.with(Items.copper, 80, Items.graphite, 70, Items.lead, 100, Items.silicon, 70, Items.thorium, 70));
maxLiquidGenerate = 2f;
powerProduction = 2f;
generateEffect = Fx.redgeneratespark;
size = 2;

View File

@ -37,8 +37,8 @@ public class Items implements ContentList{
}};
coal = new Item("coal", Color.valueOf("272727")){{
explosiveness = 0.2f;
flammability = 0.5f;
explosiveness = 0.4f;
flammability = 1f;
hardness = 2;
genOre = true;
}};
@ -52,9 +52,9 @@ public class Items implements ContentList{
thorium = new Item("thorium", Color.valueOf("f9a3c7")){{
type = ItemType.material;
explosiveness = 0.1f;
explosiveness = 0.2f;
hardness = 4;
radioactivity = 0.5f;
radioactivity = 1f;
cost = 1.4f;
genOre = true;
}};
@ -70,16 +70,16 @@ public class Items implements ContentList{
plastanium = new Item("plastanium", Color.valueOf("cbd97f")){{
type = ItemType.material;
flammability = 0.1f;
explosiveness = 0.1f;
flammability = 0.2f;
explosiveness = 0.2f;
cost = 1.6f;
}};
phasefabric = new Item("phase-fabric", Color.valueOf("f4ba6e")){{
type = ItemType.material;
cost = 1.5f;
fluxiness = 0.9f;
radioactivity = 0.3f;
fluxiness = 1.8f;
radioactivity = 0.6f;
}};
surgealloy = new Item("surge-alloy", Color.valueOf("f3e979")){{
@ -87,22 +87,22 @@ public class Items implements ContentList{
}};
biomatter = new Item("biomatter", Color.valueOf("648b55")){{
flammability = 0.55f;
fluxiness = 0.3f;
flammability = 1.05f;
fluxiness = 0.6f;
}};
sand = new Item("sand", Color.valueOf("e3d39e")){{
fluxiness = 0.5f;
fluxiness = 1f;
}};
blastCompound = new Item("blast-compound", Color.valueOf("ff795e")){{
flammability = 0.2f;
explosiveness = 0.6f;
flammability = 0.4f;
explosiveness = 1.2f;
}};
pyratite = new Item("pyratite", Color.valueOf("ffaa5f")){{
flammability = 0.7f;
explosiveness = 0.2f;
flammability = 1.4f;
explosiveness = 0.4f;
}};
}
}

View File

@ -25,8 +25,8 @@ public class Liquids implements ContentList{
oil = new Liquid("oil", Color.valueOf("313131")){{
viscosity = 0.7f;
flammability = 0.6f;
explosiveness = 0.6f;
flammability = 1.2f;
explosiveness = 1.2f;
heatCapacity = 0.7f;
tier = 1;
effect = StatusEffects.tarred;

View File

@ -86,13 +86,13 @@ public class ContentDisplay{
table.left().defaults().fillX();
table.add(Core.bundle.format("item.explosiveness", (int) (item.explosiveness * 100 * 2f)));
table.add(Core.bundle.format("item.explosiveness", (int) (item.explosiveness * 100)));
table.row();
table.add(Core.bundle.format("item.flammability", (int) (item.flammability * 100 * 2f)));
table.add(Core.bundle.format("item.flammability", (int) (item.flammability * 100)));
table.row();
table.add(Core.bundle.format("item.radioactivity", (int) (item.radioactivity * 100 * 2f)));
table.add(Core.bundle.format("item.radioactivity", (int) (item.radioactivity * 100)));
table.row();
table.add(Core.bundle.format("item.fluxiness", (int) (item.fluxiness * 100 * 2f)));
table.add(Core.bundle.format("item.fluxiness", (int) (item.fluxiness * 100)));
table.row();
}
@ -119,9 +119,9 @@ public class ContentDisplay{
table.left().defaults().fillX();
table.add(Core.bundle.format("item.explosiveness", (int) (liquid.explosiveness * 100 * 2f)));
table.add(Core.bundle.format("item.explosiveness", (int) (liquid.explosiveness * 100)));
table.row();
table.add(Core.bundle.format("item.flammability", (int) (liquid.flammability * 100 * 2f)));
table.add(Core.bundle.format("item.flammability", (int) (liquid.flammability * 100)));
table.row();
table.add(Core.bundle.format("liquid.heatcapacity", (int) (liquid.heatCapacity * 100)));
table.row();

View File

@ -5,7 +5,6 @@ import io.anuke.arc.Graphics.Cursor;
import io.anuke.arc.Graphics.Cursor.SystemCursor;
import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.EnumSet;
import io.anuke.arc.collection.IntArray;
import io.anuke.arc.function.BooleanProvider;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.graphics.g2d.Draw;
@ -293,19 +292,6 @@ public class Block extends BlockStorage{
region = Core.atlas.find(name);
}
/**Called when the world is resized.
* Call super!*/
public void transformLinks(Tile tile, int oldWidth, int oldHeight, int newWidth, int newHeight, int shiftX, int shiftY){
if(tile.entity != null && tile.entity.power != null){
IntArray links = tile.entity.power.links;
IntArray out = new IntArray();
for(int i = 0; i < links.size; i++){
out.add(world.transform(links.get(i), oldWidth, oldHeight, newWidth, shiftX, shiftY));
}
tile.entity.power.links = out;
}
}
/** Called when the block is tapped. */
public void tapped(Tile tile, Player player){

View File

@ -45,6 +45,8 @@ public class Floor extends Block{
public boolean hasOres = false;
/** whether this block can be drowned in */
public boolean isLiquid;
/** Heat of this block, 0 at baseline. Used for calculating output of thermal generators.*/
public float heat = 0f;
/** if true, this block cannot be mined by players. useful for annoying things like sand. */
public boolean playerUnmineable = false;
protected TextureRegion[] variantRegions;

View File

@ -287,14 +287,6 @@ public class ItemBridge extends Block{
return rel != rel2;
}
@Override
public void transformLinks(Tile tile, int oldWidth, int oldHeight, int newWidth, int newHeight, int shiftX, int shiftY){
super.transformLinks(tile, oldWidth, oldHeight, newWidth, newHeight, shiftX, shiftY);
ItemBridgeEntity entity = tile.entity();
entity.link = world.transform(entity.link, oldWidth, oldHeight, newWidth, shiftX, shiftY);
}
@Override
public TileEntity newEntity(){
return new ItemBridgeEntity();

View File

@ -231,14 +231,6 @@ public class MassDriver extends Block{
return tile.entity.items.total() < itemCapacity;
}
@Override
public void transformLinks(Tile tile, int oldWidth, int oldHeight, int newWidth, int newHeight, int shiftX, int shiftY){
super.transformLinks(tile, oldWidth, oldHeight, newWidth, newHeight, shiftX, shiftY);
MassDriverEntity entity = tile.entity();
entity.link = world.transform(entity.link, oldWidth, oldHeight, newWidth, shiftX, shiftY);
}
@Override
public TileEntity newEntity(){
return new MassDriverEntity();

View File

@ -6,7 +6,7 @@ import io.anuke.mindustry.type.Liquid;
public class BurnerGenerator extends ItemLiquidGenerator{
public BurnerGenerator(String name){
super(InputType.LiquidsAndItems, name);
super(true, true, name);
}
@Override

View File

@ -1,12 +1,11 @@
package io.anuke.mindustry.world.blocks.power;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.Liquid;
public class DecayGenerator extends ItemLiquidGenerator{
public DecayGenerator(String name){
super(InputType.ItemsOnly, name);
super(true, false, name);
hasItems = true;
hasLiquids = false;
}

View File

@ -37,24 +37,16 @@ public class ItemLiquidGenerator extends PowerGenerator{
protected Color heatColor = Color.valueOf("ff9b59");
protected TextureRegion topRegion;
public enum InputType{
ItemsOnly,
LiquidsOnly,
LiquidsAndItems
}
public ItemLiquidGenerator(InputType inputType, String name){
public ItemLiquidGenerator(boolean hasItems, boolean hasLiquids, String name){
super(name);
this.hasItems = inputType != InputType.LiquidsOnly;
this.hasLiquids = inputType != InputType.ItemsOnly;
this.hasItems = hasItems;
this.hasLiquids = hasLiquids;
if(hasItems){
itemCapacity = 20;
consumes.add(new ConsumeItemFilter(item -> getItemEfficiency(item) >= minItemEfficiency)).update(false).optional(true);
}
if(hasLiquids){
liquidCapacity = 10f;
consumes.add(new ConsumeLiquidFilter(liquid -> getLiquidEfficiency(liquid) >= minLiquidEfficiency, 0.001f, true)).update(false).optional(true);
}
}
@ -72,8 +64,8 @@ public class ItemLiquidGenerator extends PowerGenerator{
public void update(Tile tile){
ItemLiquidGeneratorEntity entity = tile.entity();
// Note: Do not use this delta when calculating the amount of power or the power efficiency, but use it for resource consumption if necessary.
// Power amount is delta'd by PowerGraph class already.
//Note: Do not use this delta when calculating the amount of power or the power efficiency, but use it for resource consumption if necessary.
//Power amount is delta'd by PowerGraph class already.
float calculationDelta = entity.delta();
if(!entity.cons.valid()){
@ -115,7 +107,7 @@ public class ItemLiquidGenerator extends PowerGenerator{
if(entity.generateTime > 0f){
entity.generateTime -= Math.min(1f / itemDuration * entity.delta(), entity.generateTime);
if(Mathf.chance(entity.delta() * 0.06 * Mathf.clamp(entity.explosiveness - 0.25f))){
if(Mathf.chance(entity.delta() * 0.06 * Mathf.clamp(entity.explosiveness - 0.5f))){
//this block is run last so that in the event of a block destruction, no code relies on the block type
entity.damage(Mathf.random(8f));
Effects.effect(explodeEffect, tile.worldx() + Mathf.range(size * tilesize / 2f), tile.worldy() + Mathf.range(size * tilesize / 2f));

View File

@ -1,28 +0,0 @@
package io.anuke.mindustry.world.blocks.power;
import io.anuke.mindustry.content.Liquids;
import io.anuke.mindustry.type.Liquid;
import io.anuke.mindustry.world.meta.BlockStat;
import io.anuke.mindustry.world.meta.StatUnit;
//TODO remove, as this is no longer a thing
public class LiquidHeatGenerator extends ItemLiquidGenerator{
public LiquidHeatGenerator(String name){
super(InputType.LiquidsOnly, name);
}
@Override
public void setStats(){
super.setStats();
stats.remove(BlockStat.basePowerGeneration);
// right now, Lava is the only thing that can be used.
stats.add(BlockStat.basePowerGeneration, powerProduction * getLiquidEfficiency(Liquids.slag) / maxLiquidGenerate * 60f, StatUnit.powerSecond);
}
@Override
protected float getLiquidEfficiency(Liquid liquid){
return liquid.temperature - 0.5f;
}
}

View File

@ -12,7 +12,7 @@ import java.io.DataOutput;
import java.io.IOException;
public class PowerGenerator extends PowerDistributor{
/** The amount of power produced per tick in case of an efficiency of 1.0, which currently represents 200%. */
/** The amount of power produced per tick in case of an efficiency of 1.0, which represents 100%. */
protected float powerProduction;
public BlockStat generationType = BlockStat.basePowerGeneration;
@ -25,14 +25,11 @@ public class PowerGenerator extends PowerDistributor{
@Override
public void setStats(){
super.setStats();
// Divide power production by two since that is what is produced at an efficiency of 0.5, which currently represents 100%
stats.add(generationType, powerProduction * 60.0f / 2.0f, StatUnit.powerSecond);
stats.add(generationType, powerProduction * 60.0f, StatUnit.powerSecond);
}
@Override
public float getPowerProduction(Tile tile){
// While 0.5 efficiency currently reflects 100%, we do not need to multiply by any factor since powerProduction states the
// power which would be produced at 1.0 efficiency
return powerProduction * tile.<GeneratorEntity>entity().productionEfficiency;
}
@ -48,7 +45,7 @@ public class PowerGenerator extends PowerDistributor{
public static class GeneratorEntity extends TileEntity{
public float generateTime;
/** The efficiency of the producer. Currently, an efficiency of 0.5 means 100% */
/** The efficiency of the producer. An efficiency of 1.0 means 100% */
public float productionEfficiency = 0.0f;
@Override

View File

@ -0,0 +1,55 @@
package io.anuke.mindustry.world.blocks.power;
import io.anuke.arc.entities.Effects;
import io.anuke.arc.entities.Effects.Effect;
import io.anuke.arc.math.Mathf;
import io.anuke.mindustry.content.Fx;
import io.anuke.mindustry.world.Tile;
public class ThermalGenerator extends PowerGenerator{
protected Effect generateEffect = Fx.none;
public ThermalGenerator(String name){
super(name);
}
@Override
public void update(Tile tile){
GeneratorEntity entity = tile.entity();
if(entity.productionEfficiency > 0.1f && Mathf.chance(0.05 * entity.delta())){
Effects.effect(generateEffect, tile.drawx() + Mathf.range(3f), tile.drawy() + Mathf.range(3f));
}
super.update(tile);
}
@Override
public void placed(Tile tile){
super.placed(tile);
}
@Override
public void onProximityAdded(Tile tile){
super.onProximityAdded(tile);
GeneratorEntity entity = tile.entity();
entity.productionEfficiency = 0f;
for(Tile other : tile.getLinkedTiles(tempTiles)){
entity.productionEfficiency += other.floor().heat;
}
}
@Override
public float getPowerProduction(Tile tile){
//in this case, productionEfficiency means 'total heat'
//thus, it may be greater than 1.0
return powerProduction * tile.<GeneratorEntity>entity().productionEfficiency;
}
@Override
public boolean canPlaceOn(Tile tile){
//make sure there's heat at this location
return tile.getLinkedTilesAs(this, tempTiles).sum(other -> other.floor().heat) > 0.01f;
}
}

View File

@ -78,6 +78,8 @@ public class GenericCrafter extends Block{
if(entity.progress >= 1f){
//TODO, bad design, crafter has to know that this consumes items
//there should be a separate trigger in #cons to consume discrete amounts of items
if(consumes.has(ConsumeItem.class)) tile.entity.items.remove(consumes.item(), consumes.itemAmount());
useContent(tile, output);

View File

@ -8,6 +8,8 @@ import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.production.GenericCrafter.GenericCrafterEntity;
import io.anuke.mindustry.world.meta.BlockStat;
/**Similar to GenericCrafter, but also optionally outputs liquids.
* TODO consolidate into one class*/
public class PowerCrafter extends Block{
protected final int timerDump = timers++;
protected final int timerContentCheck = timers++;

View File

@ -296,14 +296,6 @@ public class Reconstructor extends Block{
Call.reconstructPlayer(player, tile);
}
@Override
public void transformLinks(Tile tile, int oldWidth, int oldHeight, int newWidth, int newHeight, int shiftX, int shiftY){
super.transformLinks(tile, oldWidth, oldHeight, newWidth, newHeight, shiftX, shiftY);
ReconstructorEntity entity = tile.entity();
entity.link = world.transform(entity.link, oldWidth, oldHeight, newWidth, shiftX, shiftY);
}
@Override
public TileEntity newEntity(){
return new ReconstructorEntity();

View File

@ -30,8 +30,8 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{
private final float fakeItemDuration = 60f; // 60 ticks
private final float maximumLiquidUsage = 0.5f;
public void createGenerator(ItemLiquidGenerator.InputType inputType){
generator = new ItemLiquidGenerator(inputType, "fakegen"){
public void createGenerator(InputType inputType){
generator = new ItemLiquidGenerator(inputType != InputType.liquids, inputType != InputType.items, "fakegen"){
{
powerProduction = 0.1f;
itemDuration = 60f;
@ -59,13 +59,13 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{
DynamicTest[] generatorWorksProperlyWithLiquidInput(){
// Execute all tests for the case where only liquids are accepted and for the case where liquids and items are accepted (but supply only liquids)
ItemLiquidGenerator.InputType[] inputTypesToBeTested = new ItemLiquidGenerator.InputType[]{
ItemLiquidGenerator.InputType.LiquidsOnly,
ItemLiquidGenerator.InputType.LiquidsAndItems
InputType[] inputTypesToBeTested = new InputType[]{
InputType.liquids,
InputType.any
};
ArrayList<DynamicTest> tests = new ArrayList<>();
for(ItemLiquidGenerator.InputType inputType : inputTypesToBeTested){
for(InputType inputType : inputTypesToBeTested){
tests.add(dynamicTest("01", () -> simulateLiquidConsumption(inputType, Liquids.oil, 0.0f, "No liquids provided")));
tests.add(dynamicTest("02", () -> simulateLiquidConsumption(inputType, Liquids.oil, maximumLiquidUsage / 4.0f, "Low oil provided")));
tests.add(dynamicTest("03", () -> simulateLiquidConsumption(inputType, Liquids.oil, maximumLiquidUsage * 1.0f, "Sufficient oil provided")));
@ -77,7 +77,7 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{
return testArray;
}
void simulateLiquidConsumption(ItemLiquidGenerator.InputType inputType, Liquid liquid, float availableLiquidAmount, String parameterDescription){
void simulateLiquidConsumption(InputType inputType, Liquid liquid, float availableLiquidAmount, String parameterDescription){
final float baseEfficiency = liquid.flammability;
final float expectedEfficiency = Math.min(1.0f, availableLiquidAmount / maximumLiquidUsage) * baseEfficiency;
final float expectedConsumptionPerTick = Math.min(maximumLiquidUsage, availableLiquidAmount);
@ -102,13 +102,13 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{
DynamicTest[] generatorWorksProperlyWithItemInput(){
// Execute all tests for the case where only items are accepted and for the case where liquids and items are accepted (but supply only items)
ItemLiquidGenerator.InputType[] inputTypesToBeTested = new ItemLiquidGenerator.InputType[]{
ItemLiquidGenerator.InputType.ItemsOnly,
ItemLiquidGenerator.InputType.LiquidsAndItems
InputType[] inputTypesToBeTested = new InputType[]{
InputType.items,
InputType.any
};
ArrayList<DynamicTest> tests = new ArrayList<>();
for(ItemLiquidGenerator.InputType inputType : inputTypesToBeTested){
for(InputType inputType : inputTypesToBeTested){
tests.add(dynamicTest("01", () -> simulateItemConsumption(inputType, Items.coal, 0, "No items provided")));
tests.add(dynamicTest("02", () -> simulateItemConsumption(inputType, Items.coal, 1, "Sufficient coal provided")));
tests.add(dynamicTest("03", () -> simulateItemConsumption(inputType, Items.coal, 10, "Excess coal provided")));
@ -122,7 +122,7 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{
return testArray;
}
void simulateItemConsumption(ItemLiquidGenerator.InputType inputType, Item item, int amount, String parameterDescription){
void simulateItemConsumption(InputType inputType, Item item, int amount, String parameterDescription){
final float expectedEfficiency = Math.min(1.0f, amount > 0 ? item.flammability : 0f);
final float expectedRemainingItemAmount = Math.max(0, amount - 1);
@ -145,16 +145,16 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{
/** Makes sure the efficiency stays equal during the item duration. */
@Test
void efficiencyRemainsConstantWithinItemDuration_ItemsOnly(){
testItemDuration(ItemLiquidGenerator.InputType.ItemsOnly);
testItemDuration(InputType.items);
}
/** Makes sure the efficiency stays equal during the item duration. */
@Test
void efficiencyRemainsConstantWithinItemDuration_ItemsAndLiquids(){
testItemDuration(ItemLiquidGenerator.InputType.LiquidsAndItems);
testItemDuration(InputType.any);
}
void testItemDuration(ItemLiquidGenerator.InputType inputType){
void testItemDuration(InputType inputType){
createGenerator(inputType);
// Burn a single coal and test for the duration
@ -172,4 +172,10 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{
generator.update(tile);
assertEquals(0.0f, entity.productionEfficiency, "Duration: " + String.valueOf(currentDuration));
}
enum InputType{
items,
liquids,
any
}
}