diff --git a/scripts/microbe_stage/configs.as b/scripts/microbe_stage/configs.as index cdd1761bafe..83e592cf76c 100644 --- a/scripts/microbe_stage/configs.as +++ b/scripts/microbe_stage/configs.as @@ -23,15 +23,17 @@ const auto MAX_SPAWN_DISTANCE = 5000.0f; // Cell Colors const auto MIN_COLOR = 0.0f; const auto MAX_COLOR = 0.9f; + // Too subtle? -const auto MIN_COLOR_MUTATION = -0.005f; -const auto MAX_COLOR_MUTATION = 0.005f; +const auto MIN_COLOR_MUTATION = -0.2f; +const auto MAX_COLOR_MUTATION = 0.2f; const auto MIN_OPACITY = 0.5f; const auto MAX_OPACITY = 1.8f; const auto MIN_OPACITY_CHITIN = 0.4f; const auto MAX_OPACITY_CHITIN = 1.2f; + // Min Opacity Mutation const auto MIN_OPACITY_MUTATION = -0.01f; const auto MAX_OPACITY_MUTATION = 0.01f; @@ -40,9 +42,11 @@ const auto MAX_OPACITY_MUTATION = 0.01f; const auto MUTATION_BACTERIA_TO_EUKARYOTE = 1; const auto MUTATION_CREATION_RATE = 0.1f; const auto MUTATION_DELETION_RATE = 0.1f; +const auto MUTATION_REPLACEMENT_RATE = 0.1f; //Removal cost const auto ORGANELLE_REMOVE_COST = 10; + // Spawn Radius const auto MICROBE_SPAWN_RADIUS = 150; const auto BACTERIA_SPAWN_RADIUS = 150; @@ -101,8 +105,11 @@ const auto REGENERATION_RATE = 1.0f; const auto FLAGELLA_ENERGY_COST = 7.1f; const auto FLAGELLA_BASE_FORCE = 0.7f; const auto CELL_BASE_THRUST = 1.6f; + // is set by this and modified by applyCellMovement like the player later -const auto AI_BASE_MOVEMENT = 1.0f; +const auto AI_BASE_MOVEMENT = 1.6f; +const auto AI_FOCUSED_MOVEMENT = 1.0f; + //! The drag force is calculated by taking the current velocity and multiplying it by this. //! This must be negative! const auto CELL_DRAG_MULTIPLIER = -0.12f; diff --git a/scripts/microbe_stage/microbe_ai.as b/scripts/microbe_stage/microbe_ai.as index 512b00d2b5a..1d088e2be04 100644 --- a/scripts/microbe_stage/microbe_ai.as +++ b/scripts/microbe_stage/microbe_ai.as @@ -51,6 +51,8 @@ class MicrobeAIControllerComponent : ScriptComponent{ ObjectID prey = NULL_OBJECT; ObjectID targetChunk = NULL_OBJECT; ObjectID predator = NULL_OBJECT; + bool moveThisHunt = true; + bool moveFocused = false; bool preyPegged=false; // Prey and predator lists array predatoryMicrobes; @@ -521,12 +523,17 @@ 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){ - microbeComponent.movementDirection = Float3(0, 0, -AI_BASE_MOVEMENT); + if (aiComponent.moveThisHunt){ + if (aiComponent.moveFocused){ + microbeComponent.movementDirection = Float3(0.0f,0.0f,-AI_FOCUSED_MOVEMENT); } else{ - microbeComponent.movementDirection = Float3(0, 0, 0); + microbeComponent.movementDirection = Float3(0.0f,0.0f,-AI_BASE_MOVEMENT); } + } + else{ + microbeComponent.movementDirection = Float3(0, 0, 0); + } // Turn off engulf if prey is Dead // This is probabbly not working @@ -614,11 +621,11 @@ class MicrobeAISystem : ScriptSystem{ aiComponent.targetPosition = world.GetComponent_Position(chunk)._Position; auto vec = (aiComponent.targetPosition - position._Position); aiComponent.direction = vec.Normalize(); - microbeComponent.facingTargetPoint = aiComponent.targetPosition; + microbeComponent.facingTargetPoint = aiComponent.targetPosition; aiComponent.hasTargetPosition = true; //Always set target Position, for use later in AI - microbeComponent.movementDirection = Float3(0, 0, -AI_BASE_MOVEMENT); + microbeComponent.movementDirection = Float3(0.0f,0.0f,-AI_BASE_MOVEMENT); // Turn off engulf if chunk is gone if (engulfableComponent is null){ @@ -707,7 +714,7 @@ class MicrobeAISystem : ScriptSystem{ auto vec = (position._Position-aiComponent.targetPosition); aiComponent.direction = vec.Normalize(); microbeComponent.facingTargetPoint = -aiComponent.targetPosition; - microbeComponent.movementDirection = Float3(0, 0, -(AI_BASE_MOVEMENT)); + microbeComponent.movementDirection = Float3(0.0f,0.0f,-AI_BASE_MOVEMENT); aiComponent.hasTargetPosition = true; //Freak out and fire toxins everywhere @@ -727,17 +734,17 @@ class MicrobeAISystem : ScriptSystem{ //LOG_INFO("evaluating"); MicrobeAIControllerComponent@ aiComponent = components.first; Position@ position = components.third; + MicrobeComponent@ microbeComponent = components.second; + CompoundId oxytoxyId = SimulationParameters::compoundRegistry().getTypeId("oxytoxy"); + int numberOfAgentVacuoles = int( + microbeComponent.specialStorageOrganelles[formatUInt(oxytoxyId)]); + //rollCheck(aiComponent.speciesOpportunism,500.0f) if (rollCheck(aiComponent.speciesOpportunism,500.0f)) { aiComponent.lifeState = SCAVENGING_STATE; aiComponent.boredom = 0; } - else if (rollCheck(aiComponent.speciesActivity,500.0f)) - { - aiComponent.lifeState = PLANTLIKE_STATE; - aiComponent.boredom = 0; - } else { if (prey != NULL_OBJECT && predator != NULL_OBJECT) { @@ -745,6 +752,12 @@ class MicrobeAISystem : ScriptSystem{ if (GetEngine().GetRandom().GetNumber(0.0f,aiComponent.speciesAggression) > GetEngine().GetRandom().GetNumber(0.0f,aiComponent.speciesFear) && (aiComponent.preyMicrobes.length() > 0)){ + aiComponent.moveThisHunt=!rollCheck(aiComponent.speciesActivity,500.0f); + + if (numberOfAgentVacuoles > 0){ + aiComponent.moveFocused = rollCheck(aiComponent.speciesFocus,500.0f); + } + aiComponent.lifeState = PREDATING_STATE; } else if (GetEngine().GetRandom().GetNumber(0.0f,aiComponent.speciesAggression) < @@ -756,6 +769,12 @@ class MicrobeAISystem : ScriptSystem{ else if (aiComponent.speciesAggression == aiComponent.speciesFear && (aiComponent.preyMicrobes.length() > 0)){ // Prefer predating (makes game more fun) + aiComponent.moveThisHunt=!rollCheck(aiComponent.speciesActivity,500.0f); + + if (numberOfAgentVacuoles > 0){ + aiComponent.moveFocused = rollCheck(aiComponent.speciesFocus,500.0f); + } + aiComponent.lifeState = PREDATING_STATE; } else if (rollCheck(aiComponent.speciesFocus,500.0f) && GetEngine().GetRandom().GetNumber(0,10) <= 2){ @@ -764,6 +783,12 @@ class MicrobeAISystem : ScriptSystem{ } else if (prey != NULL_OBJECT){ //LOG_INFO("prey only"); + aiComponent.moveThisHunt=!rollCheck(aiComponent.speciesActivity,500.0f); + + if (numberOfAgentVacuoles > 0){ + aiComponent.moveFocused = rollCheck(aiComponent.speciesFocus,500.0f); + } + aiComponent.lifeState = PREDATING_STATE; } else if (predator != NULL_OBJECT){ @@ -845,7 +870,7 @@ class MicrobeAISystem : ScriptSystem{ auto vec = (aiComponent.targetPosition - position._Position); aiComponent.direction = vec.Normalize(); microbeComponent.facingTargetPoint = aiComponent.targetPosition; - microbeComponent.movementDirection = Float3(0, 0, -AI_BASE_MOVEMENT); + microbeComponent.movementDirection = Float3(0.0f,0.0f,-AI_BASE_MOVEMENT); aiComponent.hasTargetPosition = true; } diff --git a/scripts/microbe_stage/microbe_editor/microbe_editor.as b/scripts/microbe_stage/microbe_editor/microbe_editor.as index c77f922fa56..64573f7dbf7 100644 --- a/scripts/microbe_stage/microbe_editor/microbe_editor.as +++ b/scripts/microbe_stage/microbe_editor/microbe_editor.as @@ -125,10 +125,20 @@ class MicrobeEditor{ playerSpecies.organelles); editedMicrobe.resize(0); + playerSpecies.stringCode=""; for(uint i = 0; i < templateOrganelles.length(); ++i){ - editedMicrobe.insertLast(cast(templateOrganelles[i])); + auto organelle = cast(templateOrganelles[i]); + editedMicrobe.insertLast(organelle); + playerSpecies.stringCode+=organelle._organelle.gene; + // This will always be added after each organelle so its safe to assume its there + playerSpecies.stringCode+=","+organelle.q+","+ + organelle.r+","+ + organelle.rotation; + if (i != templateOrganelles.length()-1){ + playerSpecies.stringCode+="|"; + } } - + LOG_INFO(playerSpecies.stringCode); LOG_INFO("Starting microbe editor with: " + editedMicrobe.length() + " organelles in the microbe"); diff --git a/scripts/microbe_stage/organelle.as b/scripts/microbe_stage/organelle.as index 76c49fdde5d..f7d18abcf39 100644 --- a/scripts/microbe_stage/organelle.as +++ b/scripts/microbe_stage/organelle.as @@ -873,7 +873,7 @@ class PlacedOrganelle : SpeciesStoredOrganelleType{ } } - private Organelle@ _organelle; + Organelle@ _organelle; // q and r are radial coordinates instead of cartesian // Could use the class AxialCoordinates here diff --git a/scripts/microbe_stage/organelle_components/movement_organelle.as b/scripts/microbe_stage/organelle_components/movement_organelle.as index aaeb013803d..45b58dfe6a1 100644 --- a/scripts/microbe_stage/organelle_components/movement_organelle.as +++ b/scripts/microbe_stage/organelle_components/movement_organelle.as @@ -205,9 +205,12 @@ class MovementOrganelle : OrganelleComponent{ MicrobeComponent@ microbeComponent = cast( organelle.world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); auto pos = organelle.world.GetComponent_Position(microbeEntity); + + const auto force = calculateMovementForce(microbeEntity, organelle, logicTime, microbeComponent, pos); + if(force != Float3(0, 0, 0)) microbeComponent.addMovementForce(force); } diff --git a/scripts/microbe_stage/procedural_microbes.as b/scripts/microbe_stage/procedural_microbes.as index 0b1206d4cc0..48f8404bdf8 100644 --- a/scripts/microbe_stage/procedural_microbes.as +++ b/scripts/microbe_stage/procedural_microbes.as @@ -1,17 +1,7 @@ #include "configs.as" #include "nucleus_organelle.as" #include "hex.as" - -// Limits the size of the initial stringCodes -const auto MIN_INITIAL_LENGTH = 2; -const auto MAX_INITIAL_LENGTH = 15; - -const auto MIN_INITIAL_EPIC_LENGTH = 30; -const auto MAX_INITIAL_EPIC_LENGTH = 70; - -const auto MIN_INITIAL_EPIC_BACTERIA_LENGTH = 3; -const auto MAX_INITIAL_EPIC_BACTERIA_LENGTH = 30; - +// Lists of valid organelles to choose from for mutation dictionary organelleLetters = {}; array VALID_ORGANELLES = {}; array VALID_ORGANELLE_LETTERS = {}; @@ -55,6 +45,8 @@ void setupOrganelleLetters(){ // TODO: verify that this has a good chance of returning also the last organelle // TODO: is there a way to make this run faster? string getRandomLetter(bool isBacteria){ + + // This is actually essentially the entire mutation system here if (!isBacteria) { float i = GetEngine().GetRandom().GetNumber(0.f, maxEukaryoteScore); @@ -86,18 +78,19 @@ string getRandomLetter(bool isBacteria){ // Checks whether an organelle in a certain position would fit within a list of other organelles. bool isValidPlacement(const string &in organelleName, int q, int r, int rotation, - const array &in organelleList + array@ organelleList ) { - // This is super hacky :/ - // this is now slightly less hacky + + // this is now slightly less hacky but it could be btter auto organelleHexes = getOrganelleDefinition(organelleName).getRotatedHexes(rotation); for(uint i = 0; i < organelleList.length(); ++i){ auto otherOrganelle = organelleList[i]; + auto organelleDef = getOrganelleDefinition(otherOrganelle.organelle.name); - auto otherOrganelleHexes = getOrganelleDefinition(otherOrganelle.type).getRotatedHexes( - otherOrganelle.rotation); + // The organelles hexes + auto otherOrganelleHexes = organelleDef.getRotatedHexes(organelleList[i].rotation); for(uint thisHexIndex = 0; thisHexIndex < organelleHexes.length(); ++thisHexIndex){ @@ -119,101 +112,186 @@ bool isValidPlacement(const string &in organelleName, int q, int r, int rotation } // Finds a valid position to place the organelle and returns it -// Maybe the values should be saved? -OrganelleTemplatePlaced@ getPosition(const string &in organelleName, - const array &in organelleList +// We should be able to get far more creative with our cells now +OrganelleTemplatePlaced@ getRealisticPosition(const string &in organelleName, + array@ organelleList ) { int q = 0; int r = 0; - // Checks whether the center is free. - for(int j = 0; j <= 5; ++j){ - int rotation = 360 * j / 6; - if(isValidPlacement(organelleName, q, r, rotation, organelleList)){ - return OrganelleTemplatePlaced(organelleName, q, r, rotation); - } - } + auto organelleShuffledArray = organelleList; - // Moving the center one hex to the bottom. - // This way organelles are "encouraged" to be on the bottom, rather than on the top, - // which in turn means the flagellum are more likely to be on the back side of the cell. - auto initialOffset = Int2(HEX_NEIGHBOUR_OFFSET[formatInt(int(HEX_SIDE::TOP))]); - q = q + initialOffset.X; - r = r + initialOffset.Y; - - // Spiral search for space for the organelle - int radius = 1; - - while(true){ - //Moves into the ring of radius "radius" and center the old organelle - Int2 radiusOffset = Int2(HEX_NEIGHBOUR_OFFSET[ - formatInt(int(HEX_SIDE::BOTTOM_LEFT))]); - q = q + radiusOffset.X; - r = r + radiusOffset.Y; - - //Iterates in the ring - for(int side = 1; side <= 6; ++side){ - Int2 offset = Int2(HEX_NEIGHBOUR_OFFSET[formatInt(side)]); - //Moves "radius" times into each direction - for(int i = 1; i <= radius; ++i){ + // Shuffle the Array to make sure its not always placing at the same part of the cell + organelleShuffledArray.sort( function(a,b) { + return GetEngine().GetRandom().GetNumber(0,100) <= 50; + } + ); + + // Loop through all the organelles and find an open spot to place our new organelle attached to existing organelles + // This almost always is over at the first iteration, so its not a huge performance hog + for(uint i = 0; i < organelleShuffledArray.length(); ++i){ + // The organelle we wish to be next to + auto otherOrganelle = organelleShuffledArray[i].organelle; + auto organelleDef = getOrganelleDefinition(otherOrganelle.name); + + // The organelles hexes + auto hexes = organelleDef.getRotatedHexes(organelleShuffledArray[i].rotation); + + // Middle of our organelle + q = organelleShuffledArray[i].q; + r = organelleShuffledArray[i].r; + + for(uint z = 0; z < hexes.length(); ++z){ + // Off set by hexes in organelle we are looking at + q+=hexes[z].q; + r+=hexes[z].r; + + for(int side = 1; side <= 6; ++side){ + Int2 offset = Int2(HEX_NEIGHBOUR_OFFSET[formatInt(side)]); + // Offset by hex offset q = q + offset.X; r = r + offset.Y; - //Checks every possible rotation value. + //Check every possible rotation value. for(int j = 0; j <= 5; ++j){ - int rotation = (360 * j / 6); - - if(isValidPlacement(organelleName, q, r, rotation, organelleList)){ + if(isValidPlacement(organelleName, q, r, rotation, organelleShuffledArray)){ return OrganelleTemplatePlaced(organelleName, q, r, rotation); } } } - } - ++radius; - } + //Gotta reset each time + q = organelleShuffledArray[i].q; + r = organelleShuffledArray[i].r; + } + } + // We didnt find an open spot, that doesnt mak emuch sense return null; } +// This function takes in a positioning block from the string code and a name +// and returns an organelle with the correct position info +OrganelleTemplatePlaced@ getStringCodePosition(const string &in organelleName, string code){ + //LOG_INFO(code); + + array@ chromArray = code.split(","); + //TODO:Need to add some proper error handling + int q = 0; + int r = 0; + int rotation = 0; + + q=parseInt(chromArray[1]); + + //LOG_INFO(""+q); + r=parseInt(chromArray[2]); + + //LOG_INFO(""+r); + + rotation=parseInt(chromArray[3]); + + //LOG_INFO(""+rotation); + + return OrganelleTemplatePlaced(organelleName, q, r, rotation); +} + // Creates a list of organelles from the stringCode. array@ positionOrganelles(const string &in stringCode){ // TODO: remove once this works - LOG_INFO("DEBUG: positionOrganelles stringCode: " + stringCode); + //LOG_INFO("DEBUG: positionOrganelles stringCode: " + stringCode); array@ result = array(); - array organelleList; + array@ chromArray = stringCode.split("|"); + for(uint i = 0; i < chromArray.length(); ++i){ + OrganelleTemplatePlaced@ pos; + string geneCode = chromArray[i]; + + if (geneCode.length() > 0){ + const auto letter = CharacterToString(geneCode[0]); + //LOG_WRITE(formatUInt(i) + ": " + letter); + string name = string(organelleLetters[letter]); + @pos = getStringCodePosition(name,geneCode); + + if(pos.type == ""){ + assert(false, "positionOrganelles: organelleLetters didn't have the " + "current letter: " + letter); + } - for(uint i = 0; i < stringCode.length(); ++i){ + result.insertLast(PlacedOrganelle(getOrganelleDefinition(pos.type), pos.q, pos.r, + pos.rotation)); + } + } - OrganelleTemplatePlaced@ pos; - const auto letter = CharacterToString(stringCode[i]); - // LOG_WRITE(formatUInt(i) + ": " + letter); - string name = string(organelleLetters[letter]); - //this places the nucleus - if(i == 0){ + return result; +} - @pos = OrganelleTemplatePlaced(name, 0, 0, 360); +//! Mutates a species' dna code randomly - } else { - @pos = getPosition(name, organelleList); - } +string translateOrganelleToGene(OrganelleTemplatePlaced@ ourOrganelle){ + string completeString = ""; + auto organelle = getOrganelleDefinition(ourOrganelle.type); + completeString=organelle.gene+","+ + ourOrganelle.q+","+ + ourOrganelle.r+","+ + ourOrganelle.rotation; + return completeString; - if(pos.type == ""){ +} + +// Pass in the string code, isbacteria +string mutateMicrobe(const string &in stringCode, bool isBacteria) +{ + array@ chromArray = stringCode.split("|"); + array@ modifiedArray = chromArray; + LOG_INFO(chromArray[0]); + string completeString = ""; + + // Delete or replace an organelle randomly + for(uint i = 0; i < chromArray.length(); i++){ + string chromosomes = chromArray[i]; + // Removing last organelle would be silly + if(GetEngine().GetRandom().GetNumber(0.f, 1.f) < MUTATION_DELETION_RATE && chromosomes.length() > 0){ + if (i != chromArray.length()-1 && CharacterToString(chromosomes[0]) != "N"){ + //LOG_INFO("deleteing"); + //LOG_INFO("chromosomes:"+chromArray[i]); + // Delete organelle and its position + modifiedArray.removeAt(i); - assert(false, "positionOrganelles: organelleLetters didn't have the " - "current letter: " + letter); + } + }else if(GetEngine().GetRandom().GetNumber(0.f, 1.f) < MUTATION_REPLACEMENT_RATE && chromosomes.length() > 0){ + if (CharacterToString(chromosomes[0]) != "N"){ + //LOG_INFO("Replacing"); + //LOG_INFO("chromosomes:"+chromArray[i]); + chromosomes[0]=getRandomLetter(isBacteria)[0]; + if (i != chromArray.length()-1){ + modifiedArray.removeAt(i); + modifiedArray.insertAt(i,chromosomes); + } + else{ + modifiedArray.removeAt(i); + modifiedArray.insertLast(chromosomes); + } + } } - organelleList.insertLast(pos); - result.insertLast(PlacedOrganelle(getOrganelleDefinition(pos.type), pos.q, pos.r, - pos.rotation)); } - // Make sure all were added - assert(stringCode.length() == result.length()); - return result; + completeString = join(modifiedArray,"|"); + + // We can insert new organelles at the end of the list + if(GetEngine().GetRandom().GetNumber(0.f, 1.f) < MUTATION_CREATION_RATE){ + auto organelleList = positionOrganelles(completeString); + const auto letter = getRandomLetter(isBacteria); + string name = string(organelleLetters[letter]); + string returnedGenome = translateOrganelleToGene(getRealisticPosition(name,organelleList)); + //LOG_INFO("Adding"); + //LOG_INFO("chromosomes:"+returnedGenome); + completeString+="|"+returnedGenome; + } + + LOG_INFO("Mutated: "+completeString); + return completeString; } diff --git a/scripts/microbe_stage/species_system.as b/scripts/microbe_stage/species_system.as index ce4cd544d04..05c6ae09368 100644 --- a/scripts/microbe_stage/species_system.as +++ b/scripts/microbe_stage/species_system.as @@ -266,19 +266,20 @@ class Species{ Species(SpeciesComponent@ parent, CellStageWorld@ world, bool isBacteria) { this.isBacteria = parent.isBacteria; - + LOG_INFO("Gene Code Is:"+parent.stringCode); if (!isBacteria) { name = randomSpeciesName(); + //Mutate the epithet - if (GetEngine().GetRandom().GetNumber(0, 10) < 8){ + if (GetEngine().GetRandom().GetNumber(0, 10) < 5){ epithet = mutateWord(parent.epithet); } else { epithet = generateNameSection(); } genus = parent.genus; - + colour=parent.colour; mutateBehavior(parent); // Make sure not over or under our scales @@ -286,20 +287,19 @@ class Species{ // Subtly mutate color - if (GetEngine().GetRandom().GetNumber(0,5) == 0) - { - this.colour = Float4(parent.colour.X + randomMutationColourChannel(), - parent.colour.Y + randomMutationColourChannel(), - parent.colour.Z + randomMutationColourChannel(), - parent.colour.W + randomMutationColourChannel()); - } + this.colour = Float4(parent.colour.X + randomMutationColourChannel(), + parent.colour.Y + randomMutationColourChannel(), + parent.colour.Z + randomMutationColourChannel(), + parent.colour.W + randomMutationColourChannel()); + LOG_INFO("X:"+parent.colour.X+" Y:"+parent.colour.Y+" Z:"+parent.colour.Z+" W:"+parent.colour.W); + LOG_INFO("X:"+colour.X+" Y:"+colour.Y+" Z:"+colour.Z+" W:"+colour.W); // Chance of new color needs to be low - if (GetEngine().GetRandom().GetNumber(0,100)==1) + if (GetEngine().GetRandom().GetNumber(0,100) <= 20) { LOG_INFO("New Genus"); // We can do more fun stuff here later - if (GetEngine().GetRandom().GetNumber(0, 10) < 8){ + if (GetEngine().GetRandom().GetNumber(0, 10) < 5){ genus = mutateWord(parent.genus); } else { @@ -312,28 +312,10 @@ class Species{ parent.colour.W + randomMutationColourChannel()); } - this.stringCode = Species::mutate(parent.stringCode); + this.stringCode = mutateMicrobe(parent.stringCode,false); - if (GetEngine().GetRandom().GetNumber(0,100)<=20){ - if (GetEngine().GetRandom().GetNumber(0,100) < 50){ - this.speciesMembraneType = MEMBRANE_TYPE::MEMBRANE; - } - else if (GetEngine().GetRandom().GetNumber(0,100) < 50) { - this.speciesMembraneType = MEMBRANE_TYPE::DOUBLEMEMBRANE; - this.colour.W = randomOpacityChitin();; - } - else if (GetEngine().GetRandom().GetNumber(0,100) < 50) { - this.speciesMembraneType = MEMBRANE_TYPE::WALL; - } - else { - this.speciesMembraneType = MEMBRANE_TYPE::CHITIN; - this.colour.W = randomOpacityChitin(); - } - } - else { - this.speciesMembraneType = parent.speciesMembraneType; - } + generateMembranes(parent); commonConstructor(world); @@ -347,6 +329,28 @@ class Species{ } } + private void generateMembranes(SpeciesComponent@ parent){ + if (GetEngine().GetRandom().GetNumber(0,100)<=20){ + if (GetEngine().GetRandom().GetNumber(0,100) < 50){ + this.speciesMembraneType = MEMBRANE_TYPE::MEMBRANE; + } + else if (GetEngine().GetRandom().GetNumber(0,100) < 50) { + this.speciesMembraneType = MEMBRANE_TYPE::DOUBLEMEMBRANE; + this.colour.W = randomOpacityChitin(); + } + else if (GetEngine().GetRandom().GetNumber(0,100) < 50) { + this.speciesMembraneType = MEMBRANE_TYPE::WALL; + } + else { + this.speciesMembraneType = MEMBRANE_TYPE::CHITIN; + this.colour.W = randomOpacityChitin(); + } + } + else{ + this.speciesMembraneType = parent.speciesMembraneType; + } + } + private void cleanPersonality() { this.aggression = clamp(this.aggression, 0.0f, MAX_SPECIES_AGRESSION); this.fear = clamp(this.fear, 0.0f, MAX_SPECIES_FEAR); @@ -373,7 +377,9 @@ class Species{ { @forWorld = world; + // This translates the genetic code into positions auto organelles = positionOrganelles(stringCode); + // If you have iron (f is the symbol for rusticyanin) if (stringCode.findFirst('f') >= 0) { @@ -585,8 +591,9 @@ class Species{ { name = randomBacteriaName(); genus = parent.genus; + colour=parent.colour; //Mutate the epithet - if (GetEngine().GetRandom().GetNumber(0, 10) < 8){ + if (GetEngine().GetRandom().GetNumber(0, 10) < 5){ epithet = mutateWord(parent.epithet); } else { @@ -600,21 +607,22 @@ class Species{ cleanPersonality(); // Subtly mutate color - if (GetEngine().GetRandom().GetNumber(0, 5)==0) - { - this.colour = Float4(parent.colour.X + randomMutationColourChannel(), - parent.colour.Y + randomMutationColourChannel(), - parent.colour.Z + randomMutationColourChannel(), - parent.colour.W + randomMutationColourChannel()); - } + this.colour = Float4(parent.colour.X + randomMutationColourChannel(), + parent.colour.Y + randomMutationColourChannel(), + parent.colour.Z + randomMutationColourChannel(), + parent.colour.W + randomMutationColourChannel()); - if (GetEngine().GetRandom().GetNumber(0, 100)==1) + + LOG_INFO("X:"+parent.colour.X+" Y:"+parent.colour.Y+" Z:"+parent.colour.Z+" W:"+parent.colour.W); + LOG_INFO("X:"+colour.X+" Y:"+colour.Y+" Z:"+colour.Z+" W:"+colour.W); + + if (GetEngine().GetRandom().GetNumber(0,100) <= 20) { LOG_INFO("New Genus of bacteria"); // We can do more fun stuff here later //Mutate the genus - if (GetEngine().GetRandom().GetNumber(0, 10) < 8){ + if (GetEngine().GetRandom().GetNumber(0, 10) < 5){ genus = mutateWord(parent.genus); } else { @@ -628,27 +636,9 @@ class Species{ parent.colour.W + randomMutationColourChannel()); } - this.stringCode = Species::mutateProkaryote(parent.stringCode); + this.stringCode = mutateMicrobe(parent.stringCode,true); - if (GetEngine().GetRandom().GetNumber(0,100)<=20){ - if (GetEngine().GetRandom().GetNumber(0,100) < 50){ - this.speciesMembraneType = MEMBRANE_TYPE::MEMBRANE; - } - else if (GetEngine().GetRandom().GetNumber(0,100) < 50) { - this.speciesMembraneType = MEMBRANE_TYPE::DOUBLEMEMBRANE; - this.colour.W = randomOpacityChitin();; - } - else if (GetEngine().GetRandom().GetNumber(0,100) < 50) { - this.speciesMembraneType = MEMBRANE_TYPE::WALL; - } - else { - this.speciesMembraneType = MEMBRANE_TYPE::CHITIN; - this.colour.W = randomOpacityChitin(); - } - } - else { - this.speciesMembraneType = parent.speciesMembraneType; - } + generateMembranes(parent); commonConstructor(world); this.setupSpawn(world); @@ -1064,6 +1054,7 @@ void applyTemplate(CellStageWorld@ world, ObjectID microbe, SpeciesComponent@ sp InitialCompound amount = InitialCompound(species.avgCompoundAmounts[ids[i]]); MicrobeOperations::setCompound(world, microbe, compoundId, amount.amount); } + } void restoreOrganelleLayout(CellStageWorld@ world, ObjectID microbeEntity, @@ -1097,6 +1088,11 @@ void restoreOrganelleLayout(CellStageWorld@ world, ObjectID microbeEntity, // Cache isBacteria from species. This can be changed depending on // the added organelles in the editor microbeComponent.isBacteria = species.isBacteria; + + // Call this to reset processor component + Species::initProcessorComponent(world, microbeEntity, species); + // This makes sure that the microbes processer are up to date with their species + Species::copyProcessesFromSpecies(world, species, microbeEntity); } void initProcessorComponent(CellStageWorld@ world, ObjectID entity, @@ -1237,11 +1233,20 @@ ObjectID createSpecies(CellStageWorld@ world, const string &in name, const strin @speciesComponent.avgCompoundAmounts = dictionary(); @speciesComponent.organelles = array(); - for(uint i = 0; i < organelles.length(); i++){ - - // This conversion does a little bit of extra calculations (that are in the - // end not used) - speciesComponent.organelles.insertLast(PlacedOrganelle(organelles[i])); + speciesComponent.stringCode=""; + + // Translate positions over + for(uint i = 0; i < organelles.length(); ++i){ + auto organelle = cast(organelles[i]); + speciesComponent.organelles.insertLast(organelle); + speciesComponent.stringCode+=organelle._organelle.gene; + // This will always be added after each organelle so its safe to assume its there + speciesComponent.stringCode+=","+organelle.q+","+ + organelle.r+","+ + organelle.rotation; + if (i != organelles.length()-1){ + speciesComponent.stringCode+="|"; + } } // Verify it // @@ -1297,91 +1302,6 @@ ObjectID createSpecies(CellStageWorld@ world, const string &in name, const strin return speciesEntity; } - -//! Mutates a species' dna code randomly -string mutate(const string &in stringCode) -{ - // Moving the stringCode to a table to facilitate changes - string chromosomes = stringCode.substr(2); - - // Try to insert a letter at the end of the table. - if(GetEngine().GetRandom().GetNumber(0.f, 1.f) < MUTATION_CREATION_RATE){ - chromosomes += getRandomLetter(false); - } - - // Modifies the rest of the table. - for(uint i = 0; i < stringCode.length(); i++){ - // Index we are adding or erasing chromosomes at - uint index = stringCode.length() - i - 1; - - if(GetEngine().GetRandom().GetNumber(0.f, 1.f) < MUTATION_DELETION_RATE){ - // Removing the last organelle is pointless, that would - // kill the creature (also caused errors). - if (index != stringCode.length()-1) - { - chromosomes.erase(index, 1); - } - } - - if(GetEngine().GetRandom().GetNumber(0.f, 1.f) < MUTATION_CREATION_RATE){ - // There is an error here when we try to insert at the end - // of the list so use insertlast instead in that case - if (index != stringCode.length()-1) - { - chromosomes.insert(index, getRandomLetter(false)); - } - else{ - chromosomes+=getRandomLetter(false); - } - } - } - - // Transforming the table back into a string - // TODO: remove Hardcoded microbe genes - auto newString = "NY" + chromosomes; - return newString; -} - -// Mutate a Bacterium -string mutateProkaryote(const string &in stringCode) -{ - // Moving the stringCode to a table to facilitate changes - string chromosomes = stringCode; - - // Try to insert a letter at the end of the table. - if(GetEngine().GetRandom().GetNumber(0.f, 1.f) < MUTATION_CREATION_RATE){ - chromosomes += getRandomLetter(true); - } - - // Modifies the rest of the table. - for(uint i = 0; i < stringCode.length(); i++){ - // Index we are adding or erasing chromosomes at - uint index = stringCode.length() - i -1; - // Bacteria can be size 1 so removing their only organelle is a bad idea - if(GetEngine().GetRandom().GetNumber(0.f, 1.f) < MUTATION_DELETION_RATE){ - if (index != stringCode.length()-1) - { - chromosomes.erase(index, 1); - } - } - - if(GetEngine().GetRandom().GetNumber(0.f, 1.f) < MUTATION_CREATION_RATE){ - // There is an error here when we try to insert at the end - // of the list so use insertlast instead in that case - if (index != stringCode.length()-1) - { - chromosomes.insert(index, getRandomLetter(true)); - } - else{ - chromosomes+=getRandomLetter(true); - } - } - } - - auto newString = "" + chromosomes; - return newString; -} - //! Calls resetAutoEvo on world's SpeciesSystem void resetAutoEvo(CellStageWorld@ world){ cast(world.GetScriptSystem("SpeciesSystem")).resetAutoEvo();