diff --git a/simulation_parameters/Constants.cs b/simulation_parameters/Constants.cs index 2aa4dee87cb..18af10411f3 100644 --- a/simulation_parameters/Constants.cs +++ b/simulation_parameters/Constants.cs @@ -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; diff --git a/src/microbe_stage/systems/MicrobeAISystem.cs b/src/microbe_stage/systems/MicrobeAISystem.cs index 64e10a6a80d..ad85caac97c 100644 --- a/src/microbe_stage/systems/MicrobeAISystem.cs +++ b/src/microbe_stage/systems/MicrobeAISystem.cs @@ -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(); + Vector3 signalerPosition = default; + float signalerDistanceSquared = default; + + if (signalExists) + { + signalerPosition = signaling.ReceivedCommandFromEntity.Get().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 @@ -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; } @@ -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 @@ -390,8 +416,11 @@ 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); + if (signalerDistanceSquared < Constants.AI_MOVE_DISTANCE_SQUARED) + { + ai.MoveToLocation(signalerPosition, ref control, entity); + } + return; } @@ -402,9 +431,8 @@ 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) + if (signalerDistanceSquared > Constants.AI_FOLLOW_DISTANCE_SQUARED && + signalerDistanceSquared < Constants.AI_MOVE_DISTANCE_SQUARED) { ai.MoveToLocation(signalerPosition, ref control, entity); } @@ -419,9 +447,7 @@ 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) + if (signalerDistanceSquared < Constants.AI_FLEE_DISTANCE_SQUARED) { control.SetStateColonyAware(entity, MicrobeState.Normal); control.SetMoveSpeed(Constants.AI_BASE_MOVEMENT); @@ -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); + 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 + { + // 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,