Skip to content

Commit

Permalink
Major update to factorio 2.0: base game (non SA)
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielKote committed Oct 24, 2024
1 parent ef44a9c commit 21119d8
Show file tree
Hide file tree
Showing 30 changed files with 15,718 additions and 7,548 deletions.
2 changes: 1 addition & 1 deletion Foreman/Controls/EditRecipePanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ private void UpdateBeaconInfo()

BeaconEnergyLabel.Text = nodeData.SelectedBeacon == null ? "0J" : GraphicsStuff.DoubleToEnergy(nodeData.GetBeaconEnergyConsumption(), "W");
BeaconModuleCountLabel.Text = nodeData.SelectedBeacon == null ? "0" : nodeData.SelectedBeacon.ModuleSlots.ToString();
BeaconEfficiencyLabel.Text = nodeData.SelectedBeacon == null ? "0%" : nodeData.SelectedBeacon.BeaconEffectivity.ToString("P0");
BeaconEfficiencyLabel.Text = nodeData.SelectedBeacon == null ? "0%" : nodeData.SelectedBeacon.GetBeaconEffectivity(nodeData.SelectedBeacon.Owner.DefaultQuality, nodeData.BeaconCount).ToString("P0"); //QUALITY UPDATE REQUIRED
TotalBeaconsLabel.Text = nodeData.GetTotalBeacons().ToString();
TotalBeaconEnergyLabel.Text = nodeData.SelectedBeacon == null ? "0J" : GraphicsStuff.DoubleToEnergy(nodeData.GetTotalBeaconElectricalConsumption(), "W");
}
Expand Down
536 changes: 376 additions & 160 deletions Foreman/DataCache/DataCache.cs

Large diffs are not rendered by default.

25 changes: 24 additions & 1 deletion Foreman/DataCache/DataTypes/Assembler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,41 @@ namespace Foreman
public interface Assembler : EntityObjectBase
{
IReadOnlyCollection<Recipe> Recipes { get; }
double BaseSpeedBonus { get; }
double BaseProductivityBonus { get; }
double BaseConsumptionBonus { get; }
double BasePollutionBonus { get; }
double BaseQualityBonus { get; }

bool AllowBeacons { get; }
bool AllowModules { get; }
}

internal class AssemblerPrototype : EntityObjectBasePrototype, Assembler
{
public IReadOnlyCollection<Recipe> Recipes { get { return recipes; } }
public double BaseProductivityBonus { get; set; }
public double BaseSpeedBonus { get; set; }
public double BaseProductivityBonus { get; set; }
public double BaseConsumptionBonus { get; set; }
public double BasePollutionBonus { get; set; }
public double BaseQualityBonus { get; set; }

public bool AllowBeacons { get; internal set; }
public bool AllowModules { get; internal set; }

internal HashSet<RecipePrototype> recipes { get; private set; }

public AssemblerPrototype(DataCache dCache, string name, string friendlyName, EntityType type, EnergySource source, bool isMissing = false) : base(dCache, name, friendlyName, type, source, isMissing)
{
BaseSpeedBonus = 0;
BaseProductivityBonus = 0;
BaseConsumptionBonus = 0;
BasePollutionBonus = 0;
BaseQualityBonus = 0;

AllowBeacons = false; //assumed to be default? no info in LUA
AllowModules = false; //assumed to be default? no info in LUA

recipes = new HashSet<RecipePrototype>();
}

Expand Down
41 changes: 38 additions & 3 deletions Foreman/DataCache/DataTypes/Beacon.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,53 @@

using System;
using System.Collections.Generic;

namespace Foreman
{

public interface Beacon : EntityObjectBase
{
double BeaconEffectivity { get; }
double GetBeaconEffectivity(Quality quality, double beaconCount);
}

internal class BeaconPrototype : EntityObjectBasePrototype, Beacon
{
public double BeaconEffectivity { get; set; }

public double GetBeaconEffectivity(Quality quality, double beaconCount)
{
if (beaconCount <= 0)
return 0;
if(beaconCount > 999)
beaconCount = 999;

int baseCount = (int)Math.Truncate(beaconCount);
double remainder = beaconCount - baseCount;

double lowerBeaconEffectivity = baseCount * GetBeaconEffectivityBase(quality, baseCount);
double upperBeaconEffectivity = (baseCount + 1) * GetBeaconEffectivityBase(quality, baseCount + 1);

return (((1 - remainder) * lowerBeaconEffectivity) + (remainder * upperBeaconEffectivity)) / beaconCount;
//just to explain - we need to calculate the 'average' beacon effectivity for a beacon count of (for example) 1.6:
//this means that for every 10 assemblers you have 6 with 2 beacons and 4 with 1 beacon. So calculate the total bonus and divide it by beaconCount.
//therefore 10 assemblers with beacon count of 1.6 will produce exactly the same amount as 6 assemblers with 2 beacons + 4 assemblers with 1 beacon
}

private double GetBeaconEffectivityBase(Quality quality, int beaconCount)
{
return profile[beaconCount] * (DistributionEffectivity + (quality.Level * DistributionEffectivityQualityBoost));
}

internal double DistributionEffectivity { get; set; }
internal double DistributionEffectivityQualityBoost { get; set; }

internal double[] profile { get; private set; } //off by 1 from factorio (or more akin same index as LUA starts from 0) ==> profile[x] is the multiplier for x beacons (so profile[0] is multiplier for 0 beacons...)

public BeaconPrototype(DataCache dCache, string name, string friendlyName, EnergySource source, bool isMissing = false) : base(dCache, name, friendlyName, EntityType.Beacon, source, isMissing)
{
BeaconEffectivity = 0.5f;
profile = new double[1000];
for(int i = 1; i < profile.Length; i++) { profile[i] = 0.5f; }
DistributionEffectivity = 0.5f;
DistributionEffectivityQualityBoost = 0f;
}

public override string ToString() { return string.Format("Beacon: {0}", Name); }
Expand Down
54 changes: 33 additions & 21 deletions Foreman/DataCache/DataTypes/EntityObjectBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public interface EntityObjectBase : DataObjectBase
IReadOnlyCollection<Module> Modules { get; }
IReadOnlyCollection<Item> Fuels { get; }
IReadOnlyCollection<Item> AssociatedItems { get; }
IReadOnlyDictionary<string, double> Pollution { get; }

EntityType EntityType { get; }
string GetEntityTypeName(bool plural);
Expand All @@ -25,19 +26,19 @@ public interface EntityObjectBase : DataObjectBase
bool IsTemperatureFluidBurner { get; }
fRange FluidFuelTemperatureRange { get; }

double GetBaseFuelConsumptionRate(Item fuel, double temperature = double.NaN);
double GetBaseFuelConsumptionRate(Item fuel, Quality quality, double temperature = double.NaN);

bool IsMissing { get; }

double Speed { get; }
double GetSpeed(Quality quality);

int ModuleSlots { get; }

double EnergyDrain { get; }
double EnergyConsumption { get; }
double EnergyProduction { get; }
double GetEnergyDrain();
double GetEnergyConsumption(Quality quality);
double GetEnergyProduction(Quality quality);

double ConsumptionEffectivity { get; }
double Pollution { get; }

//steam generators
double OperationTemperature { get; }
Expand All @@ -53,10 +54,12 @@ internal class EntityObjectBasePrototype : DataObjectBasePrototype, EntityObject
public IReadOnlyCollection<Module> Modules { get { return modules; } }
public IReadOnlyCollection<Item> Fuels { get { return fuels; } }
public IReadOnlyCollection<Item> AssociatedItems { get { return associatedItems; } }
public IReadOnlyDictionary<string, double> Pollution { get { return pollution; } }

internal HashSet<ModulePrototype> modules { get; private set; }
internal HashSet<ItemPrototype> fuels { get; private set; }
internal List<ItemPrototype> associatedItems { get; private set; } //should honestly only be 1, but knowing modders....
internal Dictionary<string, double> pollution { get; private set; }

public EntityType EntityType { get; private set; }
public EnergySource EnergySource { get; internal set; }
Expand All @@ -65,56 +68,65 @@ internal class EntityObjectBasePrototype : DataObjectBasePrototype, EntityObject
public bool IsTemperatureFluidBurner { get; set; }
public fRange FluidFuelTemperatureRange { get; set; }

private double speed;
public double Speed { get { return speed; } internal set { speed = value == 0 ? 0.001 : value; } }
internal Dictionary<Quality, double> speed { get; private set; }
internal Dictionary<Quality, double> energyConsumption { get; private set; }
internal Dictionary<Quality, double> energyProduction { get; private set; }

public double GetSpeed(Quality quality) { return speed.ContainsKey(quality)? (speed[quality] > 0 ? speed[quality] : 1) : 1; }

public int ModuleSlots { get; internal set; }
public double NeighbourBonus { get; internal set; }

public double EnergyDrain { get; internal set; } //per second
public double EnergyConsumption { get; internal set; }
public double EnergyProduction { get; internal set; }
internal double energyDrain;
public double GetEnergyDrain() { return energyDrain; }
public double GetEnergyConsumption(Quality quality)
{
if(this is BeaconPrototype)
return quality.BeaconPowerMultiplier * (energyConsumption.ContainsKey(quality) ? energyConsumption[quality] : 1000);
else
return energyConsumption.ContainsKey(quality)? energyConsumption[quality] : 1000;
}
public double GetEnergyProduction(Quality quality) { return energyConsumption.ContainsKey(quality)? energyProduction[quality] : 0; }

public double ConsumptionEffectivity { get; internal set; }
public double OperationTemperature { get; internal set; }

public double Pollution { get; internal set; }

public EntityObjectBasePrototype(DataCache dCache, string name, string friendlyName, EntityType type, EnergySource source, bool isMissing) : base(dCache, name, friendlyName, "-")
{
availableOverride = false;

modules = new HashSet<ModulePrototype>();
fuels = new HashSet<ItemPrototype>();
associatedItems = new List<ItemPrototype>();
pollution = new Dictionary<string, double>();

speed = new Dictionary<Quality, double>();
energyConsumption = new Dictionary<Quality, double>();
energyProduction = new Dictionary<Quality, double>();

IsMissing = isMissing;
EntityType = type;
EnergySource = source;

//just some base defaults -> helps prevent overflow errors during solving if the assembler is a missing entity
Speed = 1f;
ModuleSlots = 0;
NeighbourBonus = 0;
EnergyDrain = 0; //passive use (pretty much electricity only)
EnergyConsumption = 1000; //default value to prevent issues with missing objects
EnergyProduction = 0;
ConsumptionEffectivity = 1f;
OperationTemperature = double.MaxValue;
FluidFuelTemperatureRange = new fRange(double.MinValue, double.MaxValue);

Pollution = 0;
}

public double GetBaseFuelConsumptionRate(Item fuel, double temperature = double.NaN)
public double GetBaseFuelConsumptionRate(Item fuel, Quality quality, double temperature = double.NaN)
{
if ((EnergySource != EnergySource.Burner && EnergySource != EnergySource.FluidBurner && EnergySource != EnergySource.Heat))
Trace.Fail(string.Format("Cant ask for fuel consumption rate on a non-burner! {0}", this));
else if (!fuels.Contains(fuel))
Trace.Fail(string.Format("Invalid fuel! {0} for entity {1}", fuel, this));
else if (!IsTemperatureFluidBurner)
return EnergyConsumption / (fuel.FuelValue * ConsumptionEffectivity);
return GetEnergyConsumption(quality) / (fuel.FuelValue * ConsumptionEffectivity);
else if (!double.IsNaN(temperature) && (fuel is Fluid fluidFuel) && (temperature > fluidFuel.DefaultTemperature) && (fluidFuel.SpecificHeatCapacity > 0)) //temperature burn of liquid
return EnergyConsumption / ((temperature - fluidFuel.DefaultTemperature) * fluidFuel.SpecificHeatCapacity * ConsumptionEffectivity);
return GetEnergyConsumption(quality) / ((temperature - fluidFuel.DefaultTemperature) * fluidFuel.SpecificHeatCapacity * ConsumptionEffectivity);
return 0.01; // we cant have a 0 consumption rate as that would mess with the solver.
}

Expand Down
6 changes: 6 additions & 0 deletions Foreman/DataCache/DataTypes/Fluid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public interface Fluid : Item
bool IsTemperatureDependent { get; }
double DefaultTemperature { get; }
double SpecificHeatCapacity { get; }
double GasTemperature { get; }
double MaxTemperature { get; }

string GetTemperatureRangeFriendlyName(fRange tempRange);
string GetTemperatureFriendlyName(double temperature);
Expand All @@ -21,12 +23,16 @@ public class FluidPrototype : ItemPrototype, Fluid
public bool IsTemperatureDependent { get; internal set; } //true if not all recipes can accept each other (ex: fluid produced in R1 is at 10*c, and is required to be at 20+*c as ingredient at R2)
public double DefaultTemperature { get; internal set; }
public double SpecificHeatCapacity { get; internal set; }
public double GasTemperature { get; internal set; }
public double MaxTemperature { get; internal set; }

public FluidPrototype(DataCache dCache, string name, string friendlyName, SubgroupPrototype subgroup, string order, bool isMissing = false) : base(dCache, name, friendlyName, subgroup, order, isMissing)
{
IsTemperatureDependent = false;
DefaultTemperature = 0;
SpecificHeatCapacity = 0;
GasTemperature = 0;
MaxTemperature = 0;
}

public string GetTemperatureRangeFriendlyName(fRange tempRange)
Expand Down
22 changes: 22 additions & 0 deletions Foreman/DataCache/DataTypes/Item.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,22 @@ public interface Item : DataObjectBase

int StackSize { get; }

double Weight { get; }
double IngredientToWeightCoefficient { get; }
double FuelValue { get; }
double PollutionMultiplier { get; }

Item BurnResult { get; }
Item PlantResult { get; }
Item SpoilResult { get; }

Item FuelOrigin { get; }
Item PlantOrigin { get; }
Item SpoilOrigin { get; }

IReadOnlyCollection<EntityObjectBase> FuelsEntities { get; }

//spoil ticks are ignored - its assumed that if there is a plant/spoil result then the ticks are at least low enough to make it viable on a world basis
}

public class ItemPrototype : DataObjectBasePrototype, Item
Expand All @@ -36,10 +47,19 @@ public class ItemPrototype : DataObjectBasePrototype, Item

public int StackSize { get; set; }

public double Weight { get; set; }
public double IngredientToWeightCoefficient { get; set; }
public double FuelValue { get; internal set; }
public double PollutionMultiplier { get; internal set; }

public Item BurnResult { get; internal set; }
public Item PlantResult { get; internal set; }
public Item SpoilResult { get; internal set; }

public Item FuelOrigin { get; internal set; }
public Item PlantOrigin { get; internal set; }
public Item SpoilOrigin { get; internal set; }

public IReadOnlyCollection<EntityObjectBase> FuelsEntities { get { return fuelsEntities; } }

internal SubgroupPrototype mySubgroup;
Expand All @@ -61,6 +81,8 @@ public ItemPrototype(DataCache dCache, string name, string friendlyName, Subgrou
consumptionTechnologies = new HashSet<TechnologyPrototype>();
fuelsEntities = new HashSet<EntityObjectBasePrototype>();

Weight = 0.01f;
IngredientToWeightCoefficient = 1f;
FuelValue = 1f; //useful for preventing overlow issues when using missing items / non-fuel items (loading with wrong mods / importing from alt mod group can cause this)
PollutionMultiplier = 1f;
IsMissing = isMissing;
Expand Down
18 changes: 14 additions & 4 deletions Foreman/DataCache/DataTypes/Module.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ public interface Module : DataObjectBase
double ProductivityBonus { get; }
double ConsumptionBonus { get; }
double PollutionBonus { get; }
double QualityBonus { get; }

string Category { get; }

int Tier { get; }

Expand All @@ -32,10 +35,13 @@ public class ModulePrototype : DataObjectBasePrototype, Module
public IReadOnlyCollection<Recipe> AvailableRecipes { get; private set; }
public Item AssociatedItem { get { return Owner.Items[Name]; } }

public double SpeedBonus { get; set; }
public double ProductivityBonus { get; set; }
public double ConsumptionBonus { get; set; }
public double PollutionBonus { get; set; }
public double SpeedBonus { get; internal set; }
public double ProductivityBonus { get; internal set; }
public double ConsumptionBonus { get; internal set; }
public double PollutionBonus { get; internal set; }
public double QualityBonus { get; internal set; }

public string Category { get; internal set; }

public int Tier { get; set; }

Expand All @@ -55,6 +61,10 @@ public ModulePrototype(DataCache dCache, string name, string friendlyName, bool
ProductivityBonus = 0;
ConsumptionBonus = 0;
PollutionBonus = 0;
QualityBonus = 0;

Category = "";

recipes = new HashSet<RecipePrototype>();
assemblers = new HashSet<AssemblerPrototype>();
beacons = new HashSet<BeaconPrototype>();
Expand Down
41 changes: 41 additions & 0 deletions Foreman/DataCache/DataTypes/Quality.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;

namespace Foreman
{
public interface Quality : DataObjectBase
{
Quality NextQuality { get; }
Quality PrevQuality { get; }
double NextProbability { get; }

int Level { get; }
double BeaconPowerMultiplier { get; }
double MiningDrillResourceDrainMultiplier { get; }

}

public class QualityPrototype : DataObjectBasePrototype, Quality
{
public Quality NextQuality { get; internal set; }
public Quality PrevQuality { get; internal set; }
public double NextProbability { get; set; }

public int Level { get; set; }
public double BeaconPowerMultiplier { get; set; }
public double MiningDrillResourceDrainMultiplier { get; set; }

public QualityPrototype(DataCache dCache, string name, string friendlyName, string order) : base(dCache, name, friendlyName, order)
{
Enabled = true;

Level = 0;
BeaconPowerMultiplier = 1;
MiningDrillResourceDrainMultiplier = 1;
}

public override string ToString() { return string.Format("Quality T{0}: {1}", Level, Name); }
}
}
Loading

0 comments on commit 21119d8

Please sign in to comment.