Jump to content

A couple of code fixes for Turbine


yoakenashi
  • Branch: Live Branch Version: Windows Pending

The current Turbine code reads like this, with comments added for my own understanding/clarity:

Spoiler

    private bool CanSteamFlow(ref bool insufficient_mass, ref bool insufficient_temperature)
    {
      float a1 = 0.0f;
      float a2 = 0.0f;
      float a3 = float.PositiveInfinity;
      this.isInputBlocked = false;
      for (int index = 0; index < this.master.srcCells.Length; ++index)		// for each source cell
      {
        int srcCell = this.master.srcCells[index];
        float b1 = Grid.Mass[srcCell];									// b1 = source cell mass
        if (Grid.Element[srcCell].id == this.master.srcElem)					// if source cell is steam
          a1 = Mathf.Max(a1, b1);									//       a1 = max(a1,b1), get highest source mass
        float b2 = Grid.Temperature[srcCell];							//    b2 = cell temp
        a2 = Mathf.Max(a2, b2);										//    a2 = max(a2, b2), get highest source temperature
        byte num = Grid.ElementIdx[srcCell];								
        Element element = ElementLoader.elements[(int) num];
        if (element.IsLiquid || element.IsSolid)							//    if source cell is a liquid or solid
          this.isInputBlocked = true;									//    input is blocked
      }


      this.isOutputBlocked = false;									// output is not blocked
	  for (int index = 0; index < this.master.destCells.Length; ++index)		// for each destination cell
      {
        int destCell = this.master.destCells[index];
        float b = Grid.Mass[destCell];									//    b = destination cell mass
        a3 = Mathf.Min(a3, b);										//    a3 = min(a3, b), get smallest output mass
        byte num = Grid.ElementIdx[destCell];
        Element element = ElementLoader.elements[(int) num];
        if (element.IsLiquid || element.IsSolid)							//    if source cell is a liquid or solid
          this.isOutputBlocked = true;									//    output is blocked
      }
	  
	  
      insufficient_mass = (double) a1 - (double) a3 < (double) this.master.requiredMassFlowDifferential;		// insufficient mass if highest input mass - smallest output mass is less than 3 kg
      insufficient_temperature = (double) a2 < (double) this.master.minActiveTemperature;					// insufficient temperature if highest input temperature is less than 400 K
      if (!insufficient_mass)
        return !insufficient_temperature;
      return false;
    }

 

Move "float b2 = Grid.Temperature[srcCell];"  above the If statement.

Include "a2 = Mathf.Max(a2, b2);" in the If statement, so that only steam temperatures are considered. In other words, we do not want steam to flow if another gas other than steam is above the minActiveTemperature.

Change the ending If statements "if (!insufficient_mass)" to "if (!this.isInputBlocked && !this.isOutputBlocked && !insufficient_mass)" so that the input blocked and output blocked Boolean are considered.

The only problem that would not be resolved is where a low mass of gas exists above the steam turbine (in the destination cells) and never actually becomes compressed (increases in mass), so a3 always stays small. This is a common exploit (good, bad, otherwise?)

Maybe a way fix to this would be to compare steam separately from other gasses. If steam is present on the output, use the minimum steam mass, otherwise use the minimum non-steam mass.

Add a new variable for steam minimum mass:
    float a4 = float.PositiveInfinity;

Make the min function in the destination dependent on destination cell element:
    Grid.Element[destCell].id == this.master.srcElem ? a4 = Mathf.Min(a3, b) : a3 = Mathf.Min(a4, b);

And then add another conditional to use either the min steam or min non-steam:
    a4 == float.PositiveInfinity ? a3 = a3 : a3 = a4;

The final logic would look like this:

Spoiler

    private bool CanSteamFlow(ref bool insufficient_mass, ref bool insufficient_temperature)
    {
      float a1 = 0.0f;
      float a2 = 0.0f;
      float a3 = float.PositiveInfinity;
	  float a4 = float.PositiveInfinity;
      this.isInputBlocked = false;
      for (int index = 0; index < this.master.srcCells.Length; ++index)		// for each source cell
      {
        int srcCell = this.master.srcCells[index];
        float b1 = Grid.Mass[srcCell];									// b1 = source cell mass
        float b2 = Grid.Temperature[srcCell];							// b2 = cell temp
        if (Grid.Element[srcCell].id == this.master.srcElem)					// if source cell is steam
        {
          a1 = Mathf.Max(a1, b1);									//       a1 = max(a1,b1), get highest source mass
          a2 = Mathf.Max(a2, b2);									//       a2 = max(a2, b2), get highest source temperature
        }
        byte num = Grid.ElementIdx[srcCell];								
        Element element = ElementLoader.elements[(int) num];
        if (element.IsLiquid || element.IsSolid)							//    if source cell is a liquid or solid
          this.isInputBlocked = true;									//    input is blocked
      }


      this.isOutputBlocked = false;									// out is not blocked
	  for (int index = 0; index < this.master.destCells.Length; ++index)		// for each destination cell
      {
        int destCell = this.master.destCells[index];
        float b = Grid.Mass[destCell];									//    b = destination cell mass
        Grid.Element[destCell].id == this.master.srcElem ? a4 = Mathf.Min(a4, b) : a3 = Mathf.Min(a3, b); // if destination cell is steam evaluate a4 = min(a4, b) and get smallest steam output mass, otherwise evaluate a3 = min(a3, b) and get smallest non-steam output mass
        byte num = Grid.ElementIdx[destCell];
        Element element = ElementLoader.elements[(int) num];
        if (element.IsLiquid || element.IsSolid)							//    if source cell is a liquid or solid
          this.isOutputBlocked = true;									//    output is blocked
      }
	  
      a4 == float.PositiveInfinity ? a3 = a3 : a3 = a4;						// if no steam (min steam mass is still positive infinity), then use regular non-steam minimum mass a3, otherwise use steam miminum mass a4
	  
      insufficient_mass = (double) a1 - (double) a3 < (double) this.master.requiredMassFlowDifferential;		// insufficient mass if highest input mass - smallest output mass is less than 3 kg
      insufficient_temperature = (double) a2 < (double) this.master.minActiveTemperature;					// insufficient temperature if highest input temperature is less than 400 K
      
	  
      if (!this.isInputBlocked && !this.isOutputBlocked && !insufficient_mass)
        return !insufficient_temperature;
      return false;
	  
    }

 

Caution, I'm not a C# programmer, so my syntax may be a little off. I also hope posting code snippets is also not against the forum rules. If so, I apologize. Thanks for a great game!


Steps to Reproduce
Examine game code and refer to https://forums.kleientertainment.com/forums/topic/98732-the-steam-turbine-everything-you-need-to-know/



User Feedback


Note that "blocked" is true if *any* tile is blocked...not just if *all* of them are.  This would disable the Steam Turbine just by blocking one input or output port, which is probably not intended.

  • Like 1

Share this comment


Link to comment
Share on other sites

On 1/18/2019 at 4:20 PM, Lawnmower Man said:

Note that "blocked" is true if *any* tile is blocked...not just if *all* of them are.  This would disable the Steam Turbine just by blocking one input or output port, which is probably not intended.

You think so? I personally thought the opposite, that "if any input tile is blocked, then disable the turbine" was intended operation. Haha, of course we are both making assumptions as to what the developers "intended" based on how we see the code. Thanks for pointing that out., it's a very valid comment.

Share this comment


Link to comment
Share on other sites



Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
  • Create New...