Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
224cb54
AI: Use move to me command if entity has binding agent
IdfbAn Feb 11, 2026
51c70e1
AI Signaling Agent: Add else condition for no command
IdfbAn Feb 11, 2026
8d88abe
MicrobeAISystem.UseSignalingAgent()
IdfbAn Feb 11, 2026
d5ed2a0
Make UseSignalingAgent() return the command
IdfbAn Feb 12, 2026
e491f3d
Make returning no command outside of conditions
IdfbAn Feb 12, 2026
2d9a1c6
Start adding conditions for predation
IdfbAn Feb 12, 2026
a45ef6b
Comply with JetBrains check
IdfbAn Feb 12, 2026
144a74b
Make UseSignalingAgent() set commands directly again
IdfbAn Feb 13, 2026
4d8bc43
Add "or has toxins" to pili condition
IdfbAn Feb 14, 2026
e9f1932
MicrobeControl.Fleeing
IdfbAn Feb 14, 2026
8195e59
Set control.Fleeing in ChooseActions()
IdfbAn Feb 14, 2026
ecca883
Use flee from me command if fleeing
IdfbAn Feb 15, 2026
36de1a4
Remove control.Fleeing = false line
IdfbAn Feb 15, 2026
f5fc4c8
Remove exact chance from comment
IdfbAn Feb 16, 2026
07f62e2
Move Fleeing to MicrobeAI and increment SERIALIZATION_VERSION
IdfbAn Feb 16, 2026
08cbe44
Handle reading Fleeing for SERIALIZATION_VERSION == 1
IdfbAn Feb 16, 2026
c758755
Correct control.Fleeing to ai.Fleeing
IdfbAn Feb 16, 2026
0920682
Add else conditions that set command to none
IdfbAn Feb 16, 2026
74ac805
Add and use AI_MOVE_DISTANCE_SQUARED
IdfbAn Feb 17, 2026
4c1708e
Add and use AI_BECOME_AGGRESSIVE_DISTANCE_SQUARED
IdfbAn Feb 17, 2026
d471a74
Fix indentation
IdfbAn Feb 17, 2026
43032a9
Fix indentation MicrobeAISystem.cs:273
IdfbAn Feb 17, 2026
16a1d7e
Edit ternary operator to comply with JetBrains
IdfbAn Feb 17, 2026
b98eb16
Move flee from me command to outside of UseSignalingAgent()
IdfbAn Feb 18, 2026
880c09f
Remove MicrobeAI.Fleeing as it is now useless
IdfbAn Feb 18, 2026
6340dba
Remove unused parameter
IdfbAn Feb 18, 2026
ef56fc8
Fix signalerPosition
IdfbAn Feb 18, 2026
66cff35
Fix AI use of flee from me command
IdfbAn Feb 18, 2026
8ae66c4
Improve signalerPosition assignment
IdfbAn Feb 23, 2026
3426b61
Use signalExists in signalerPosition condition
IdfbAn Feb 24, 2026
01abd06
Fulfill (some of) Patryk26g's requests
IdfbAn Feb 24, 2026
0301823
Resolve JetBrains check fail and fulfill new Patryk26g requests
IdfbAn Feb 25, 2026
e1d3cc1
Change comment as suggested by hhyyrylainen
IdfbAn Feb 26, 2026
9179fa4
Add condition for sending become aggressive command
IdfbAn Mar 9, 2026
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
4 changes: 4 additions & 0 deletions simulation_parameters/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1277,8 +1277,12 @@ 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;

public const float AI_SIGNALING_CHANCE = 0.05f;

public const float AI_BASE_TOXIN_SHOOT_ANGLE_PRECISION = 5;

Expand Down
102 changes: 90 additions & 12 deletions src/microbe_stage/systems/MicrobeAISystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -263,16 +263,30 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor

var compounds = compoundStorage.Compounds;

bool signalExists = signaling.ReceivedCommand != MicrobeSignalCommand.None &&
entity.IsAliveAndHas<WorldPosition>();
Vector3 signalerPosition = default;
float signalerDistanceSquared = default;

if (signalExists)
{
signalerPosition = signaling.ReceivedCommandFromEntity.Get<WorldPosition>().Position;
signalerDistanceSquared = position.Position.DistanceSquaredTo(signalerPosition);
}

// Adjusted behaviour values (calculated here as these are needed by various methods)
var speciesBehaviour = ourSpecies.Species.Behaviour;
var adjustBehaviourValues = signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive &&
signalerDistanceSquared < Constants.AI_BECOME_AGGRESSIVE_DISTANCE_SQUARED;

float speciesAggression = speciesBehaviour.Aggression *
(signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive ? 1.5f : 1.0f);
(adjustBehaviourValues ? 1.5f : 1.0f);

float speciesFear = speciesBehaviour.Fear *
(signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive ? 0.75f : 1.0f);
(adjustBehaviourValues ? 0.75f : 1.0f);

float speciesActivity = speciesBehaviour.Activity *
(signaling.ReceivedCommand == MicrobeSignalCommand.BecomeAggressive ? 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
Expand Down Expand Up @@ -300,6 +314,12 @@ 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);

if (organelles.HasSignalingAgent && random.NextSingle() < Constants.AI_SIGNALING_CHANCE)
{
signaling.QueuedSignalingCommand = MicrobeSignalCommand.FleeFromMe;
}

return;
}

Expand Down Expand Up @@ -377,8 +397,14 @@ 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 method call
if (organelles.HasSignalingAgent && random.NextSingle() < Constants.AI_SIGNALING_CHANCE)
{
UseSignalingAgent(ref position, ref organelles, speciesAggression, ref signaling, random, ref ourSpecies);
}

// 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
Expand All @@ -390,8 +416,11 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor
// was smelled from
if (signaling.ReceivedCommandFromEntity.IsAliveAndHas<WorldPosition>())
{
ai.MoveToLocation(signaling.ReceivedCommandFromEntity.Get<WorldPosition>().Position,
ref control, entity);
if (signalerDistanceSquared < Constants.AI_MOVE_DISTANCE_SQUARED)
{
ai.MoveToLocation(signalerPosition, ref control, entity);
}

return;
}

Expand All @@ -402,9 +431,8 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor
{
if (signaling.ReceivedCommandFromEntity.IsAliveAndHas<WorldPosition>())
{
var signalerPosition = signaling.ReceivedCommandFromEntity.Get<WorldPosition>().Position;
if (position.Position.DistanceSquaredTo(signalerPosition) >
Constants.AI_FOLLOW_DISTANCE_SQUARED)
if (signalerDistanceSquared > Constants.AI_FOLLOW_DISTANCE_SQUARED &&
signalerDistanceSquared < Constants.AI_MOVE_DISTANCE_SQUARED)
{
ai.MoveToLocation(signalerPosition, ref control, entity);
}
Expand All @@ -419,9 +447,7 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor
{
if (signaling.ReceivedCommandFromEntity.IsAliveAndHas<WorldPosition>())
{
var signalerPosition = signaling.ReceivedCommandFromEntity.Get<WorldPosition>().Position;
if (position.Position.DistanceSquaredTo(signalerPosition) <
Constants.AI_FLEE_DISTANCE_SQUARED)
if (signalerDistanceSquared < Constants.AI_FLEE_DISTANCE_SQUARED)
{
control.SetStateColonyAware(entity, MicrobeState.Normal);
control.SetMoveSpeed(Constants.AI_BASE_MOVEMENT);
Expand Down Expand Up @@ -525,6 +551,58 @@ private void ChooseActions(in Entity entity, ref MicrobeAI ai, ref CompoundAbsor
}
}

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);
Copy link
Contributor

@Accidental-Explorer Accidental-Explorer Feb 26, 2026

Choose a reason for hiding this comment

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

So this, combined with the section below is just deciding whether they should be trying to travel in a group? (Because this is outside specific responses, just passive, right?)

I think this would make sense not just for aggressive predators, but also for some Brave prey.

var speciesMembers = GetSpeciesMembers(ourSpecies.Species);

if (organelles.HasBindingAgent)
{
signaling.QueuedSignalingCommand = MicrobeSignalCommand.MoveToMe;
}

if (shouldBeAggressive)
{
foreach (var organelle in organelles.Organelles!)
{
// 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;
}

signaling.QueuedSignalingCommand = MicrobeSignalCommand.None;
}
}
else
Copy link
Contributor

Choose a reason for hiding this comment

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

this else is unnecesary

Copy link
Member Author

Choose a reason for hiding this comment

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

I guess it is right now, but since I want to add more sub-conditions I'll keep it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Are you going to do this in this PR? If not, then you should remove it. YAGNI

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I'm gonna do it in this PR.

Copy link
Member

Choose a reason for hiding this comment

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

So there was unimplemented stuff? Good thing that I didn't spend any more review energy yet...

{
// TODO: should probably add more
signaling.QueuedSignalingCommand = MicrobeSignalCommand.None;
}

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,
Expand Down