From f38917b396ad5dc1a8430b05167e9f55e457e01a Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Sat, 5 Jan 2019 15:59:19 -0600 Subject: [PATCH] Improve AI for 0.4.1 (#705) * made slight changes to aggression calculations., Ill definetly have to do more then this to make things properly challenging and sensible , especially once pilus are in. * Cleane dup AI code to match teh rest of the code, and started working on improving the AI * Cleaned up AI more, and they seem to be more aggressive now, i want to change it so they peg a prey item instead of always targeting nearest now, that should make it even better. * Added a comment detailing my plan for the next change. * prey now gets pegged properly (lots of null pointer errors though, will fix soon) * am trying to fix null pointer error with no success, AI works really well at predating now. * fixed null pointer error finally. Now to work on improving fleeing. * AI now flees properly when they notice predators nearby, no matter what they may have been in the middle of doing. Its not balanced though, i need to work on it more. * Simplified AI code even more., it now calls a method when doing checks instead of directly doing the same expression each time. Yay for modularization. * cleaned up fleeing code immensely, also fine tuned fleeing behavior (they also flee when being engulfed, no matter what) * Improved fleeing even more, also fleeing is less chaotic. * Prey now flees when they spot a predator at double the distance of previously, made it easier for them to fail their check (so they run), and made things flee at the same speed they used to flee. * Fixed bug that made creatures being engulfed, totally unable to move (it would continuously apply a movement factor that divide dit without resetting), improved fleeing behavior more. * Predators now get bored again. * ran code formatter again, and tweaked AI more. * removed pointless greyscale filter i added to disabled buttons ages ago, which did absolutely nothing except break my tooltips (yes everything still looks disabled fine) * removed now unused disabled button class so the formatter stops complaining. --- scripts/gui/thrive_gui.html | 6 + scripts/gui/thrive_style.css | 9 +- scripts/microbe_stage/configs.as | 8 +- scripts/microbe_stage/microbe.as | 7 +- scripts/microbe_stage/microbe_ai.as | 336 +++++++++----------- scripts/microbe_stage/microbe_operations.as | 12 +- scripts/microbe_stage/setup.as | 2 - 7 files changed, 167 insertions(+), 213 deletions(-) diff --git a/scripts/gui/thrive_gui.html b/scripts/gui/thrive_gui.html index e5031aab789..9750af9a1b7 100644 --- a/scripts/gui/thrive_gui.html +++ b/scripts/gui/thrive_gui.html @@ -369,6 +369,12 @@
Chloroplast
40 MP + + Chloroplast

Cost: 40 mutation points

+ Performs Process: Photosynthesis
(1 glucose)/Second

+ A captured prokaryote used by eukaryotic cells to perform photosynthesis.
+ The chloroplast is used primarily by plant cells on earth, but some ciliates and other organisms use it too. +
Thermoplast
40 MP diff --git a/scripts/gui/thrive_style.css b/scripts/gui/thrive_style.css index 23b506fdb4c..90fcf86b350 100644 --- a/scripts/gui/thrive_style.css +++ b/scripts/gui/thrive_style.css @@ -235,14 +235,6 @@ video { flex-direction: column; } -.DisabledButton { - filter: grayscale(100%); -} - -.DisabledButton:hover { - filter: grayscale(100%); -} - .MenuButton.DisabledButton { background-image: url("../../Textures/gui/bevel/MenuDisabled.png"); } @@ -1090,6 +1082,7 @@ video { visibility: visible; } + #PlastidIcon { position: relative; left: calc(50% - 30px); diff --git a/scripts/microbe_stage/configs.as b/scripts/microbe_stage/configs.as index e1a7f742b0e..a7ab339d2e5 100644 --- a/scripts/microbe_stage/configs.as +++ b/scripts/microbe_stage/configs.as @@ -64,8 +64,8 @@ const auto MIN_BACTERIAL_LINE_SIZE = 3; const auto MAX_BACTERIAL_LINE_SIZE = 6; // What is divided during fear and aggression calculations in the AI -const auto AGRESSION_DIVISOR = 100.0f; -const auto FEAR_DIVISOR = 100.0f; +const auto AGRESSION_DIVISOR = 25.0f; +const auto FEAR_DIVISOR = 25.0f; const auto ACTIVITY_DIVISOR = 100.0f; const auto FOCUS_DIVISOR = 100.0f; @@ -140,10 +140,10 @@ const float RELATIVE_VELOCITY_TO_BUMP_SOUND = 6.0; const float INITIAL_EMISSION_RADIUS = 0.5; // The speed reduction when a cell is in rngulfing mode. -const uint ENGULFING_MOVEMENT_DIVISION = 3; +const double ENGULFING_MOVEMENT_DIVISION = 2.0f; // The speed reduction when a cell is being engulfed. -const uint ENGULFED_MOVEMENT_DIVISION = 6; +const double ENGULFED_MOVEMENT_DIVISION = 1.7f; // The amount of ATP per second spent on being on engulfing mode. const float ENGULFING_ATP_COST_SECOND = 1.5; diff --git a/scripts/microbe_stage/microbe.as b/scripts/microbe_stage/microbe.as index 7ecd910078d..41644fac989 100644 --- a/scripts/microbe_stage/microbe.as +++ b/scripts/microbe_stage/microbe.as @@ -292,12 +292,12 @@ class MicrobeSystem : ScriptSystem{ private void updateAliveCell(MicrobeSystemCached@ &in components, uint logicTime) { auto microbeEntity = components.entity; - MembraneComponent@ membraneComponent = components.fifth; RenderNode@ sceneNodeComponent = components.third; CompoundAbsorberComponent@ compoundAbsorberComponent = components.first; CompoundBagComponent@ compoundBag = components.sixth; MicrobeComponent@ microbeComponent = components.second; + microbeComponent.movementFactor = 1.0f; //LOG_INFO(""+logicTime); // Recalculating agent cooldown time. @@ -439,7 +439,12 @@ class MicrobeSystem : ScriptSystem{ Float4(0.2,0.5,1.0,0.5)); } + if(microbeComponent.engulfMode){ + microbeComponent.movementFactor = microbeComponent.movementFactor/ENGULFING_MOVEMENT_DIVISION; + } + if(microbeComponent.isBeingEngulfed){ + microbeComponent.movementFactor = microbeComponent.movementFactor/ENGULFED_MOVEMENT_DIVISION; //LOG_INFO("doing engulf damage"); MicrobeOperations::damage(world,microbeEntity,ENGULF_DAMAGE/logicTime, "isBeingEngulfed - Microbe.update()s"); diff --git a/scripts/microbe_stage/microbe_ai.as b/scripts/microbe_stage/microbe_ai.as index 143edf8cbba..471ef9cadf5 100644 --- a/scripts/microbe_stage/microbe_ai.as +++ b/scripts/microbe_stage/microbe_ai.as @@ -29,8 +29,8 @@ class MicrobeAIControllerComponent : ScriptComponent{ } float movementRadius = 2000; - // That means they evaluate every 10 seconds or so, correct? - int reevalutationInterval = 1000; + // That means they evaluate every 5 seconds or so, correct? + int reevalutationInterval = 500; int intervalRemaining; int boredom = 0; int ticksSinceLastToggle = 600; @@ -47,6 +47,7 @@ class MicrobeAIControllerComponent : ScriptComponent{ float previousAngle = 0.0f; float compoundDifference=0; ObjectID prey = NULL_OBJECT; + bool preyPegged=false; // Prey and predator lists array predatoryMicrobes; array preyMicrobes; @@ -115,22 +116,17 @@ class MicrobeAISystem : ScriptSystem{ aiComponent.intervalRemaining += logicTime; // Cache fear and aggression as we dont wnat to be calling "getSpecies" every frame for every microbe (maybe its not a big deal) SpeciesComponent@ ourSpecies = MicrobeOperations::getSpeciesComponent(world, microbeEntity); - if (ourSpecies !is null) - { - if (aiComponent.speciesAggression == -1.0f) - { + if (ourSpecies !is null){ + if (aiComponent.speciesAggression == -1.0f){ aiComponent.speciesAggression = ourSpecies.aggression; } - if (aiComponent.speciesFear == -1.0f) - { + if (aiComponent.speciesFear == -1.0f){ aiComponent.speciesFear = ourSpecies.fear; } - if (aiComponent.speciesActivity == -1.0f) - { + if (aiComponent.speciesActivity == -1.0f){ aiComponent.speciesActivity =ourSpecies.activity; } - if (aiComponent.speciesFocus == -1.0f) - { + if (aiComponent.speciesFocus == -1.0f){ aiComponent.speciesFocus = ourSpecies.focus; } } @@ -140,7 +136,7 @@ class MicrobeAISystem : ScriptSystem{ LOG_INFO("AI Focus"+aiComponent.speciesFocus); LOG_INFO("AI Activity"+aiComponent.speciesActivity);*/ - while(aiComponent.intervalRemaining > aiComponent.reevalutationInterval) { + while(aiComponent.intervalRemaining > aiComponent.reevalutationInterval){ aiComponent.intervalRemaining -= aiComponent.reevalutationInterval; int numberOfAgentVacuoles = int( microbeComponent.specialStorageOrganelles[formatUInt(oxytoxyId)]); @@ -148,22 +144,27 @@ class MicrobeAISystem : ScriptSystem{ // Clear the lists aiComponent.predatoryMicrobes.removeRange(0,aiComponent.predatoryMicrobes.length()); aiComponent.preyMicrobes.removeRange(0,aiComponent.preyMicrobes.length()); - - // Update most feared microbe and most tasty microbe - ObjectID prey = getNearestPreyItem(components,allMicrobes); + ObjectID prey = NULL_OBJECT; + // Peg your prey + if (!aiComponent.preyPegged){ + aiComponent.prey=NULL_OBJECT; + prey = getNearestPreyItem(components,allMicrobes); + aiComponent.prey = prey; + if (prey != NULL_OBJECT){ + aiComponent.preyPegged=true; + } + } ObjectID predator = getNearestPredatorItem(components,allMicrobes); //30 seconds about - if (aiComponent.boredom == GetEngine().GetRandom().GetNumber(aiComponent.speciesFocus,1000.0f+aiComponent.speciesFocus)){ + if (aiComponent.boredom == GetEngine().GetRandom().GetNumber(aiComponent.speciesFocus*2,1000.0f+aiComponent.speciesFocus*2)){ // Occassionally you need to reevaluate things aiComponent.boredom = 0; - if (GetEngine().GetRandom().GetNumber(0.0f,400.0f) <= aiComponent.speciesActivity) - { + if (rollCheck(aiComponent.speciesActivity, 400)){ //LOG_INFO("gather only"); aiComponent.lifeState = PLANTLIKE_STATE; } - else - { + else{ aiComponent.lifeState = NEUTRAL_STATE; } } @@ -182,7 +183,9 @@ class MicrobeAISystem : ScriptSystem{ { //In this state you just sit there and analyze your environment aiComponent.boredom=0; - evaluateEnvironment(components,prey,predator); + aiComponent.preyPegged=false; + prey = NULL_OBJECT; + evaluateEnvironment(components,aiComponent.prey,predator); break; } case GATHERING_STATE: @@ -193,20 +196,18 @@ class MicrobeAISystem : ScriptSystem{ } case FLEEING_STATE: { - //In this state you run from preadtory microbes - if (predator != NULL_OBJECT) - { + //In this state you run from predatory microbes + if (predator != NULL_OBJECT){ + //aiComponent.hasTargetPosition = false; dealWithPredators(components,predator); } else{ - if (GetEngine().GetRandom().GetNumber(0.0f,400.0f) <= aiComponent.speciesActivity) - { + if (rollCheck(aiComponent.speciesActivity, 400)){ //LOG_INFO("gather only"); aiComponent.lifeState = PLANTLIKE_STATE; aiComponent.boredom=0; } - else - { + else{ aiComponent.lifeState = NEUTRAL_STATE; } } @@ -214,26 +215,45 @@ class MicrobeAISystem : ScriptSystem{ } case PREDATING_STATE: { - if (prey != NULL_OBJECT) - { - dealWithPrey(components,prey); + if (aiComponent.preyPegged && aiComponent.prey != NULL_OBJECT){ + dealWithPrey(components, aiComponent.prey, allMicrobes); } else{ - if (GetEngine().GetRandom().GetNumber(0.0f,400.0f) <= aiComponent.speciesActivity) - { + if (rollCheck(aiComponent.speciesActivity, 400)){ //LOG_INFO("gather only"); aiComponent.lifeState = NEUTRAL_STATE; aiComponent.boredom=0; } - else - { + else{ aiComponent.lifeState = NEUTRAL_STATE; } } break; } } + + /* Check if we are willing to run, and there is a predator nearby, if so, flee for your life + If it was ran in evaluate environment, it would only work if the microbe was in the neutral state. + So think of this as a "reflex" maybe it should go in its own "doReflex" method, + because we may need more of these very specific things in the future for things like latching onto rocks */ + // If you are predating and not being engulfed, don't run away until you switch state (keeps predators chasing you even when their predators are nearby) + // Its not a good survival strategy but it makes the game more fun. + if (predator != NULL_OBJECT && (aiComponent.lifeState != PREDATING_STATE || microbeComponent.isBeingEngulfed)){ + Float3 testPosition = world.GetComponent_Position(predator)._Position; + MicrobeComponent@ secondMicrobeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(predator)); + if ((position._Position - testPosition).LengthSquared() <= (2000+(secondMicrobeComponent.organelles.length()*8.0f)*2)){ + if (aiComponent.lifeState != FLEEING_STATE) + { + // Reset target position for faster fleeing + aiComponent.hasTargetPosition = false; + } + aiComponent.boredom=0; + aiComponent.lifeState = FLEEING_STATE; + } + } } + //cache stored compounds for use in the next frame (For Run and tumble) aiComponent.compoundDifference = microbeComponent.stored-aiComponent.previousStoredCompounds; aiComponent.previousStoredCompounds = microbeComponent.stored; @@ -250,28 +270,21 @@ class MicrobeAISystem : ScriptSystem{ ObjectID chosenPrey = NULL_OBJECT; CompoundId oxytoxyId = SimulationParameters::compoundRegistry().getTypeId("oxytoxy"); + // Grab the agent amounts so a small cell with a lot of toxins has the courage to attack. int numberOfAgentVacuoles = int( microbeComponent.specialStorageOrganelles[formatUInt(oxytoxyId)]); // Retrieve nearest potential prey - for (uint i = 0; i < allMicrobes.length(); i++) - { + for (uint i = 0; i < allMicrobes.length(); i++){ // Get the microbe component MicrobeComponent@ secondMicrobeComponent = cast( world.GetScriptComponentHolder("MicrobeComponent").Find(allMicrobes[i])); // At max aggression add them all - if (allMicrobes[i] != microbeEntity && (secondMicrobeComponent.speciesName != microbeComponent.speciesName) && !secondMicrobeComponent.dead) - { - // TODO: - // I think we should call this and factor it into predator calculations .specialStorageOrganelles[formatUInt(oxytoxyId)]) - // that way a small cell with alot of toxins still has the courage to attack. - // But that may be rather arcane to read through code wise. SO im not sure. - + if (allMicrobes[i] != microbeEntity && (secondMicrobeComponent.speciesName != microbeComponent.speciesName) && !secondMicrobeComponent.dead){ if ((aiComponent.speciesAggression==MAX_SPECIES_AGRESSION) or ((((numberOfAgentVacuoles+microbeComponent.organelles.length())*1.0f)*(aiComponent.speciesAggression/AGRESSION_DIVISOR)) > - (secondMicrobeComponent.organelles.length()*1.0f))) - { + (secondMicrobeComponent.organelles.length()*1.0f))){ //You are non-threatening to me aiComponent.preyMicrobes.insertLast(allMicrobes[i]); } @@ -283,15 +296,13 @@ class MicrobeAISystem : ScriptSystem{ { Float3 testPosition = world.GetComponent_Position(aiComponent.preyMicrobes[0])._Position; chosenPrey = aiComponent.preyMicrobes[0]; - for (uint c = 0; c < aiComponent.preyMicrobes.length(); c++) - { + for (uint c = 0; c < aiComponent.preyMicrobes.length(); c++){ // Get the microbe component MicrobeComponent@ secondMicrobeComponent = cast( world.GetScriptComponentHolder("MicrobeComponent").Find(aiComponent.preyMicrobes[c])); Position@ thisPosition = world.GetComponent_Position(aiComponent.preyMicrobes[c]); - if ((testPosition - position._Position).LengthSquared() > (thisPosition._Position - position._Position).LengthSquared()) - { + if ((testPosition - position._Position).LengthSquared() > (thisPosition._Position - position._Position).LengthSquared()){ testPosition = thisPosition._Position; chosenPrey = aiComponent.preyMicrobes[c]; } @@ -320,16 +331,15 @@ class MicrobeAISystem : ScriptSystem{ // Get the microbe component MicrobeComponent@ secondMicrobeComponent = cast( world.GetScriptComponentHolder("MicrobeComponent").Find(allMicrobes[i])); - // Is this an expensive lookup?, ill come up with a more effieient means of doing this. + // Is this an expensive lookup?, ill come up with a more efficient means of doing this. CompoundId oxytoxyId = SimulationParameters::compoundRegistry().getTypeId("oxytoxy"); int numberOfAgentVacuoles = int( secondMicrobeComponent.specialStorageOrganelles[formatUInt(oxytoxyId)]); // At max fear add them all - if (allMicrobes[i] != microbeEntity && (secondMicrobeComponent.speciesName != microbeComponent.speciesName) && !secondMicrobeComponent.dead) - { - if ((aiComponent.speciesFear==MAX_SPECIES_FEAR) or ((((numberOfAgentVacuoles+secondMicrobeComponent.organelles.length())*1.0f)*(aiComponent.speciesFear/FEAR_DIVISOR)) > - (microbeComponent.organelles.length()*1.0f))) - { + if (allMicrobes[i] != microbeEntity && (secondMicrobeComponent.speciesName != microbeComponent.speciesName) && !secondMicrobeComponent.dead){ + if ((aiComponent.speciesFear==MAX_SPECIES_FEAR) or + ((((numberOfAgentVacuoles+secondMicrobeComponent.organelles.length())*1.0f)*(aiComponent.speciesFear/FEAR_DIVISOR)) > + (microbeComponent.organelles.length()*1.0f))){ //You are bigger then me and i am afraid of that aiComponent.predatoryMicrobes.insertLast(allMicrobes[i]); //LOG_INFO("Added predator " + allMicrobes[i] ); @@ -338,20 +348,17 @@ class MicrobeAISystem : ScriptSystem{ } // Get the nearest one if it exists - if (aiComponent.predatoryMicrobes.length() > 0 ) - { + if (aiComponent.predatoryMicrobes.length() > 0){ Float3 testPosition = world.GetComponent_Position(aiComponent.predatoryMicrobes[0])._Position; predator = aiComponent.predatoryMicrobes[0]; - for (uint c = 0; c < aiComponent.predatoryMicrobes.length(); c++) - { + for (uint c = 0; c < aiComponent.predatoryMicrobes.length(); c++){ // Get the microbe component MicrobeComponent@ secondMicrobeComponent = cast( world.GetScriptComponentHolder("MicrobeComponent").Find(aiComponent.predatoryMicrobes[c])); Position@ thisPosition = world.GetComponent_Position(aiComponent.predatoryMicrobes[c]); - if ((testPosition - position._Position).LengthSquared() > (thisPosition._Position - position._Position).LengthSquared()) - { + if ((testPosition - position._Position).LengthSquared() > (thisPosition._Position - position._Position).LengthSquared()){ testPosition = thisPosition._Position; predator = aiComponent.predatoryMicrobes[c]; } @@ -361,7 +368,7 @@ class MicrobeAISystem : ScriptSystem{ } // For chasing down and killing prey in various ways - void dealWithPrey(MicrobeAISystemCached@ components, ObjectID prey) + void dealWithPrey(MicrobeAISystemCached@ components, ObjectID prey, array@ allMicrobes ) { //LOG_INFO("chasing"+prey); // Set Components @@ -374,9 +381,14 @@ class MicrobeAISystem : ScriptSystem{ // Required For AI CompoundId oxytoxyId = SimulationParameters::compoundRegistry().getTypeId("oxytoxy"); CompoundId atpID = SimulationParameters::compoundRegistry().getTypeId("atp"); - + //LOG_INFO("predating"); MicrobeComponent@ secondMicrobeComponent = cast( world.GetScriptComponentHolder("MicrobeComponent").Find(prey)); + if (secondMicrobeComponent is null){ + aiComponent.preyPegged=false; + aiComponent.prey = NULL_OBJECT; + return; + } // Agent vacuoles. int numberOfAgentVacuoles = int( microbeComponent.specialStorageOrganelles[formatUInt(oxytoxyId)]); @@ -391,12 +403,10 @@ class MicrobeAISystem : ScriptSystem{ aiComponent.hasTargetPosition = true; //Always set target Position, for use later in AI - if (aiComponent.speciesAggression+GetEngine().GetRandom().GetNumber(-100.0f,100.0f) > aiComponent.speciesActivity) - { + if (aiComponent.speciesAggression+GetEngine().GetRandom().GetNumber(-100.0f,100.0f) > aiComponent.speciesActivity){ microbeComponent.movementDirection = Float3(0, 0, -AI_BASE_MOVEMENT); } - else - { + else{ microbeComponent.movementDirection = Float3(0, 0, 0); } @@ -404,31 +414,33 @@ class MicrobeAISystem : ScriptSystem{ // This is probabbly not working if (secondMicrobeComponent.dead == true){ aiComponent.hasTargetPosition = false; - aiComponent.lifeState = GATHERING_STATE; - if (microbeComponent.engulfMode) - { + aiComponent.prey=getNearestPreyItem(components, allMicrobes); + if (aiComponent.prey != NULL_OBJECT ) { + aiComponent.preyPegged=true; + } + + if (microbeComponent.engulfMode){ MicrobeOperations::toggleEngulfMode(world, microbeEntity); - } + } // You got a kill, good job auto playerSpecies = MicrobeOperations::getSpeciesComponent(world, "Default"); - if (!microbeComponent.isPlayerMicrobe && microbeComponent.speciesName != playerSpecies.name) - { + if (!microbeComponent.isPlayerMicrobe && microbeComponent.speciesName != playerSpecies.name){ MicrobeOperations::alterSpeciesPopulation(world,microbeEntity,CREATURE_KILL_POPULATION_GAIN); } } else { // Turn on engulfmode if close - if (((position._Position - aiComponent.targetPosition).LengthSquared() <= 300+(microbeComponent.organelles.length()*3.0f)) && (MicrobeOperations::getCompoundAmount(world,microbeEntity,atpID) >= 1.0f) + if (((position._Position - aiComponent.targetPosition).LengthSquared() <= 300+(microbeComponent.organelles.length()*3.0f)) + && (MicrobeOperations::getCompoundAmount(world,microbeEntity,atpID) >= 1.0f) && !microbeComponent.engulfMode && (float(microbeComponent.organelles.length()) > ( - ENGULF_HP_RATIO_REQ*secondMicrobeComponent.organelles.length()))) - { + ENGULF_HP_RATIO_REQ*secondMicrobeComponent.organelles.length()))){ MicrobeOperations::toggleEngulfMode(world, microbeEntity); aiComponent.ticksSinceLastToggle=0; } - else if ((position._Position - aiComponent.targetPosition).LengthSquared() >= 500+(microbeComponent.organelles.length()*3.0f) && microbeComponent.engulfMode && aiComponent.ticksSinceLastToggle >= AI_ENGULF_INTERVAL) - { + else if (((position._Position - aiComponent.targetPosition).LengthSquared() >= 500+(microbeComponent.organelles.length()*3.0f)) + && (microbeComponent.engulfMode && aiComponent.ticksSinceLastToggle >= AI_ENGULF_INTERVAL)){ MicrobeOperations::toggleEngulfMode(world, microbeEntity); aiComponent.ticksSinceLastToggle=0; } @@ -441,20 +453,17 @@ class MicrobeAISystem : ScriptSystem{ // For now creatures with a focus under 100 will never shoot. //LOG_INFO("Our focus is: "+ aiComponent.speciesFocus); - if (aiComponent.speciesFocus >= 100.0f) - { + if (aiComponent.speciesFocus >= 100.0f){ if (microbeComponent.hitpoints > 0 && numberOfAgentVacuoles > 0 && - (position._Position - aiComponent.targetPosition).LengthSquared() <= aiComponent.speciesFocus*10.0f) - { - if (MicrobeOperations::getCompoundAmount(world,microbeEntity,oxytoxyId) >= MINIMUM_AGENT_EMISSION_AMOUNT) - { + (position._Position - aiComponent.targetPosition).LengthSquared() <= aiComponent.speciesFocus*10.0f){ + if (MicrobeOperations::getCompoundAmount(world,microbeEntity,oxytoxyId) >= MINIMUM_AGENT_EMISSION_AMOUNT){ MicrobeOperations::emitAgent(world,microbeEntity, oxytoxyId,10.0f,aiComponent.speciesFocus*10.0f); } } - } + } } - // For self defense (not nessessarily fleeing) + // For self defense (not necessarily fleeing) void dealWithPredators(MicrobeAISystemCached@ components, ObjectID predator) { ObjectID microbeEntity = components.entity; @@ -462,14 +471,12 @@ class MicrobeAISystem : ScriptSystem{ MicrobeComponent@ microbeComponent = components.second; Position@ position = components.third; - if (GetEngine().GetRandom().GetNumber(0,100) <= 10) - { + if (GetEngine().GetRandom().GetNumber(0,50) <= 10){ aiComponent.hasTargetPosition = false; } // Run From Predator - if (aiComponent.hasTargetPosition == false) - { + if (aiComponent.hasTargetPosition == false){ preyFlee(microbeEntity, aiComponent, microbeComponent, position, predator); } } @@ -484,87 +491,46 @@ class MicrobeAISystem : ScriptSystem{ int numberOfAgentVacuoles = int( microbeComponent.specialStorageOrganelles[formatUInt(oxytoxyId)]); - if (GetEngine().GetRandom().GetNumber(0,100) <= 40) - { + // If focused you can run away more specifically, if not you freak out and scatter + if (!rollCheck(aiComponent.speciesFocus,500.0f)){ // Scatter auto randAngle = GetEngine().GetRandom().GetFloat(-2*PI, 2*PI); auto randDist = GetEngine().GetRandom().GetFloat(200,aiComponent.movementRadius*10); aiComponent.targetPosition = Float3(cos(randAngle) * randDist,0, sin(randAngle)* randDist); - auto vec = (aiComponent.targetPosition - position._Position); - aiComponent.direction = vec.Normalize(); - microbeComponent.facingTargetPoint = aiComponent.targetPosition; - microbeComponent.movementDirection = Float3(0, 0, -AI_BASE_MOVEMENT); - aiComponent.hasTargetPosition = true; } else { // Run specifically away - int choice = GetEngine().GetRandom().GetNumber(0,3); - switch (choice) - { - case 0: - if (world.GetComponent_Position(predator)._Position.X >= position._Position.X) - { - aiComponent.targetPosition = - Float3(GetEngine().GetRandom().GetFloat(-10.0f,-100.0f),1.0,1.0)* - world.GetComponent_Position(predator)._Position; - } - else { - aiComponent.targetPosition = - Float3(GetEngine().GetRandom().GetFloat(20.0f,100.0f),1.0,1.0)* - world.GetComponent_Position(predator)._Position; - } - break; - case 1: - if (world.GetComponent_Position(predator)._Position.Z >= position._Position.Z) - { - aiComponent.targetPosition = - Float3(1.0,1.0,GetEngine().GetRandom().GetFloat(-10.0f,-100.0f))* + aiComponent.targetPosition = Float3(GetEngine().GetRandom().GetFloat(-5000.0f,5000.0f),1.0, + GetEngine().GetRandom().GetFloat(-5000.0f,5000.0f))* world.GetComponent_Position(predator)._Position; - } - else { - aiComponent.targetPosition = - Float3(1.0,1.0,GetEngine().GetRandom().GetFloat(20.0f,100.0f))* - world.GetComponent_Position(predator)._Position; - } - break; - case 2: - case 3: - aiComponent.targetPosition = - Float3(GetEngine().GetRandom().GetFloat(-100.0f,100.0f),1.0, - GetEngine().GetRandom().GetFloat(-100.0f,100.0f))* - world.GetComponent_Position(predator)._Position; - break; } - auto vec = (aiComponent.targetPosition - position._Position); + auto vec = (position._Position-aiComponent.targetPosition); aiComponent.direction = vec.Normalize(); - microbeComponent.facingTargetPoint = aiComponent.targetPosition; - microbeComponent.movementDirection = Float3(0, 0, -AI_BASE_MOVEMENT); + microbeComponent.facingTargetPoint = -aiComponent.targetPosition; + microbeComponent.movementDirection = Float3(0, 0, -(AI_BASE_MOVEMENT)); aiComponent.hasTargetPosition = true; - } //Freak out and fire toxins everywhere - if (aiComponent.speciesAggression > aiComponent.speciesFear && aiComponent.speciesFocus >= GetEngine().GetRandom().GetNumber(0.0f,400.0f)) - { + if ((aiComponent.speciesAggression > aiComponent.speciesFear) && rollReverseCheck(aiComponent.speciesFocus, 400.0f)){ if (microbeComponent.hitpoints > 0 && numberOfAgentVacuoles > 0 && - (position._Position - aiComponent.targetPosition).LengthSquared() <= aiComponent.speciesFocus*10.0f) - { - if (MicrobeOperations::getCompoundAmount(world,microbeEntity,oxytoxyId) >= MINIMUM_AGENT_EMISSION_AMOUNT) - { + (position._Position - aiComponent.targetPosition).LengthSquared() <= aiComponent.speciesFocus*10.0f){ + if (MicrobeOperations::getCompoundAmount(world,microbeEntity,oxytoxyId) >= MINIMUM_AGENT_EMISSION_AMOUNT){ MicrobeOperations::emitAgent(world,microbeEntity, oxytoxyId,10.0f,aiComponent.speciesFocus*10.0f); } } } - } + } // For for firguring out which state to enter void evaluateEnvironment(MicrobeAISystemCached@ components, ObjectID prey, ObjectID predator) { //LOG_INFO("evaluating"); MicrobeAIControllerComponent@ aiComponent = components.first; - if (GetEngine().GetRandom().GetNumber(0.0f,500.0f) <= aiComponent.speciesActivity) + Position@ position = components.third; + if (rollCheck(aiComponent.speciesActivity,500.0f)) { aiComponent.lifeState = PLANTLIKE_STATE; aiComponent.boredom = 0; @@ -573,58 +539,45 @@ class MicrobeAISystem : ScriptSystem{ if (prey != NULL_OBJECT && predator != NULL_OBJECT) { //LOG_INFO("Both"); - if (aiComponent.speciesAggression > aiComponent.speciesFear) - { - aiComponent.lifeState = PREDATING_STATE; - } - else if (aiComponent.speciesAggression < aiComponent.speciesFear) - { - //aiComponent.lifeState = PREDATING_STATE; - aiComponent.lifeState = FLEEING_STATE; + if (GetEngine().GetRandom().GetNumber(0.0f,aiComponent.speciesAggression) > + GetEngine().GetRandom().GetNumber(0.0f,aiComponent.speciesFear) && + (aiComponent.preyMicrobes.length() > 0)){ + aiComponent.lifeState = PREDATING_STATE; } - else if (aiComponent.speciesAggression == aiComponent.speciesFear) - { - // Very rare - if (GetEngine().GetRandom().GetNumber(0,10) <= 5) - { - // Prefer predating by 10% (makes game more fun) - aiComponent.lifeState = PREDATING_STATE; - } - else { + else if (GetEngine().GetRandom().GetNumber(0.0f,aiComponent.speciesAggression) < + GetEngine().GetRandom().GetNumber(0.0f,aiComponent.speciesFear)&& + (aiComponent.predatoryMicrobes.length() > 0)){ + //aiComponent.lifeState = PREDATING_STATE; aiComponent.lifeState = FLEEING_STATE; - } } - // I want gathering to trigger more often so i added this here. Because even with predators and prey around its still important to eat compounds - if (GetEngine().GetRandom().GetNumber(0.0f,500.0f) <= aiComponent.speciesFocus && GetEngine().GetRandom().GetNumber(0,10) <= 2) - { - aiComponent.lifeState = GATHERING_STATE; + else if (aiComponent.speciesAggression == aiComponent.speciesFear && + (aiComponent.preyMicrobes.length() > 0)){ + // Prefer predating (makes game more fun) + aiComponent.lifeState = PREDATING_STATE; } + else if (rollCheck(aiComponent.speciesFocus,500.0f) && GetEngine().GetRandom().GetNumber(0,10) <= 2){ + aiComponent.lifeState = GATHERING_STATE; } - else if (prey != NULL_OBJECT) - { + } + else if (prey != NULL_OBJECT){ //LOG_INFO("prey only"); aiComponent.lifeState = PREDATING_STATE; - } - else if (predator != NULL_OBJECT) - { + else if (predator != NULL_OBJECT){ //LOG_INFO("predator only"); aiComponent.lifeState = FLEEING_STATE; // I want gathering to trigger more often so i added this here. Because even with predators around you should still graze - if (GetEngine().GetRandom().GetNumber(0.0f,500.0f) <= aiComponent.speciesFocus && GetEngine().GetRandom().GetNumber(0,10) <= 5) - { - aiComponent.lifeState = GATHERING_STATE; + if (rollCheck(aiComponent.speciesFocus,500.0f) && GetEngine().GetRandom().GetNumber(0,10) <= 5){ + aiComponent.lifeState = GATHERING_STATE; } } // Every 2 intervals or so - else if (GetEngine().GetRandom().GetNumber(0,10) < 8) - { + else if (GetEngine().GetRandom().GetNumber(0,10) < 8){ //LOG_INFO("gather only"); aiComponent.lifeState = GATHERING_STATE; } // Every 10 intervals or so - else if (GetEngine().GetRandom().GetNumber(0.0f,400.0f) <= aiComponent.speciesActivity) - { + else if (rollCheck(aiComponent.speciesActivity,400.0f)){ //LOG_INFO("gather only"); aiComponent.lifeState = PLANTLIKE_STATE; } @@ -649,8 +602,7 @@ class MicrobeAISystem : ScriptSystem{ float compoundDifference = aiComponent.compoundDifference; // Angle should only change if you havent picked up compounds or picked up less compounds - if (compoundDifference < 0 && GetEngine().GetRandom().GetNumber(0,10) < 5) - { + if (compoundDifference < 0 && GetEngine().GetRandom().GetNumber(0,10) < 5){ randAngle = aiComponent.previousAngle+GetEngine().GetRandom().GetFloat(0.1f,1.0f); aiComponent.previousAngle = randAngle; randDist = GetEngine().GetRandom().GetFloat(200.0f,float(aiComponent.movementRadius)); @@ -658,16 +610,14 @@ class MicrobeAISystem : ScriptSystem{ } // If last round you had 0, then have a high likelihood of turning - if (compoundDifference < AI_COMPOUND_BIAS && GetEngine().GetRandom().GetNumber(0,10) < 9) - { + if (compoundDifference < AI_COMPOUND_BIAS && GetEngine().GetRandom().GetNumber(0,10) < 9){ randAngle = aiComponent.previousAngle+GetEngine().GetRandom().GetFloat(1.0f,2.0f); aiComponent.previousAngle = randAngle; randDist = GetEngine().GetRandom().GetFloat(200.0f,float(aiComponent.movementRadius)); aiComponent.targetPosition = Float3(cos(randAngle) * randDist,0, sin(randAngle)* randDist); } - if (compoundDifference == 0 && GetEngine().GetRandom().GetNumber(0,10) < 9) - { + if (compoundDifference == 0 && GetEngine().GetRandom().GetNumber(0,10) < 9){ randAngle = aiComponent.previousAngle+GetEngine().GetRandom().GetFloat(1.0f,2.0f); aiComponent.previousAngle = randAngle; randDist = GetEngine().GetRandom().GetFloat(200.0f,float(aiComponent.movementRadius)); @@ -675,8 +625,7 @@ class MicrobeAISystem : ScriptSystem{ } // If positive last step you gained compounds - if (compoundDifference > 0 && GetEngine().GetRandom().GetNumber(0,10) < 5) - { + if (compoundDifference > 0 && GetEngine().GetRandom().GetNumber(0,10) < 5){ // If found food subtract from angle randomly; randAngle = aiComponent.previousAngle-GetEngine().GetRandom().GetFloat(0.1f,0.3f); aiComponent.previousAngle = randAngle; @@ -694,6 +643,17 @@ class MicrobeAISystem : ScriptSystem{ } + /* Personality checks */ + //There are cases when we want either or, so heres two state rolls + //TODO: add method for rolling stat versus stat + bool rollCheck(double ourStat, double dc){ + return (GetEngine().GetRandom().GetNumber(0.0f,dc) <= ourStat); + } + + bool rollReverseCheck(double ourStat, double dc){ + return (ourStat >= GetEngine().GetRandom().GetNumber(0.0f,dc)); + } + void Clear(){ CachedComponents.resize(0); } diff --git a/scripts/microbe_stage/microbe_operations.as b/scripts/microbe_stage/microbe_operations.as index 2d9c1c3f16e..65df873c3be 100644 --- a/scripts/microbe_stage/microbe_operations.as +++ b/scripts/microbe_stage/microbe_operations.as @@ -713,16 +713,8 @@ void toggleEngulfMode(MicrobeComponent@ microbeComponent) microbeComponent.movementFactor = 1.0f; // soundSourceComponent.stopSound("microbe-engulfment"); // Possibly comment out. } - else if (microbeComponent.isBeingEngulfed) - { - microbeComponent.movementFactor = microbeComponent.movementFactor / - ENGULFED_MOVEMENT_DIVISION; - } - else - { - microbeComponent.movementFactor = microbeComponent.movementFactor / - ENGULFING_MOVEMENT_DIVISION; - } + microbeComponent.movementFactor = microbeComponent.movementFactor / + ENGULFING_MOVEMENT_DIVISION; microbeComponent.engulfMode = !microbeComponent.engulfMode; } diff --git a/scripts/microbe_stage/setup.as b/scripts/microbe_stage/setup.as index 6b3c5cdb6a1..58470154b68 100644 --- a/scripts/microbe_stage/setup.as +++ b/scripts/microbe_stage/setup.as @@ -408,7 +408,6 @@ bool beingEngulfed(GameWorld@ world, ObjectID firstEntity, ObjectID secondEntity (ENGULF_HP_RATIO_REQ * secondMicrobeComponentOrganelles) && firstMicrobeComponent.dead == false && secondMicrobeComponent.dead == false) { - secondMicrobeComponent.movementFactor = secondMicrobeComponent.movementFactor/ENGULFED_MOVEMENT_DIVISION; secondMicrobeComponent.isBeingEngulfed = true; secondMicrobeComponent.hostileEngulfer = firstEntity; secondMicrobeComponent.wasBeingEngulfed = true; @@ -422,7 +421,6 @@ bool beingEngulfed(GameWorld@ world, ObjectID firstEntity, ObjectID secondEntity (ENGULF_HP_RATIO_REQ * firstMicrobeComponentOrganelles) && secondMicrobeComponent.dead == false && firstMicrobeComponent.dead == false) { - firstMicrobeComponent.movementFactor = firstMicrobeComponent.movementFactor/ENGULFED_MOVEMENT_DIVISION; firstMicrobeComponent.isBeingEngulfed = true; firstMicrobeComponent.hostileEngulfer = secondEntity; firstMicrobeComponent.wasBeingEngulfed = true;