From 224cb54bc2bc0c9bba1264988d464e82766b64e0 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Wed, 11 Feb 2026 21:48:48 +0400 Subject: [PATCH 01/35] AI: Use move to me command if entity has binding agent AI_SIGNALING_CHANCE is so that it's not used a billion times per second (Thanks to Patryk26g for suggesting to use NextSingle instead of Next) This is only the very beginning of this. --- simulation_parameters/Constants.cs | 2 ++ src/microbe_stage/systems/MicrobeAISystem.cs | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/simulation_parameters/Constants.cs b/simulation_parameters/Constants.cs index 2aa4dee87cb..706f116942b 100644 --- a/simulation_parameters/Constants.cs +++ b/simulation_parameters/Constants.cs @@ -1280,6 +1280,8 @@ public static class Constants public const float AI_FOLLOW_DISTANCE_SQUARED = 60 * 60; public const float AI_FLEE_DISTANCE_SQUARED = 85 * 85; + public const float AI_SIGNALING_CHANCE = 0.05f; + public const float AI_BASE_TOXIN_SHOOT_ANGLE_PRECISION = 5; /// diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 64e10a6a80d..cb54278e98d 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -377,6 +377,15 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor ai.ATPThreshold = 0.0f; } + // Use signaling agent if I have any with a chance of 5% per think + if (organelles.HasSignalingAgent && random.NextSingle() < Constants.AI_SIGNALING_CHANCE) + { + if (organelles.HasBindingAgent) + { + signaling.QueuedSignalingCommand = MicrobeSignalCommand.MoveToMe; + } + } + // Follow received commands if we have them if (organelles.HasSignalingAgent && signaling.ReceivedCommand != MicrobeSignalCommand.None) { From 51c70e180b18defa4095a2d26d28769be9c17644 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Wed, 11 Feb 2026 23:37:04 +0400 Subject: [PATCH 02/35] AI Signaling Agent: Add else condition for no command --- src/microbe_stage/systems/MicrobeAISystem.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index cb54278e98d..bfdfbe103b4 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -384,6 +384,10 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor { signaling.QueuedSignalingCommand = MicrobeSignalCommand.MoveToMe; } + else + { + signaling.QueuedSignalingCommand = MicrobeSignalCommand.None; + } } // Follow received commands if we have them From 8d88abe370b446ee2d1d4e677e0685325b0902fa Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Wed, 11 Feb 2026 23:46:50 +0400 Subject: [PATCH 03/35] MicrobeAISystem.UseSignalingAgent() --- src/microbe_stage/systems/MicrobeAISystem.cs | 21 ++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index bfdfbe103b4..e49d3121794 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -380,14 +380,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor // Use signaling agent if I have any with a chance of 5% per think if (organelles.HasSignalingAgent && random.NextSingle() < Constants.AI_SIGNALING_CHANCE) { - if (organelles.HasBindingAgent) - { - signaling.QueuedSignalingCommand = MicrobeSignalCommand.MoveToMe; - } - else - { - signaling.QueuedSignalingCommand = MicrobeSignalCommand.None; - } + UseSignalingAgent(ref organelles, ref signaling); } // Follow received commands if we have them @@ -538,6 +531,18 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor } } + private void UseSignalingAgent(ref OrganelleContainer organelles, ref CommandSignaler signaling) + { + if (organelles.HasBindingAgent) + { + signaling.QueuedSignalingCommand = MicrobeSignalCommand.MoveToMe; + } + else + { + signaling.QueuedSignalingCommand = MicrobeSignalCommand.None; + } + } + private bool CheckForHuntingConditions(ref MicrobeAI ai, ref WorldPosition position, ref OrganelleContainer organelles, ref SpeciesMember ourSpecies, ref Engulfer engulfer, ref CellProperties cellProperties, ref MicrobeControl control, ref Health health, From d5ed2a014f69695c05ac65a5d22570fc023aa560 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Thu, 12 Feb 2026 20:51:33 +0400 Subject: [PATCH 04/35] Make UseSignalingAgent() return the command --- src/microbe_stage/systems/MicrobeAISystem.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index e49d3121794..efb6390d002 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -380,7 +380,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor // Use signaling agent if I have any with a chance of 5% per think if (organelles.HasSignalingAgent && random.NextSingle() < Constants.AI_SIGNALING_CHANCE) { - UseSignalingAgent(ref organelles, ref signaling); + signaling.QueuedSignalingCommand = UseSignalingAgent(ref organelles); } // Follow received commands if we have them @@ -531,15 +531,15 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor } } - private void UseSignalingAgent(ref OrganelleContainer organelles, ref CommandSignaler signaling) + private MicrobeSignalCommand UseSignalingAgent(ref OrganelleContainer organelles) { if (organelles.HasBindingAgent) { - signaling.QueuedSignalingCommand = MicrobeSignalCommand.MoveToMe; + return MicrobeSignalCommand.MoveToMe; } else { - signaling.QueuedSignalingCommand = MicrobeSignalCommand.None; + return MicrobeSignalCommand.None; } } From e491f3dc67eeee2afb4c85ae30352b5eb551217b Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Thu, 12 Feb 2026 20:57:57 +0400 Subject: [PATCH 05/35] Make returning no command outside of conditions --- src/microbe_stage/systems/MicrobeAISystem.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index efb6390d002..569ff05c682 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -537,10 +537,8 @@ private MicrobeSignalCommand UseSignalingAgent(ref OrganelleContainer organelles { return MicrobeSignalCommand.MoveToMe; } - else - { - return MicrobeSignalCommand.None; - } + + return MicrobeSignalCommand.None; } private bool CheckForHuntingConditions(ref MicrobeAI ai, ref WorldPosition position, From 2d9a1c69ab50976d42428cddd400a828777f735d Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Thu, 12 Feb 2026 21:39:44 +0400 Subject: [PATCH 06/35] Start adding conditions for predation --- src/microbe_stage/systems/MicrobeAISystem.cs | 27 +++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 569ff05c682..d85975b4339 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -380,7 +380,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor // Use signaling agent if I have any with a chance of 5% per think if (organelles.HasSignalingAgent && random.NextSingle() < Constants.AI_SIGNALING_CHANCE) { - signaling.QueuedSignalingCommand = UseSignalingAgent(ref organelles); + signaling.QueuedSignalingCommand = UseSignalingAgent(ref organelles, speciesAggression, random); } // Follow received commands if we have them @@ -531,13 +531,34 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor } } - private MicrobeSignalCommand UseSignalingAgent(ref OrganelleContainer organelles) + private MicrobeSignalCommand UseSignalingAgent(ref OrganelleContainer organelles, float speciesAggression, + Random random) { + var willBeAggressiveThisTime = RollCheck(speciesAggression, Constants.MAX_SPECIES_AGGRESSION, random); + if (organelles.HasBindingAgent) { return MicrobeSignalCommand.MoveToMe; } - + else if (willBeAggressiveThisTime) + { + foreach (var organelle in organelles.Organelles!) + { + if (organelle.Definition.HasPilusComponent) + { + return MicrobeSignalCommand.FollowMe; + } + else + { + return MicrobeSignalCommand.None; + } + } + } + else if (!willBeAggressiveThisTime) + { + // TOOD + } + return MicrobeSignalCommand.None; } From a45ef6bd9e6bbbdcdee41316810269ed9b577aad Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Thu, 12 Feb 2026 22:05:40 +0400 Subject: [PATCH 07/35] Comply with JetBrains check --- src/microbe_stage/systems/MicrobeAISystem.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index d85975b4339..4f40451a244 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -540,7 +540,8 @@ private MicrobeSignalCommand UseSignalingAgent(ref OrganelleContainer organelles { return MicrobeSignalCommand.MoveToMe; } - else if (willBeAggressiveThisTime) + + if (willBeAggressiveThisTime) { foreach (var organelle in organelles.Organelles!) { @@ -548,10 +549,8 @@ private MicrobeSignalCommand UseSignalingAgent(ref OrganelleContainer organelles { return MicrobeSignalCommand.FollowMe; } - else - { - return MicrobeSignalCommand.None; - } + + return MicrobeSignalCommand.None; } } else if (!willBeAggressiveThisTime) From 144a74b7826fe7e128fb0912f6b1d6f8ea5f4f79 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Fri, 13 Feb 2026 11:42:24 +0400 Subject: [PATCH 08/35] Make UseSignalingAgent() set commands directly again --- src/microbe_stage/systems/MicrobeAISystem.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 4f40451a244..9cdcf3b5cb3 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -380,7 +380,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor // Use signaling agent if I have any with a chance of 5% per think if (organelles.HasSignalingAgent && random.NextSingle() < Constants.AI_SIGNALING_CHANCE) { - signaling.QueuedSignalingCommand = UseSignalingAgent(ref organelles, speciesAggression, random); + UseSignalingAgent(ref organelles, speciesAggression, ref signaling, random); } // Follow received commands if we have them @@ -531,14 +531,14 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor } } - private MicrobeSignalCommand UseSignalingAgent(ref OrganelleContainer organelles, float speciesAggression, - Random random) + private void UseSignalingAgent(ref OrganelleContainer organelles, float speciesAggression, + ref CommandSignaler signaling, Random random) { var willBeAggressiveThisTime = RollCheck(speciesAggression, Constants.MAX_SPECIES_AGGRESSION, random); if (organelles.HasBindingAgent) { - return MicrobeSignalCommand.MoveToMe; + signaling.QueuedSignalingCommand = MicrobeSignalCommand.MoveToMe; } if (willBeAggressiveThisTime) @@ -547,18 +547,17 @@ private MicrobeSignalCommand UseSignalingAgent(ref OrganelleContainer organelles { if (organelle.Definition.HasPilusComponent) { - return MicrobeSignalCommand.FollowMe; + signaling.QueuedSignalingCommand = MicrobeSignalCommand.FollowMe; + break; } - return MicrobeSignalCommand.None; + signaling.QueuedSignalingCommand = MicrobeSignalCommand.None; } } else if (!willBeAggressiveThisTime) { // TOOD } - - return MicrobeSignalCommand.None; } private bool CheckForHuntingConditions(ref MicrobeAI ai, ref WorldPosition position, From 4d8bc4339b1602877dad6e8009818df4e6298c4a Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Sat, 14 Feb 2026 21:26:37 +0400 Subject: [PATCH 09/35] Add "or has toxins" to pili condition --- src/microbe_stage/systems/MicrobeAISystem.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 9cdcf3b5cb3..668ff29cb47 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -545,7 +545,8 @@ private void UseSignalingAgent(ref OrganelleContainer organelles, float speciesA { foreach (var organelle in organelles.Organelles!) { - if (organelle.Definition.HasPilusComponent) + // Has pili or toxins + if (organelle.Definition.HasPilusComponent || organelles.AgentVacuoleCount > 0) { signaling.QueuedSignalingCommand = MicrobeSignalCommand.FollowMe; break; From e9f19325aa75af208da3b68040e866df162553da Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Sat, 14 Feb 2026 22:10:40 +0400 Subject: [PATCH 10/35] MicrobeControl.Fleeing --- src/microbe_stage/components/MicrobeControl.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/microbe_stage/components/MicrobeControl.cs b/src/microbe_stage/components/MicrobeControl.cs index 0f68065eb12..55c829e3ec0 100644 --- a/src/microbe_stage/components/MicrobeControl.cs +++ b/src/microbe_stage/components/MicrobeControl.cs @@ -94,6 +94,11 @@ public struct MicrobeControl : IArchivableComponent /// public bool MucocystEffectsApplied; + /// + /// Whether this microbe is currently fleeing + /// + public bool Fleeing; + /// /// Constructs an instance with a sensible set /// @@ -111,6 +116,7 @@ public MicrobeControl(Vector3 startingPosition) SlowedBySlime = false; Sprinting = false; MucocystEffectsApplied = false; + Fleeing = false; } public ushort CurrentArchiveVersion => SERIALIZATION_VERSION; @@ -133,6 +139,7 @@ public void WriteToArchive(ISArchiveWriter writer) writer.Write(OutOfSprint); writer.Write(Sprinting); writer.Write(MucocystEffectsApplied); + writer.Write(Fleeing); } } @@ -159,6 +166,7 @@ public static MicrobeControl ReadFromArchive(ISArchiveReader reader, ushort vers OutOfSprint = reader.ReadBool(), Sprinting = reader.ReadBool(), MucocystEffectsApplied = reader.ReadBool(), + Fleeing = reader.ReadBool(), }; } From 8195e5938d211aa66e9fd351d0d1d6360c975ad5 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Sat, 14 Feb 2026 22:14:35 +0400 Subject: [PATCH 11/35] Set control.Fleeing in ChooseActions() --- src/microbe_stage/systems/MicrobeAISystem.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 668ff29cb47..0416654159a 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -286,6 +286,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor float speciesOpportunism = speciesBehaviour.Opportunism; control.Sprinting = false; + control.Fleeing = false; // If nothing is engulfing me right now, see if there's something that might want to hunt me (Entity Entity, Vector3 Position, float EngulfSize)? predator = @@ -297,9 +298,13 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor if (control.State == MicrobeState.MucocystShield) return; + control.Fleeing = true; + FleeFromPredators(ref position, ref ai, ref control, ref organelles, ref compoundStorage, entity, predator.Value.Position, predator.Value.Entity, speciesFocus, speciesActivity, speciesAggression, speciesFear, strain, random); + + control.Fleeing = false; return; } From ecca883dd756fe6f99ff88f28b5f8d215cbcb39b Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Sun, 15 Feb 2026 14:00:36 +0400 Subject: [PATCH 12/35] Use flee from me command if fleeing --- src/microbe_stage/systems/MicrobeAISystem.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 0416654159a..4edb71a29af 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -385,7 +385,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor // Use signaling agent if I have any with a chance of 5% per think if (organelles.HasSignalingAgent && random.NextSingle() < Constants.AI_SIGNALING_CHANCE) { - UseSignalingAgent(ref organelles, speciesAggression, ref signaling, random); + UseSignalingAgent(ref organelles, speciesAggression, ref signaling, ref control, random); } // Follow received commands if we have them @@ -537,7 +537,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor } private void UseSignalingAgent(ref OrganelleContainer organelles, float speciesAggression, - ref CommandSignaler signaling, Random random) + ref CommandSignaler signaling, ref MicrobeControl control, Random random) { var willBeAggressiveThisTime = RollCheck(speciesAggression, Constants.MAX_SPECIES_AGGRESSION, random); @@ -564,6 +564,11 @@ private void UseSignalingAgent(ref OrganelleContainer organelles, float speciesA { // TOOD } + + if (control.Fleeing) + { + signaling.QueuedSignalingCommand = MicrobeSignalCommand.FleeFromMe; + } } private bool CheckForHuntingConditions(ref MicrobeAI ai, ref WorldPosition position, From 36de1a4b1bddb9fb78653572b656abaa9a6aee41 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Sun, 15 Feb 2026 17:27:07 +0400 Subject: [PATCH 13/35] Remove control.Fleeing = false line --- src/microbe_stage/systems/MicrobeAISystem.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 4edb71a29af..339b49c8cb4 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -303,8 +303,6 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor FleeFromPredators(ref position, ref ai, ref control, ref organelles, ref compoundStorage, entity, predator.Value.Position, predator.Value.Entity, speciesFocus, speciesActivity, speciesAggression, speciesFear, strain, random); - - control.Fleeing = false; return; } From f5fc4c8a1ad4ad50db8aae0f99860315d0f44f6c Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Mon, 16 Feb 2026 14:24:29 +0400 Subject: [PATCH 14/35] Remove exact chance from comment --- src/microbe_stage/systems/MicrobeAISystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 339b49c8cb4..055b1d2155e 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -380,7 +380,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor ai.ATPThreshold = 0.0f; } - // Use signaling agent if I have any with a chance of 5% per think + // Use signaling agent if I have any with a small chance per think if (organelles.HasSignalingAgent && random.NextSingle() < Constants.AI_SIGNALING_CHANCE) { UseSignalingAgent(ref organelles, speciesAggression, ref signaling, ref control, random); From 07f62e282a3a494c9ba704df63b2172edd2b3d8c Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Mon, 16 Feb 2026 14:30:00 +0400 Subject: [PATCH 15/35] Move Fleeing to MicrobeAI and increment SERIALIZATION_VERSION --- src/microbe_stage/components/MicrobeAI.cs | 9 ++++++++- src/microbe_stage/components/MicrobeControl.cs | 8 -------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/microbe_stage/components/MicrobeAI.cs b/src/microbe_stage/components/MicrobeAI.cs index 7f0e1afa083..9b19440e4e8 100644 --- a/src/microbe_stage/components/MicrobeAI.cs +++ b/src/microbe_stage/components/MicrobeAI.cs @@ -14,7 +14,7 @@ /// public struct MicrobeAI : IArchivableComponent { - public const ushort SERIALIZATION_VERSION = 1; + public const ushort SERIALIZATION_VERSION = 2; public float TimeUntilNextThink; @@ -50,6 +50,11 @@ public struct MicrobeAI : IArchivableComponent public bool HasBeenNearPlayer; + /// + /// Whether this microbe is currently fleeing + /// + public bool Fleeing; + public ushort CurrentArchiveVersion => SERIALIZATION_VERSION; public ThriveArchiveObjectType ArchiveObjectType => ThriveArchiveObjectType.ComponentMicrobeAI; @@ -63,6 +68,7 @@ public void WriteToArchive(ISArchiveWriter writer) writer.Write(PursuitThreshold); writer.Write(ATPThreshold); writer.Write(HasBeenNearPlayer); + writer.Write(Fleeing); writer.Write(LastSmelledCompoundPosition.HasValue); if (LastSmelledCompoundPosition.HasValue) @@ -95,6 +101,7 @@ public static MicrobeAI ReadFromArchive(ISArchiveReader reader, ushort version) PursuitThreshold = reader.ReadFloat(), ATPThreshold = reader.ReadFloat(), HasBeenNearPlayer = reader.ReadBool(), + Fleeing = reader.ReadBool(), }; if (reader.ReadBool()) diff --git a/src/microbe_stage/components/MicrobeControl.cs b/src/microbe_stage/components/MicrobeControl.cs index 55c829e3ec0..0f68065eb12 100644 --- a/src/microbe_stage/components/MicrobeControl.cs +++ b/src/microbe_stage/components/MicrobeControl.cs @@ -94,11 +94,6 @@ public struct MicrobeControl : IArchivableComponent /// public bool MucocystEffectsApplied; - /// - /// Whether this microbe is currently fleeing - /// - public bool Fleeing; - /// /// Constructs an instance with a sensible set /// @@ -116,7 +111,6 @@ public MicrobeControl(Vector3 startingPosition) SlowedBySlime = false; Sprinting = false; MucocystEffectsApplied = false; - Fleeing = false; } public ushort CurrentArchiveVersion => SERIALIZATION_VERSION; @@ -139,7 +133,6 @@ public void WriteToArchive(ISArchiveWriter writer) writer.Write(OutOfSprint); writer.Write(Sprinting); writer.Write(MucocystEffectsApplied); - writer.Write(Fleeing); } } @@ -166,7 +159,6 @@ public static MicrobeControl ReadFromArchive(ISArchiveReader reader, ushort vers OutOfSprint = reader.ReadBool(), Sprinting = reader.ReadBool(), MucocystEffectsApplied = reader.ReadBool(), - Fleeing = reader.ReadBool(), }; } From 08cbe44f3f76c7a4ab30102a24147512e7360aaa Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Mon, 16 Feb 2026 14:40:49 +0400 Subject: [PATCH 16/35] Handle reading Fleeing for SERIALIZATION_VERSION == 1 --- src/microbe_stage/components/MicrobeAI.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/microbe_stage/components/MicrobeAI.cs b/src/microbe_stage/components/MicrobeAI.cs index 9b19440e4e8..20eed1947d1 100644 --- a/src/microbe_stage/components/MicrobeAI.cs +++ b/src/microbe_stage/components/MicrobeAI.cs @@ -101,7 +101,7 @@ public static MicrobeAI ReadFromArchive(ISArchiveReader reader, ushort version) PursuitThreshold = reader.ReadFloat(), ATPThreshold = reader.ReadFloat(), HasBeenNearPlayer = reader.ReadBool(), - Fleeing = reader.ReadBool(), + Fleeing = version > 1 && reader.ReadBool(), }; if (reader.ReadBool()) From c75875509eb7592cd64e40f82da49b87b1c611b1 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Mon, 16 Feb 2026 14:46:21 +0400 Subject: [PATCH 17/35] Correct control.Fleeing to ai.Fleeing --- src/microbe_stage/systems/MicrobeAISystem.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 055b1d2155e..c9f8560cfdb 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -286,7 +286,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor float speciesOpportunism = speciesBehaviour.Opportunism; control.Sprinting = false; - control.Fleeing = false; + ai.Fleeing = false; // If nothing is engulfing me right now, see if there's something that might want to hunt me (Entity Entity, Vector3 Position, float EngulfSize)? predator = @@ -298,7 +298,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor if (control.State == MicrobeState.MucocystShield) return; - control.Fleeing = true; + ai.Fleeing = true; FleeFromPredators(ref position, ref ai, ref control, ref organelles, ref compoundStorage, entity, predator.Value.Position, predator.Value.Entity, speciesFocus, @@ -383,7 +383,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor // Use signaling agent if I have any with a small chance per think if (organelles.HasSignalingAgent && random.NextSingle() < Constants.AI_SIGNALING_CHANCE) { - UseSignalingAgent(ref organelles, speciesAggression, ref signaling, ref control, random); + UseSignalingAgent(ref ai, ref organelles, speciesAggression, ref signaling, random); } // Follow received commands if we have them @@ -534,8 +534,8 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor } } - private void UseSignalingAgent(ref OrganelleContainer organelles, float speciesAggression, - ref CommandSignaler signaling, ref MicrobeControl control, Random random) + private void UseSignalingAgent(ref MicrobeAI ai, ref OrganelleContainer organelles, float speciesAggression, + ref CommandSignaler signaling, Random random) { var willBeAggressiveThisTime = RollCheck(speciesAggression, Constants.MAX_SPECIES_AGGRESSION, random); @@ -563,7 +563,7 @@ private void UseSignalingAgent(ref OrganelleContainer organelles, float speciesA // TOOD } - if (control.Fleeing) + if (ai.Fleeing) { signaling.QueuedSignalingCommand = MicrobeSignalCommand.FleeFromMe; } From 0920682d04b6b660deb9993976c52fae7e4e0d6b Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Mon, 16 Feb 2026 20:04:15 +0400 Subject: [PATCH 18/35] Add else conditions that set command to none --- src/microbe_stage/systems/MicrobeAISystem.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index c9f8560cfdb..0b9db1c4e92 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -558,15 +558,20 @@ private void UseSignalingAgent(ref MicrobeAI ai, ref OrganelleContainer organell signaling.QueuedSignalingCommand = MicrobeSignalCommand.None; } } - else if (!willBeAggressiveThisTime) + else { - // TOOD + // TODO: should probably add more + signaling.QueuedSignalingCommand = MicrobeSignalCommand.None; } if (ai.Fleeing) { signaling.QueuedSignalingCommand = MicrobeSignalCommand.FleeFromMe; } + else + { + signaling.QueuedSignalingCommand = MicrobeSignalCommand.None; + } } private bool CheckForHuntingConditions(ref MicrobeAI ai, ref WorldPosition position, From 74ac805aa19f10533e5dd26bc9672d67735e1bea Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Tue, 17 Feb 2026 16:25:31 +0400 Subject: [PATCH 19/35] Add and use AI_MOVE_DISTANCE_SQUARED --- simulation_parameters/Constants.cs | 1 + src/microbe_stage/systems/MicrobeAISystem.cs | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/simulation_parameters/Constants.cs b/simulation_parameters/Constants.cs index 706f116942b..5335c8d6e99 100644 --- a/simulation_parameters/Constants.cs +++ b/simulation_parameters/Constants.cs @@ -1279,6 +1279,7 @@ public static class Constants public const float AI_FOLLOW_DISTANCE_SQUARED = 60 * 60; public const float AI_FLEE_DISTANCE_SQUARED = 85 * 85; + public const float AI_MOVE_DISTANCE_SQUARED = 240 * 240; public const float AI_SIGNALING_CHANCE = 0.05f; diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 0b9db1c4e92..bc8cdbbdc39 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -399,8 +399,13 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor // was smelled from if (signaling.ReceivedCommandFromEntity.IsAliveAndHas()) { - ai.MoveToLocation(signaling.ReceivedCommandFromEntity.Get().Position, - ref control, entity); + var signalerPosition = signaling.ReceivedCommandFromEntity.Get().Position; + if (position.Position.DistanceSquaredTo(signalerPosition) < + Constants.AI_MOVE_DISTANCE_SQUARED) + { + ai.MoveToLocation(signalerPosition, ref control, entity); + } + return; } @@ -413,7 +418,9 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor { var signalerPosition = signaling.ReceivedCommandFromEntity.Get().Position; if (position.Position.DistanceSquaredTo(signalerPosition) > - Constants.AI_FOLLOW_DISTANCE_SQUARED) + Constants.AI_FOLLOW_DISTANCE_SQUARED && + position.Position.DistanceSquaredTo(signalerPosition) < + Constants.AI_MOVE_DISTANCE_SQUARED) { ai.MoveToLocation(signalerPosition, ref control, entity); } From 4c1708ea343a6168c361bf64fa98855a4aefe032 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Tue, 17 Feb 2026 16:37:47 +0400 Subject: [PATCH 20/35] Add and use AI_BECOME_AGGRESSIVE_DISTANCE_SQUARED --- simulation_parameters/Constants.cs | 1 + src/microbe_stage/systems/MicrobeAISystem.cs | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/simulation_parameters/Constants.cs b/simulation_parameters/Constants.cs index 5335c8d6e99..18af10411f3 100644 --- a/simulation_parameters/Constants.cs +++ b/simulation_parameters/Constants.cs @@ -1277,6 +1277,7 @@ public static class Constants public const float AI_BASE_MOVEMENT = 1.0f; public const float AI_ENGULF_STOP_DISTANCE = 0.8f; + public const float AI_BECOME_AGGRESSIVE_DISTANCE_SQUARED = 120 * 120; public const float AI_FOLLOW_DISTANCE_SQUARED = 60 * 60; public const float AI_FLEE_DISTANCE_SQUARED = 85 * 85; public const float AI_MOVE_DISTANCE_SQUARED = 240 * 240; diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index bc8cdbbdc39..742b27208d1 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -263,10 +263,14 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor var compounds = compoundStorage.Compounds; + var signalerPosition = signaling.ReceivedCommandFromEntity.Get().Position; + // Adjusted behaviour values (calculated here as these are needed by various methods) var speciesBehaviour = ourSpecies.Species.Behaviour; float speciesAggression = speciesBehaviour.Aggression * - (signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive ? 1.5f : 1.0f); + (signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive && + position.Position.DistanceSquaredTo(signalerPosition) < Constants.AI_BECOME_AGGRESSIVE_DISTANCE_SQUARED + ? 1.5f : 1.0f); float speciesFear = speciesBehaviour.Fear * (signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive ? 0.75f : 1.0f); @@ -399,7 +403,6 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor // was smelled from if (signaling.ReceivedCommandFromEntity.IsAliveAndHas()) { - var signalerPosition = signaling.ReceivedCommandFromEntity.Get().Position; if (position.Position.DistanceSquaredTo(signalerPosition) < Constants.AI_MOVE_DISTANCE_SQUARED) { @@ -416,7 +419,6 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor { if (signaling.ReceivedCommandFromEntity.IsAliveAndHas()) { - var signalerPosition = signaling.ReceivedCommandFromEntity.Get().Position; if (position.Position.DistanceSquaredTo(signalerPosition) > Constants.AI_FOLLOW_DISTANCE_SQUARED && position.Position.DistanceSquaredTo(signalerPosition) < @@ -435,7 +437,6 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor { if (signaling.ReceivedCommandFromEntity.IsAliveAndHas()) { - var signalerPosition = signaling.ReceivedCommandFromEntity.Get().Position; if (position.Position.DistanceSquaredTo(signalerPosition) < Constants.AI_FLEE_DISTANCE_SQUARED) { From d471a74086b45b59530c5b6098b0fee7a900f446 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Tue, 17 Feb 2026 17:38:07 +0400 Subject: [PATCH 21/35] Fix indentation --- src/microbe_stage/systems/MicrobeAISystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 742b27208d1..7b092862ca3 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -269,8 +269,8 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor var speciesBehaviour = ourSpecies.Species.Behaviour; float speciesAggression = speciesBehaviour.Aggression * (signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive && - position.Position.DistanceSquaredTo(signalerPosition) < Constants.AI_BECOME_AGGRESSIVE_DISTANCE_SQUARED - ? 1.5f : 1.0f); + position.Position.DistanceSquaredTo(signalerPosition) < Constants.AI_BECOME_AGGRESSIVE_DISTANCE_SQUARED + ? 1.5f : 1.0f); float speciesFear = speciesBehaviour.Fear * (signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive ? 0.75f : 1.0f); From 43032a911d109384071103ebdaf8e3e2adea4c3d Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Tue, 17 Feb 2026 17:48:23 +0400 Subject: [PATCH 22/35] Fix indentation MicrobeAISystem.cs:273 --- src/microbe_stage/systems/MicrobeAISystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 7b092862ca3..afd562d4d4f 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -270,7 +270,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor float speciesAggression = speciesBehaviour.Aggression * (signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive && position.Position.DistanceSquaredTo(signalerPosition) < Constants.AI_BECOME_AGGRESSIVE_DISTANCE_SQUARED - ? 1.5f : 1.0f); + ? 1.5f : 1.0f); float speciesFear = speciesBehaviour.Fear * (signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive ? 0.75f : 1.0f); From 16a1d7e6bf97a0506da78479b1447df6123cafa9 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Tue, 17 Feb 2026 18:00:17 +0400 Subject: [PATCH 23/35] Edit ternary operator to comply with JetBrains --- src/microbe_stage/systems/MicrobeAISystem.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index afd562d4d4f..b4783bb8062 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -269,8 +269,10 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor var speciesBehaviour = ourSpecies.Species.Behaviour; float speciesAggression = speciesBehaviour.Aggression * (signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive && - position.Position.DistanceSquaredTo(signalerPosition) < Constants.AI_BECOME_AGGRESSIVE_DISTANCE_SQUARED - ? 1.5f : 1.0f); + position.Position.DistanceSquaredTo(signalerPosition) < + Constants.AI_BECOME_AGGRESSIVE_DISTANCE_SQUARED ? + 1.5f : + 1.0f); float speciesFear = speciesBehaviour.Fear * (signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive ? 0.75f : 1.0f); From b98eb163facec70f67195be91ae0217d5b9bb605 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Wed, 18 Feb 2026 13:19:04 +0400 Subject: [PATCH 24/35] Move flee from me command to outside of UseSignalingAgent() Hopefully this is only a temporary workaround. --- src/microbe_stage/systems/MicrobeAISystem.cs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index b4783bb8062..13f5d42e577 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -309,6 +309,9 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor FleeFromPredators(ref position, ref ai, ref control, ref organelles, ref compoundStorage, entity, predator.Value.Position, predator.Value.Entity, speciesFocus, speciesActivity, speciesAggression, speciesFear, strain, random); + + signaling.QueuedSignalingCommand = MicrobeSignalCommand.FleeFromMe; + return; } @@ -574,14 +577,7 @@ private void UseSignalingAgent(ref MicrobeAI ai, ref OrganelleContainer organell signaling.QueuedSignalingCommand = MicrobeSignalCommand.None; } - if (ai.Fleeing) - { - signaling.QueuedSignalingCommand = MicrobeSignalCommand.FleeFromMe; - } - else - { - signaling.QueuedSignalingCommand = MicrobeSignalCommand.None; - } + signaling.QueuedSignalingCommand = MicrobeSignalCommand.None; } private bool CheckForHuntingConditions(ref MicrobeAI ai, ref WorldPosition position, From 880c09f6aa0020aabe6f5d06648b74ebececbd2b Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Wed, 18 Feb 2026 16:43:19 +0400 Subject: [PATCH 25/35] Remove MicrobeAI.Fleeing as it is now useless --- src/microbe_stage/components/MicrobeAI.cs | 9 +-------- src/microbe_stage/systems/MicrobeAISystem.cs | 3 --- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/microbe_stage/components/MicrobeAI.cs b/src/microbe_stage/components/MicrobeAI.cs index 20eed1947d1..7f0e1afa083 100644 --- a/src/microbe_stage/components/MicrobeAI.cs +++ b/src/microbe_stage/components/MicrobeAI.cs @@ -14,7 +14,7 @@ /// public struct MicrobeAI : IArchivableComponent { - public const ushort SERIALIZATION_VERSION = 2; + public const ushort SERIALIZATION_VERSION = 1; public float TimeUntilNextThink; @@ -50,11 +50,6 @@ public struct MicrobeAI : IArchivableComponent public bool HasBeenNearPlayer; - /// - /// Whether this microbe is currently fleeing - /// - public bool Fleeing; - public ushort CurrentArchiveVersion => SERIALIZATION_VERSION; public ThriveArchiveObjectType ArchiveObjectType => ThriveArchiveObjectType.ComponentMicrobeAI; @@ -68,7 +63,6 @@ public void WriteToArchive(ISArchiveWriter writer) writer.Write(PursuitThreshold); writer.Write(ATPThreshold); writer.Write(HasBeenNearPlayer); - writer.Write(Fleeing); writer.Write(LastSmelledCompoundPosition.HasValue); if (LastSmelledCompoundPosition.HasValue) @@ -101,7 +95,6 @@ public static MicrobeAI ReadFromArchive(ISArchiveReader reader, ushort version) PursuitThreshold = reader.ReadFloat(), ATPThreshold = reader.ReadFloat(), HasBeenNearPlayer = reader.ReadBool(), - Fleeing = version > 1 && reader.ReadBool(), }; if (reader.ReadBool()) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 13f5d42e577..152217275f1 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -292,7 +292,6 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor float speciesOpportunism = speciesBehaviour.Opportunism; control.Sprinting = false; - ai.Fleeing = false; // If nothing is engulfing me right now, see if there's something that might want to hunt me (Entity Entity, Vector3 Position, float EngulfSize)? predator = @@ -304,8 +303,6 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor if (control.State == MicrobeState.MucocystShield) return; - ai.Fleeing = true; - FleeFromPredators(ref position, ref ai, ref control, ref organelles, ref compoundStorage, entity, predator.Value.Position, predator.Value.Entity, speciesFocus, speciesActivity, speciesAggression, speciesFear, strain, random); From 6340dba0f7196e60d967e2a7252abebe8bb7966d Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Wed, 18 Feb 2026 16:53:21 +0400 Subject: [PATCH 26/35] Remove unused parameter --- src/microbe_stage/systems/MicrobeAISystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 152217275f1..4141841f306 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -389,7 +389,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor // Use signaling agent if I have any with a small chance per think if (organelles.HasSignalingAgent && random.NextSingle() < Constants.AI_SIGNALING_CHANCE) { - UseSignalingAgent(ref ai, ref organelles, speciesAggression, ref signaling, random); + UseSignalingAgent(ref organelles, speciesAggression, ref signaling, random); } // Follow received commands if we have them @@ -544,7 +544,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor } } - private void UseSignalingAgent(ref MicrobeAI ai, ref OrganelleContainer organelles, float speciesAggression, + private void UseSignalingAgent(ref OrganelleContainer organelles, float speciesAggression, ref CommandSignaler signaling, Random random) { var willBeAggressiveThisTime = RollCheck(speciesAggression, Constants.MAX_SPECIES_AGGRESSION, random); From ef56fc860d6a6eed901b389874ec159340ccc7a0 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Wed, 18 Feb 2026 20:41:43 +0400 Subject: [PATCH 27/35] Fix signalerPosition --- src/microbe_stage/systems/MicrobeAISystem.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 4141841f306..c7b4b69c0b9 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -263,7 +263,10 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor var compounds = compoundStorage.Compounds; - var signalerPosition = signaling.ReceivedCommandFromEntity.Get().Position; + var signalerPosition = + signaling.ReceivedCommand != MicrobeSignalCommand.None && entity.IsAliveAndHas() ? + signaling.ReceivedCommandFromEntity.Get().Position : + new Vector3(0, 0, 0); // Adjusted behaviour values (calculated here as these are needed by various methods) var speciesBehaviour = ourSpecies.Species.Behaviour; From 66cff35ed84a796c3d95dab87f57d3d97b0d2b0d Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Wed, 18 Feb 2026 21:36:57 +0400 Subject: [PATCH 28/35] Fix AI use of flee from me command --- src/microbe_stage/systems/MicrobeAISystem.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index c7b4b69c0b9..a21753e7642 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -310,7 +310,10 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor predator.Value.Position, predator.Value.Entity, speciesFocus, speciesActivity, speciesAggression, speciesFear, strain, random); - signaling.QueuedSignalingCommand = MicrobeSignalCommand.FleeFromMe; + if (organelles.HasSignalingAgent && random.NextSingle() < Constants.AI_SIGNALING_CHANCE) + { + signaling.QueuedSignalingCommand = MicrobeSignalCommand.FleeFromMe; + } return; } From 8ae66c4f6493e7585609886936176f1b6b055259 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Mon, 23 Feb 2026 15:23:34 +0400 Subject: [PATCH 29/35] Improve signalerPosition assignment Thanks hhyyrylainen --- src/microbe_stage/systems/MicrobeAISystem.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index a21753e7642..2ef4c97d47c 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -263,10 +263,17 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor var compounds = compoundStorage.Compounds; - var signalerPosition = - signaling.ReceivedCommand != MicrobeSignalCommand.None && entity.IsAliveAndHas() ? - signaling.ReceivedCommandFromEntity.Get().Position : - new Vector3(0, 0, 0); + bool signalExists = signaling.ReceivedCommand != MicrobeSignalCommand.None; + Vector3 signalerPosition = default; + + if (signaling.ReceivedCommand != MicrobeSignalCommand.None && entity.IsAliveAndHas()) + { + signalerPosition = signaling.ReceivedCommandFromEntity.Get().Position; + } + else + { + signalExists = false; + } // Adjusted behaviour values (calculated here as these are needed by various methods) var speciesBehaviour = ourSpecies.Species.Behaviour; @@ -399,7 +406,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor } // Follow received commands if we have them - if (organelles.HasSignalingAgent && signaling.ReceivedCommand != MicrobeSignalCommand.None) + if (organelles.HasSignalingAgent && signalExists) { // TODO: tweak the balance between following commands and doing normal behaviours // TODO: and also probably we want to add some randomness to the positions and speeds based on distance From 3426b6129670b757a4a78a35d717edc6775962a0 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Tue, 24 Feb 2026 23:29:07 +0400 Subject: [PATCH 30/35] Use signalExists in signalerPosition condition --- src/microbe_stage/systems/MicrobeAISystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 2ef4c97d47c..44b2d977372 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -266,7 +266,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor bool signalExists = signaling.ReceivedCommand != MicrobeSignalCommand.None; Vector3 signalerPosition = default; - if (signaling.ReceivedCommand != MicrobeSignalCommand.None && entity.IsAliveAndHas()) + if (signalExists && entity.IsAliveAndHas()) { signalerPosition = signaling.ReceivedCommandFromEntity.Get().Position; } From 01abd060c189db979e09d18fcb7a3e7e2a3a0749 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Wed, 25 Feb 2026 00:16:27 +0400 Subject: [PATCH 31/35] Fulfill (some of) Patryk26g's requests --- src/microbe_stage/systems/MicrobeAISystem.cs | 32 +++++++++----------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 44b2d977372..7cca1643386 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -263,12 +263,15 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor var compounds = compoundStorage.Compounds; - bool signalExists = signaling.ReceivedCommand != MicrobeSignalCommand.None; + bool signalExists = signaling.ReceivedCommand != MicrobeSignalCommand.None && + entity.IsAliveAndHas(); Vector3 signalerPosition = default; + float squaredDistanceToSignaler = default; - if (signalExists && entity.IsAliveAndHas()) + if (signalExists) { signalerPosition = signaling.ReceivedCommandFromEntity.Get().Position; + squaredDistanceToSignaler = position.Position.DistanceSquaredTo(signalerPosition); } else { @@ -277,18 +280,17 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor // Adjusted behaviour values (calculated here as these are needed by various methods) var speciesBehaviour = ourSpecies.Species.Behaviour; + var willAdjustBehaviourValues = signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive && + squaredDistanceToSignaler < Constants.AI_BECOME_AGGRESSIVE_DISTANCE_SQUARED; + float speciesAggression = speciesBehaviour.Aggression * - (signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive && - position.Position.DistanceSquaredTo(signalerPosition) < - Constants.AI_BECOME_AGGRESSIVE_DISTANCE_SQUARED ? - 1.5f : - 1.0f); + (willAdjustBehaviourValues ? 1.5f : 1.0f); float speciesFear = speciesBehaviour.Fear * - (signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive ? 0.75f : 1.0f); + (willAdjustBehaviourValues ? 0.75f : 1.0f); float speciesActivity = speciesBehaviour.Activity * - (signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive ? 1.25f : 1.0f); + (willAdjustBehaviourValues ? 1.25f : 1.0f); // Adjust activity for night if it is currently night // TODO: also check if the current species relies on varying compounds (otherwise it shouldn't react to it @@ -418,8 +420,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor // was smelled from if (signaling.ReceivedCommandFromEntity.IsAliveAndHas()) { - if (position.Position.DistanceSquaredTo(signalerPosition) < - Constants.AI_MOVE_DISTANCE_SQUARED) + if (squaredDistanceToSignaler < Constants.AI_MOVE_DISTANCE_SQUARED) { ai.MoveToLocation(signalerPosition, ref control, entity); } @@ -434,10 +435,8 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor { if (signaling.ReceivedCommandFromEntity.IsAliveAndHas()) { - if (position.Position.DistanceSquaredTo(signalerPosition) > - Constants.AI_FOLLOW_DISTANCE_SQUARED && - position.Position.DistanceSquaredTo(signalerPosition) < - Constants.AI_MOVE_DISTANCE_SQUARED) + if (squaredDistanceToSignaler > Constants.AI_FOLLOW_DISTANCE_SQUARED && + squaredDistanceToSignaler < Constants.AI_MOVE_DISTANCE_SQUARED) { ai.MoveToLocation(signalerPosition, ref control, entity); } @@ -452,8 +451,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor { if (signaling.ReceivedCommandFromEntity.IsAliveAndHas()) { - if (position.Position.DistanceSquaredTo(signalerPosition) < - Constants.AI_FLEE_DISTANCE_SQUARED) + if (squaredDistanceToSignaler < Constants.AI_FLEE_DISTANCE_SQUARED) { control.SetStateColonyAware(entity, MicrobeState.Normal); control.SetMoveSpeed(Constants.AI_BASE_MOVEMENT); From 0301823c1f2fb1676cb22eac5a9d70aa0c7909a0 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Wed, 25 Feb 2026 10:52:17 +0400 Subject: [PATCH 32/35] Resolve JetBrains check fail and fulfill new Patryk26g requests --- src/microbe_stage/systems/MicrobeAISystem.cs | 30 +++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 7cca1643386..fb690104ad0 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -266,31 +266,27 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor bool signalExists = signaling.ReceivedCommand != MicrobeSignalCommand.None && entity.IsAliveAndHas(); Vector3 signalerPosition = default; - float squaredDistanceToSignaler = default; + float signalerDistanceSquared = default; if (signalExists) { signalerPosition = signaling.ReceivedCommandFromEntity.Get().Position; - squaredDistanceToSignaler = position.Position.DistanceSquaredTo(signalerPosition); - } - else - { - signalExists = false; + signalerDistanceSquared = position.Position.DistanceSquaredTo(signalerPosition); } // Adjusted behaviour values (calculated here as these are needed by various methods) var speciesBehaviour = ourSpecies.Species.Behaviour; - var willAdjustBehaviourValues = signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive && - squaredDistanceToSignaler < Constants.AI_BECOME_AGGRESSIVE_DISTANCE_SQUARED; + var adjustBehaviourValues = signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive && + signalerDistanceSquared < Constants.AI_BECOME_AGGRESSIVE_DISTANCE_SQUARED; float speciesAggression = speciesBehaviour.Aggression * - (willAdjustBehaviourValues ? 1.5f : 1.0f); + (adjustBehaviourValues ? 1.5f : 1.0f); float speciesFear = speciesBehaviour.Fear * - (willAdjustBehaviourValues ? 0.75f : 1.0f); + (adjustBehaviourValues ? 0.75f : 1.0f); float speciesActivity = speciesBehaviour.Activity * - (willAdjustBehaviourValues ? 1.25f : 1.0f); + (adjustBehaviourValues ? 1.25f : 1.0f); // Adjust activity for night if it is currently night // TODO: also check if the current species relies on varying compounds (otherwise it shouldn't react to it @@ -420,7 +416,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor // was smelled from if (signaling.ReceivedCommandFromEntity.IsAliveAndHas()) { - if (squaredDistanceToSignaler < Constants.AI_MOVE_DISTANCE_SQUARED) + if (signalerDistanceSquared < Constants.AI_MOVE_DISTANCE_SQUARED) { ai.MoveToLocation(signalerPosition, ref control, entity); } @@ -435,8 +431,8 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor { if (signaling.ReceivedCommandFromEntity.IsAliveAndHas()) { - if (squaredDistanceToSignaler > Constants.AI_FOLLOW_DISTANCE_SQUARED && - squaredDistanceToSignaler < Constants.AI_MOVE_DISTANCE_SQUARED) + if (signalerDistanceSquared > Constants.AI_FOLLOW_DISTANCE_SQUARED && + signalerDistanceSquared < Constants.AI_MOVE_DISTANCE_SQUARED) { ai.MoveToLocation(signalerPosition, ref control, entity); } @@ -451,7 +447,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor { if (signaling.ReceivedCommandFromEntity.IsAliveAndHas()) { - if (squaredDistanceToSignaler < Constants.AI_FLEE_DISTANCE_SQUARED) + if (signalerDistanceSquared < Constants.AI_FLEE_DISTANCE_SQUARED) { control.SetStateColonyAware(entity, MicrobeState.Normal); control.SetMoveSpeed(Constants.AI_BASE_MOVEMENT); @@ -558,14 +554,14 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor private void UseSignalingAgent(ref OrganelleContainer organelles, float speciesAggression, ref CommandSignaler signaling, Random random) { - var willBeAggressiveThisTime = RollCheck(speciesAggression, Constants.MAX_SPECIES_AGGRESSION, random); + var shouldBeAggressive = RollCheck(speciesAggression, Constants.MAX_SPECIES_AGGRESSION, random); if (organelles.HasBindingAgent) { signaling.QueuedSignalingCommand = MicrobeSignalCommand.MoveToMe; } - if (willBeAggressiveThisTime) + if (shouldBeAggressive) { foreach (var organelle in organelles.Organelles!) { From e1d3cc17a1a011bc865f3a48629dedb6a8cee803 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Thu, 26 Feb 2026 17:48:40 +0400 Subject: [PATCH 33/35] Change comment as suggested by hhyyrylainen --- src/microbe_stage/systems/MicrobeAISystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index fb690104ad0..18672a818ce 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -397,7 +397,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor ai.ATPThreshold = 0.0f; } - // Use signaling agent if I have any with a small chance per think + // Use signaling agent if I have any with a small chance per think method call if (organelles.HasSignalingAgent && random.NextSingle() < Constants.AI_SIGNALING_CHANCE) { UseSignalingAgent(ref organelles, speciesAggression, ref signaling, random); From 9179fa46ea6ae2d6bf7195eeb29a59a6c6c16d78 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Mon, 9 Mar 2026 19:07:45 +0400 Subject: [PATCH 34/35] Add condition for sending become aggressive command --- src/microbe_stage/systems/MicrobeAISystem.cs | 25 +++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 18672a818ce..ad85caac97c 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -400,7 +400,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor // Use signaling agent if I have any with a small chance per think method call if (organelles.HasSignalingAgent && random.NextSingle() < Constants.AI_SIGNALING_CHANCE) { - UseSignalingAgent(ref organelles, speciesAggression, ref signaling, random); + UseSignalingAgent(ref position, ref organelles, speciesAggression, ref signaling, random, ref ourSpecies); } // Follow received commands if we have them @@ -551,10 +551,11 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor } } - private void UseSignalingAgent(ref OrganelleContainer organelles, float speciesAggression, - ref CommandSignaler signaling, Random random) + private void UseSignalingAgent(ref WorldPosition position, ref OrganelleContainer organelles, + float speciesAggression, ref CommandSignaler signaling, Random random, ref SpeciesMember ourSpecies) { var shouldBeAggressive = RollCheck(speciesAggression, Constants.MAX_SPECIES_AGGRESSION, random); + var speciesMembers = GetSpeciesMembers(ourSpecies.Species); if (organelles.HasBindingAgent) { @@ -568,6 +569,24 @@ private void UseSignalingAgent(ref OrganelleContainer organelles, float speciesA // Has pili or toxins if (organelle.Definition.HasPilusComponent || organelles.AgentVacuoleCount > 0) { + var membersNearEnough = 0; + var enoughMembers = (int)speciesAggression / 100; + + foreach (var member in speciesMembers!) + { + if (position.Position.DistanceSquaredTo(member.Position) + < Constants.AI_BECOME_AGGRESSIVE_DISTANCE_SQUARED) + { + ++membersNearEnough; + } + } + + if (membersNearEnough >= enoughMembers) + { + signaling.QueuedSignalingCommand = MicrobeSignalCommand.BecomeAggressive; + break; + } + signaling.QueuedSignalingCommand = MicrobeSignalCommand.FollowMe; break; } From 8d134db998e578274c20ec03746985e1297dae35 Mon Sep 17 00:00:00 2001 From: IdfbAn Date: Tue, 31 Mar 2026 19:55:01 +0400 Subject: [PATCH 35/35] Send follow me command if prey is confident enough The actual defense part should be covered by the shouldBeAggressive condition in UseSignalingAgent() --- src/microbe_stage/systems/MicrobeAISystem.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index ad85caac97c..9822b792f11 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -311,8 +311,8 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor if (control.State == MicrobeState.MucocystShield) return; - FleeFromPredators(ref position, ref ai, ref control, ref organelles, ref compoundStorage, entity, - predator.Value.Position, predator.Value.Entity, speciesFocus, + FleeFromPredators(ref position, ref ai, ref control, ref organelles, ref signaling, ref compoundStorage, + entity, predator.Value.Position, predator.Value.Entity, speciesFocus, speciesActivity, speciesAggression, speciesFear, strain, random); if (organelles.HasSignalingAgent && random.NextSingle() < Constants.AI_SIGNALING_CHANCE) @@ -594,11 +594,6 @@ private void UseSignalingAgent(ref WorldPosition position, ref OrganelleContaine signaling.QueuedSignalingCommand = MicrobeSignalCommand.None; } } - else - { - // TODO: should probably add more - signaling.QueuedSignalingCommand = MicrobeSignalCommand.None; - } signaling.QueuedSignalingCommand = MicrobeSignalCommand.None; } @@ -1003,8 +998,8 @@ private void PursueAndConsumeChunks(ref WorldPosition position, ref MicrobeAI ai } private void FleeFromPredators(ref WorldPosition position, ref MicrobeAI ai, ref MicrobeControl control, - ref OrganelleContainer organelles, ref CompoundStorage compoundStorage, in Entity entity, - Vector3 predatorLocation, Entity predatorEntity, float speciesFocus, float speciesActivity, + ref OrganelleContainer organelles, ref CommandSignaler signaling, ref CompoundStorage compoundStorage, + in Entity entity, Vector3 predatorLocation, Entity predatorEntity, float speciesFocus, float speciesActivity, float speciesAggression, float speciesFear, float strain, Random random) { var ourCompounds = compoundStorage.Compounds; @@ -1065,6 +1060,7 @@ private void FleeFromPredators(ref WorldPosition position, ref MicrobeAI ai, ref } // If prey is confident enough, it will try and launch toxin at the predator + // and send follow me command if it has signaling agent and the chance hits if (speciesAggression > speciesFear && position.Position.DistanceSquaredTo(predatorLocation) > 300.0f - (5.0f * speciesAggression) + (6.0f * speciesFear) && @@ -1072,6 +1068,11 @@ private void FleeFromPredators(ref WorldPosition position, ref MicrobeAI ai, ref { LaunchToxin(ref control, ref organelles, ref position, predatorLocation, ourCompounds, speciesFocus, speciesActivity); + + if (organelles.HasSignalingAgent && random.NextSingle() < Constants.AI_SIGNALING_CHANCE) + { + signaling.QueuedSignalingCommand = MicrobeSignalCommand.FollowMe; + } } // No matter what, I want to make sure I'm moving