Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/auto-evo/simulation/SimulationCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ public class SimulationCache
private readonly CompoundDefinition oxytoxy = SimulationParameters.GetCompound(Compound.Oxytoxy);
private readonly CompoundDefinition mucilage = SimulationParameters.GetCompound(Compound.Mucilage);

private readonly OrganelleDefinition nucleusDefinition =
SimulationParameters.Instance.GetOrganelleType("nucleus");

private readonly WorldGenerationSettings worldSettings;

#if USE_HASHED_SCORE_KEYS
Expand Down Expand Up @@ -141,7 +144,8 @@ public EnergyBalanceInfoSimple GetEnergyBalanceForSpecies(MicrobeSpecies species
var cached = new EnergyBalanceInfoSimple();

// Assume here that the species specialization factor may not be up to date, so recalculate here
var specialization = MicrobeInternalCalculations.CalculateSpecializationBonus(species.Organelles, workMemory1);
var specialization = MicrobeInternalCalculations.CalculateSpecializationBonus(species.Organelles, workMemory1,
nucleusDefinition);

// Auto-evo uses the average values of compound during the course of a simulated day
ProcessSystem.ComputeEnergyBalanceSimple(species.Organelles, biomeConditions,
Expand Down
48 changes: 29 additions & 19 deletions src/microbe_stage/MicrobeInternalCalculations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -490,9 +490,11 @@ public static void GiveNearNightInitialCompoundBuff(CompoundBag compoundReceiver
WorldGenerationSettings worldSettings)
{
var energyBalance = new EnergyBalanceInfoSimple();
var nucleusDefinition = SimulationParameters.Instance.GetOrganelleType("nucleus");

// Note this assumes this is only used just for single cell types or microbe species!
var specialization = CalculateSpecializationBonus(organelles, new Dictionary<OrganelleDefinition, int>());
var specialization = CalculateSpecializationBonus(organelles, new Dictionary<OrganelleDefinition, int>(),
nucleusDefinition);

var maximumMovementDirection = MaximumSpeedDirection(organelles);
ProcessSystem.ComputeEnergyBalanceSimple(organelles, biomeConditions, environmentalTolerances, specialization,
Expand Down Expand Up @@ -591,7 +593,10 @@ public static (bool CanSurvive, Dictionary<Compound, float> RequiredStorage) Cal
ref Dictionary<Compound, CompoundBalance>? dayCompoundBalances)
{
// Note this assumes this is only used just for single cell types or microbe species!
var specialization = CalculateSpecializationBonus(organelles, new Dictionary<OrganelleDefinition, int>());
var nucleusDefinition = SimulationParameters.Instance.GetOrganelleType("nucleus");

var specialization = CalculateSpecializationBonus(organelles, new Dictionary<OrganelleDefinition, int>(),
nucleusDefinition);

if (dayCompoundBalances == null)
{
Expand Down Expand Up @@ -830,9 +835,9 @@ public static void GetBindingAndSignalling(IReadOnlyList<OrganelleTemplate> orga
}

public static int CalculateMostCommonSpecializationOrganelle(IReadOnlyList<IReadOnlyOrganelleTemplate> organelles,
Dictionary<OrganelleDefinition, int> tempWorkMemory)
Dictionary<OrganelleDefinition, int> tempWorkMemory, OrganelleDefinition nucleusDefinition)
{
int totalOrganelles = 0;
int totalHexCount = 0;
tempWorkMemory.Clear();

var count = organelles.Count;
Expand All @@ -842,13 +847,21 @@ public static int CalculateMostCommonSpecializationOrganelle(IReadOnlyList<IRead

var definition = organelle.Definition;

// Don't count the nucleus, because of its omnipresence and large size
if (definition == nucleusDefinition)
{
continue;
}

var hexCount = definition.HexCount;

tempWorkMemory.TryGetValue(definition, out var existingCount);
tempWorkMemory[definition] = existingCount + 1;
tempWorkMemory[definition] = existingCount + hexCount;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updating this count like this will break the tooltip (just commenting to remember about this as you said you didn't touch the tooltip side yet for this PR) as the tooltip will claim the player has way more organelles than they actually do.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very true! I was planning to either count the organelles themselves separately for the tooltip, or actually referring to organelle hexes (or size in some way) in the tooltip, since that would also inform the player of what is going on.

That makes me realise that in Master, the tooltip is now already a little bit off because it counts for example thylakoids in the number of chloroplasts. When I work on the tooltip, that's probably worth an "(or simpler equivalent)", or something like that.

Copy link
Copy Markdown
Member

@hhyyrylainen hhyyrylainen Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not counting the organelle / part tooltips, this is already one of the longest tooltips in the game... so I think we are quickly reaching the point where any player seeing the tooltip will mentally give up before managing to read it.

Edit: just wanted to say why I didn't change it. The advice is still right that you should be adding more of the most common organelle even when it is said to be the eukaryotic equivalent.


++totalOrganelles;
totalHexCount += hexCount;
}

if (totalOrganelles < 1)
if (totalHexCount < 1)
return 0;

// Merge equivalent organelles to make moving to eukaryotic variants easier
Expand All @@ -872,38 +885,35 @@ public static int CalculateMostCommonSpecializationOrganelle(IReadOnlyList<IRead
}
}

return totalOrganelles;
return totalHexCount;
}

/// <summary>
/// Calculates a specialization bonus for a cell type based on its organelles.
/// </summary>
/// <returns>A multiplier starting from 1 and going up as specialization improves</returns>
public static float CalculateSpecializationBonus(IReadOnlyList<IReadOnlyOrganelleTemplate> organelles,
Dictionary<OrganelleDefinition, int> tempWorkMemory)
Dictionary<OrganelleDefinition, int> tempWorkMemory, OrganelleDefinition nucleusDefinition)
{
int totalOrganelles = CalculateMostCommonSpecializationOrganelle(organelles, tempWorkMemory);
if (totalOrganelles < 1)
return 1;

if (totalOrganelles < Constants.CELL_SPECIALIZATION_APPLIES_AFTER_SIZE)
int totalHexCount = CalculateMostCommonSpecializationOrganelle(organelles, tempWorkMemory, nucleusDefinition);
if (totalHexCount < 1)
return 1;

int maxOrganelleCount = 0;
int maxHexCount = 0;

foreach (var entry in tempWorkMemory)
{
if (entry.Value > maxOrganelleCount)
if (entry.Value > maxHexCount)
{
maxOrganelleCount = entry.Value;
maxHexCount = entry.Value;
}
}

// The raw bonus is just the ratio of the main organelle type
var bonus = (float)maxOrganelleCount / totalOrganelles;
var bonus = (float)maxHexCount / totalHexCount;

// Calculate a strength factor that adjusts things
var strength = Math.Min((float)totalOrganelles / Constants.CELL_SPECIALIZATION_STRENGTH_FULL_AT, 1);
var strength = Math.Min((float)totalHexCount / Constants.CELL_SPECIALIZATION_STRENGTH_FULL_AT, 1);
strength *= Constants.CELL_SPECIALIZATION_STRENGTH_MULTIPLIER;

// Then return the final result as the bonus being anything above 1
Expand Down
5 changes: 4 additions & 1 deletion src/microbe_stage/MicrobeSpecies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,12 @@ public override void OnAttemptedInAutoEvo(bool refreshCache)

cachedFillTimes.Clear();

var nucleusDefinition =
SimulationParameters.Instance.GetOrganelleType("nucleus");

SpecializationBonus =
MicrobeInternalCalculations.CalculateSpecializationBonus(Organelles,
new Dictionary<OrganelleDefinition, int>());
new Dictionary<OrganelleDefinition, int>(), nucleusDefinition);
}

public override bool RepositionToOrigin()
Expand Down
6 changes: 4 additions & 2 deletions src/microbe_stage/editor/CellEditorComponent.GUI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -478,13 +478,15 @@ private void OnUnlockedOrganellesChanged()
private void UpdateSpecializationDisplay()
{
var specializationBonus =
MicrobeInternalCalculations.CalculateSpecializationBonus(editedMicrobeOrganelles, tempMemory3);
MicrobeInternalCalculations.CalculateSpecializationBonus(editedMicrobeOrganelles, tempMemory3,
nucleusDefinition);

// Calculate the most common organelle to show what we should recommend the player place more
var temp = tempMemory3;
var organelles = editedMicrobeOrganelles;

int organelleCount = MicrobeInternalCalculations.CalculateMostCommonSpecializationOrganelle(organelles, temp);
int organelleCount = MicrobeInternalCalculations.CalculateMostCommonSpecializationOrganelle(organelles, temp,
nucleusDefinition);

// And then with all the info, update the tooltip and display
if (organelleCount < 1)
Expand Down
9 changes: 7 additions & 2 deletions src/microbe_stage/editor/CellEditorComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ public partial class CellEditorComponent :

private readonly List<EditorUserOverride> ignoredEditorWarnings = new();

private readonly OrganelleDefinition nucleusDefinition =
SimulationParameters.Instance.GetOrganelleType("nucleus");

#pragma warning disable CA2213

// Selection menu tab selector buttons
Expand Down Expand Up @@ -2142,7 +2145,8 @@ private void CalculateEnergyAndCompoundBalance(IReadOnlyList<OrganelleTemplate>

var maximumMovementDirection = MicrobeInternalCalculations.MaximumSpeedDirection(organelles);

var specialization = MicrobeInternalCalculations.CalculateSpecializationBonus(organelles, tempMemory3);
var specialization = MicrobeInternalCalculations.CalculateSpecializationBonus(organelles, tempMemory3,
nucleusDefinition);

var tolerances = CalculateLatestTolerances();
ProcessSystem.ComputeEnergyBalanceFull(organelles, conditionsData, tolerances, specialization,
Expand Down Expand Up @@ -2219,7 +2223,8 @@ private void HandleProcessList(EnergyBalanceInfoFull energyBalance, IBiomeCondit
float consumptionProductionRatio = energyBalance.TotalConsumption / energyBalance.TotalProduction;

var specialization =
MicrobeInternalCalculations.CalculateSpecializationBonus(editedMicrobeOrganelles, tempMemory3);
MicrobeInternalCalculations.CalculateSpecializationBonus(editedMicrobeOrganelles, tempMemory3,
nucleusDefinition);

var speedModifier = tolerances.ProcessSpeedModifier * specialization;

Expand Down
5 changes: 4 additions & 1 deletion src/microbe_stage/editor/MicrobeEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ public partial class MicrobeEditor : EditorBase<EditorAction, MicrobeStage>, IEd
// loaded
private readonly MicrobeSpeciesComparer speciesComparer = new();

private readonly OrganelleDefinition nucleusDefinition =
SimulationParameters.Instance.GetOrganelleType("nucleus");

#pragma warning disable CA2213
[Export]
private MicrobeEditorReportComponent reportTab = null!;
Expand Down Expand Up @@ -631,7 +634,7 @@ private IPlayerDataSource GetPlayerDataSource()

var specialization =
MicrobeInternalCalculations.CalculateSpecializationBonus(editedSpecies.ModifiableOrganelles.Organelles,
tempMemory1);
tempMemory1, nucleusDefinition);

ProcessSystem.ComputeEnergyBalanceSimple(editedSpecies.ModifiableOrganelles.Organelles,
CurrentPatch.Biome, in tolerances, specialization, editedSpecies.MembraneType, Vector3.Zero, false, true,
Expand Down
4 changes: 3 additions & 1 deletion src/multicellular_stage/CellType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,11 @@ public bool IsMuscularTissueType()

public void CalculateSpecialization()
{
var nucleusDefinition =
SimulationParameters.Instance.GetOrganelleType("nucleus");
SpecializationBonus =
MicrobeInternalCalculations.CalculateSpecializationBonus(ModifiableOrganelles,
new Dictionary<OrganelleDefinition, int>());
new Dictionary<OrganelleDefinition, int>(), nucleusDefinition);
}

public void SetupWorldEntities(IWorldSimulation worldSimulation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ private void HandleProcessList(EnergyBalanceInfoFull energyBalance, IBiomeCondit

var specialization =
MicrobeInternalCalculations.CalculateSpecializationBonus(cellType.Key.ModifiableOrganelles,
tempMemory3);
tempMemory3, nucleusDefinition);

for (int i = 0; i < newProcesses.Count; ++i)
{
Expand Down Expand Up @@ -249,7 +249,8 @@ private void UpdateSpecializationDisplay()
var type = GetEditedCellDataIfEdited(cells[i].Data!.ModifiableCellType);

var specialization =
MicrobeInternalCalculations.CalculateSpecializationBonus(type.ModifiableOrganelles, tempMemory3);
MicrobeInternalCalculations.CalculateSpecializationBonus(type.ModifiableOrganelles, tempMemory3,
nucleusDefinition);

// TODO: calculate adjacency specialization values
// https://github.com/Revolutionary-Games/Thrive/issues/6764
Expand Down
11 changes: 8 additions & 3 deletions src/multicellular_stage/editor/CellBodyPlanEditorComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ public partial class CellBodyPlanEditorComponent :

private readonly Dictionary<CellType, int> cellTypesCount = new();

private readonly OrganelleDefinition nucleusDefinition =
SimulationParameters.Instance.GetOrganelleType("nucleus");

/// <summary>
/// Stores cells that end up being disconnected from the colony because of growth order
/// </summary>
Expand Down Expand Up @@ -1264,7 +1267,8 @@ private void UpdateCellTypeTooltipAndWarning(CellTypeTooltip tooltip, CellTypeSe
MicrobeInternalCalculations.MaximumSpeedDirection(cellType.ModifiableOrganelles);

var specialization =
MicrobeInternalCalculations.CalculateSpecializationBonus(cellType.ModifiableOrganelles, tempMemory3);
MicrobeInternalCalculations.CalculateSpecializationBonus(cellType.ModifiableOrganelles, tempMemory3,
nucleusDefinition);

ProcessSystem.ComputeEnergyBalanceFull(cellType.ModifiableOrganelles, Editor.CurrentPatch.Biome,
environmentalTolerances, specialization,
Expand Down Expand Up @@ -1454,7 +1458,8 @@ private void CalculateEnergyAndCompoundBalance(IReadOnlyList<HexWithData<CellTem
foreach (var hex in cells)
{
var specialization =
MicrobeInternalCalculations.CalculateSpecializationBonus(hex.Data!.ModifiableOrganelles, tempMemory3);
MicrobeInternalCalculations.CalculateSpecializationBonus(hex.Data!.ModifiableOrganelles, tempMemory3,
nucleusDefinition);

// TODO: adjacency bonuses from body plan (GetAdjacencySpecializationBonus)

Expand Down Expand Up @@ -1501,7 +1506,7 @@ private Dictionary<Compound, CompoundBalance> CalculateCompoundBalanceWithMethod
{
var organelles = GetEditedCellDataIfEdited(cell.Data!.ModifiableCellType).ModifiableOrganelles;
var specialization =
MicrobeInternalCalculations.CalculateSpecializationBonus(organelles, tempMemory3);
MicrobeInternalCalculations.CalculateSpecializationBonus(organelles, tempMemory3, nucleusDefinition);

// TODO: efficiency from cell layout positions (GetAdjacencySpecializationBonus)

Expand Down
4 changes: 3 additions & 1 deletion src/multicellular_stage/editor/MulticellularEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,8 @@ private IPlayerDataSource GetPlayerDataSource()
throw new Exception("Tried to get player unlocks data source without an edited species being set");
}

var nucleusDefinition = SimulationParameters.Instance.GetOrganelleType("nucleus");

var energyBalance = new EnergyBalanceInfoSimple();

var tolerances = MicrobeEnvironmentalToleranceCalculations.ResolveToleranceValues(
Expand All @@ -772,7 +774,7 @@ private IPlayerDataSource GetPlayerDataSource()
// TODO: specialization from positions (GetAdjacencySpecializationBonus)
var specialization =
MicrobeInternalCalculations.CalculateSpecializationBonus(cellType.ModifiableOrganelles.Organelles,
tempMemory1);
tempMemory1, nucleusDefinition);

ProcessSystem.ComputeEnergyBalanceSimple(cellType.ModifiableOrganelles.Organelles, CurrentPatch.Biome,
in tolerances, specialization, cellType.MembraneType, Vector3.Zero, false, true,
Expand Down