From da9aecb1a03974c544fd66c0fdbdef621c8abcba Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Mon, 21 Jan 2019 11:53:08 -0600 Subject: [PATCH 01/42] Added floating "iron" Iron particles now dont get destroyed when you run into them and are hard to push --- scripts/microbe_stage/setup.as | 68 ++++++++++++++++++++++++++++++++-- src/thrive_common.cpp | 27 ++++++++++++++ 2 files changed, 92 insertions(+), 3 deletions(-) diff --git a/scripts/microbe_stage/setup.as b/scripts/microbe_stage/setup.as index 58470154b68..8e54fe53b49 100644 --- a/scripts/microbe_stage/setup.as +++ b/scripts/microbe_stage/setup.as @@ -269,7 +269,6 @@ void onReturnFromEditor(CellStageWorld@ world) } -// TODO: also put these physics callback somewhere more sensible (maybe physics_callbacks.as?) void cellHitFloatingOrganelle(GameWorld@ world, ObjectID firstEntity, ObjectID secondEntity) { // Determine which is the organelle @@ -294,6 +293,31 @@ void cellHitFloatingOrganelle(GameWorld@ world, ObjectID firstEntity, ObjectID s world.QueueDestroyEntity(floatingEntity); } +// TODO: also put these physics callback somewhere more sensible (maybe physics_callbacks.as?) +void cellHitIron(GameWorld@ world, ObjectID firstEntity, ObjectID secondEntity) +{ + // Determine which is the iron + CellStageWorld@ asCellWorld = cast(world); + + auto model = asCellWorld.GetComponent_Model(firstEntity); + auto floatingEntity = firstEntity; + auto cellEntity = secondEntity; + + // Cell doesn't have a model + if(model is null){ + + @model = asCellWorld.GetComponent_Model(secondEntity); + floatingEntity = secondEntity; + cellEntity = firstEntity; + } + + // TODO: use this to detect stuff + LOG_INFO("Model: " + model.GraphicalObject.getMesh().getName()); + LOG_INFO("TODO: organelle unlock progress if cell: " + cellEntity + " is the player"); + + //world.QueueDestroyEntity(floatingEntity); +} + // Cell Hit Oxytoxy // We can make this generic using the dictionary in agents.as // eventually, but for now all we have is oxytoxy @@ -624,6 +648,39 @@ ObjectID createChloroplast(CellStageWorld@ world, Float3 pos) return chloroplastEntity; } +ObjectID createIron(CellStageWorld@ world, Float3 pos) +{ + // Chloroplasts + ObjectID ironEntity = world.CreateEntity(); + + auto position = world.Create_Position(ironEntity, pos, + Ogre::Quaternion(Ogre::Degree(GetEngine().GetRandom().GetNumber(0, 360)), + Ogre::Vector3(0,1,1))); + + auto renderNode = world.Create_RenderNode(ironEntity); + renderNode.Scale = Float3(1, 1, 1); + renderNode.Marked = true; + renderNode.Node.setOrientation(Ogre::Quaternion( + Ogre::Degree(GetEngine().GetRandom().GetNumber(0, 360)), + Ogre::Vector3(0,1,1))); + renderNode.Node.setPosition(pos); + auto model = world.Create_Model(ironEntity, renderNode.Node, "iron_01.mesh"); + // Need to set the tint + model.GraphicalObject.setCustomParameter(1, Ogre::Vector4(1, 1, 1, 1)); + + auto rigidBody = world.Create_Physics(ironEntity, position); + auto body = rigidBody.CreatePhysicsBody(world.GetPhysicalWorld(), + world.GetPhysicalWorld().CreateSphere(1), 100, + //iron + world.GetPhysicalMaterial("iron")); + + body.ConstraintMovementAxises(); + + rigidBody.JumpTo(position); + + return ironEntity; +} + // TODO: the player species handling would be more logically placed if // it was in SpeciesSystem, so move it there void setupSpawnSystem(CellStageWorld@ world){ @@ -663,13 +720,18 @@ void setupFloatingOrganelles(CellStageWorld@ world){ LOG_INFO("setting up free floating organelles"); SpawnSystem@ spawnSystem = world.GetSpawnSystem(); - //spawn toxin and chloroplasts + // chloroplasts const auto chloroId = spawnSystem.addSpawnType( @createChloroplast, DEFAULT_SPAWN_DENSITY, MICROBE_SPAWN_RADIUS); - //toxins + // toxins const auto toxinId = spawnSystem.addSpawnType( @createToxin, DEFAULT_SPAWN_DENSITY, MICROBE_SPAWN_RADIUS); + + // iron + const auto ironId = spawnSystem.addSpawnType( + @createIron, DEFAULT_SPAWN_DENSITY, + MICROBE_SPAWN_RADIUS); } diff --git a/src/thrive_common.cpp b/src/thrive_common.cpp index 7e034f262b6..67352249b64 100644 --- a/src/thrive_common.cpp +++ b/src/thrive_common.cpp @@ -146,6 +146,24 @@ void LOG_ERROR("Failed to run script side cellHitFloatingOrganelle"); } +void + cellHitIron(Leviathan::PhysicalWorld& physicalWorld, + Leviathan::PhysicsBody& first, + Leviathan::PhysicsBody& second) +{ + GameWorld* gameWorld = physicalWorld.GetGameWorld(); + + ScriptRunningSetup setup("cellHitIron"); + + auto result = + ThriveCommon::get()->getMicrobeScripts()->ExecuteOnModule(setup, + false, gameWorld, first.GetOwningEntity(), + second.GetOwningEntity()); + + if(result.Result != SCRIPT_RUN_RESULT::Success) + LOG_ERROR("Failed to run script side cellHitIron"); +} + //! \todo This should return false when either cell is engulfing and apply the //! damaging effect bool @@ -244,6 +262,8 @@ std::unique_ptr std::make_unique("cell", 1); auto floatingOrganelleMaterial = std::make_unique("floatingOrganelle", 2); + auto ironMaterial = + std::make_unique("iron", 2); auto agentMaterial = std::make_unique("agentCollision", 3); @@ -252,9 +272,15 @@ std::unique_ptr // Floating organelles cellMaterial->FormPairWith(*floatingOrganelleMaterial) .SetCallbacks(nullptr, cellHitFloatingOrganelle); + + // Iron + cellMaterial->FormPairWith(*ironMaterial) + .SetCallbacks(nullptr, cellHitIron); + // Agents cellMaterial->FormPairWith(*agentMaterial) .SetCallbacks(agentCallback, agentCollided); + // Engulfing cellMaterial->FormPairWith(*cellMaterial) .SetCallbacks(cellOnCellAABBHitCallback, cellOnCellActualContact); @@ -263,6 +289,7 @@ std::unique_ptr manager->LoadedMaterialAdd(std::move(cellMaterial)); manager->LoadedMaterialAdd(std::move(floatingOrganelleMaterial)); + manager->LoadedMaterialAdd(std::move(ironMaterial)); manager->LoadedMaterialAdd(std::move(agentMaterial)); return manager; From 6f1163f9acdb0a7bcaa57d35471dc9e396e8f372 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Mon, 21 Jan 2019 13:10:06 -0600 Subject: [PATCH 02/42] fixed bug where floating chloeoplasts wouldnt get deleted --- src/thrive_common.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/thrive_common.cpp b/src/thrive_common.cpp index 67352249b64..66706e4a394 100644 --- a/src/thrive_common.cpp +++ b/src/thrive_common.cpp @@ -262,10 +262,10 @@ std::unique_ptr std::make_unique("cell", 1); auto floatingOrganelleMaterial = std::make_unique("floatingOrganelle", 2); - auto ironMaterial = - std::make_unique("iron", 2); auto agentMaterial = std::make_unique("agentCollision", 3); + auto ironMaterial = + std::make_unique("iron", 4); // Set callbacks // @@ -289,8 +289,8 @@ std::unique_ptr manager->LoadedMaterialAdd(std::move(cellMaterial)); manager->LoadedMaterialAdd(std::move(floatingOrganelleMaterial)); - manager->LoadedMaterialAdd(std::move(ironMaterial)); manager->LoadedMaterialAdd(std::move(agentMaterial)); + manager->LoadedMaterialAdd(std::move(ironMaterial)); return manager; } From 546c4ae6d3c17d23e380c5d9b0722ece858efdde Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Tue, 22 Jan 2019 12:14:24 -0600 Subject: [PATCH 03/42] game now uses all iron meshes when generating iron --- scripts/microbe_stage/setup.as | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/scripts/microbe_stage/setup.as b/scripts/microbe_stage/setup.as index 8e54fe53b49..244387cb4db 100644 --- a/scripts/microbe_stage/setup.as +++ b/scripts/microbe_stage/setup.as @@ -664,7 +664,24 @@ ObjectID createIron(CellStageWorld@ world, Float3 pos) Ogre::Degree(GetEngine().GetRandom().GetNumber(0, 360)), Ogre::Vector3(0,1,1))); renderNode.Node.setPosition(pos); - auto model = world.Create_Model(ironEntity, renderNode.Node, "iron_01.mesh"); + string mesh=""; + // There are four kinds + switch (GetEngine().GetRandom().GetNumber(0, 3)) + { + case 0: + mesh="iron_01.mesh"; + break; + case 1: + mesh="iron_02.mesh"; + break; + case 2: + mesh="iron_03.mesh"; + break; + case 3: + mesh="iron_04.mesh"; + break; + } + auto model = world.Create_Model(ironEntity, renderNode.Node, mesh); // Need to set the tint model.GraphicalObject.setCustomParameter(1, Ogre::Vector4(1, 1, 1, 1)); From a6c70c524c25e70aacda3265a57f40750956e812 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Tue, 22 Jan 2019 13:23:09 -0600 Subject: [PATCH 04/42] ran code formatteing script, and added TJwhales balance changes --- scripts/microbe_stage/setup.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/microbe_stage/setup.as b/scripts/microbe_stage/setup.as index 244387cb4db..b7f35fdd6ee 100644 --- a/scripts/microbe_stage/setup.as +++ b/scripts/microbe_stage/setup.as @@ -746,7 +746,7 @@ void setupFloatingOrganelles(CellStageWorld@ world){ const auto toxinId = spawnSystem.addSpawnType( @createToxin, DEFAULT_SPAWN_DENSITY, MICROBE_SPAWN_RADIUS); - + // iron const auto ironId = spawnSystem.addSpawnType( @createIron, DEFAULT_SPAWN_DENSITY, From efd703003d54a1e522bf196598fa831c456d0450 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Tue, 22 Jan 2019 15:20:44 -0600 Subject: [PATCH 05/42] Added iron compound game now locks up on start ran code formatter script Iron clouds now at least spawn, gamecrashes when it tries reposition though iron clouds seem to work now. Theres probabbly other places i need to make changes, but the game is no longer crashing, also i plan to make that multiple check less arcane by using a float ran formatting script, added check to cloud reposition that checks ID's , game crashes when it does that sometime snow, not sure why, still working on it. added some basic error checking to a function that assumed all clouds had all 4 compounds set to non null_compound , when in reality we noe had clouds that only had one non-null compound, its working without crashing now --- .../MicrobeStage/Biomes.json | 54 ++++++++++ .../MicrobeStage/Compounds.json | 13 +++ src/microbe_stage/compound_cloud_system.cpp | 100 ++++++++++-------- 3 files changed, 124 insertions(+), 43 deletions(-) diff --git a/scripts/SimulationParameters/MicrobeStage/Biomes.json b/scripts/SimulationParameters/MicrobeStage/Biomes.json index 2ed652b12d2..59f57d9c141 100644 --- a/scripts/SimulationParameters/MicrobeStage/Biomes.json +++ b/scripts/SimulationParameters/MicrobeStage/Biomes.json @@ -42,6 +42,12 @@ "dissolved": 0.0 }, + "iron": { + "amount": 325000, + "density": 0.00002, + "dissolved": 0.0 + }, + "oxygen": { "amount": 0, "density": 0.0, @@ -99,6 +105,12 @@ "dissolved": 0.0 }, + "iron": { + "amount": 325000, + "density": 0.00002, + "dissolved": 0.0 + }, + "oxygen": { "amount": 0, "density": 0.0, @@ -155,6 +167,12 @@ "dissolved": 0.0 }, + "iron": { + "amount": 325000, + "density": 0.00002, + "dissolved": 0.0 + }, + "oxygen": { "amount": 0, "density": 0.0, @@ -209,6 +227,12 @@ "dissolved": 0.0 }, + "iron": { + "amount": 325000, + "density": 0.00002, + "dissolved": 0.0 + }, + "oxygen": { "amount": 0, "density": 0.0, @@ -264,6 +288,12 @@ "dissolved": 0.0 }, + "iron": { + "amount": 325000, + "density": 0.00002, + "dissolved": 0.0 + }, + "oxygen": { "amount": 0, "density": 0.0, @@ -319,6 +349,12 @@ "dissolved": 0.0 }, + "iron": { + "amount": 325000, + "density": 0.00002, + "dissolved": 0.0 + }, + "oxygen": { "amount": 0, "density": 0.0, @@ -374,6 +410,12 @@ "dissolved": 0.0 }, + "iron": { + "amount": 325000, + "density": 0.00002, + "dissolved": 0.0 + }, + "oxygen": { "amount": 0, "density": 0.0, @@ -431,6 +473,12 @@ "dissolved": 0.0 }, + "iron": { + "amount": 325000, + "density": 0.00002, + "dissolved": 0.0 + }, + "oxygen": { "amount": 0, "density": 0.0, @@ -488,6 +536,12 @@ "dissolved": 0.0 }, + "iron": { + "amount": 325000, + "density": 0.00002, + "dissolved": 0.0 + }, + "oxygen": { "amount": 0, "density": 0.0, diff --git a/scripts/SimulationParameters/MicrobeStage/Compounds.json b/scripts/SimulationParameters/MicrobeStage/Compounds.json index c0979c86914..d7f4d5cbd30 100644 --- a/scripts/SimulationParameters/MicrobeStage/Compounds.json +++ b/scripts/SimulationParameters/MicrobeStage/Compounds.json @@ -101,5 +101,18 @@ "g": 0.0, "b": 0.0 } + }, + + "iron": { + "name": "Iron", + "volume": 1, + "isCloud": true, + "isUseful": false, + "isEnvironmental": false, + "colour": { + "r": 0.28, + "g": 0.098, + "b": 0.02 + } } } diff --git a/src/microbe_stage/compound_cloud_system.cpp b/src/microbe_stage/compound_cloud_system.cpp index 5d728c3c067..ddf378b196e 100644 --- a/src/microbe_stage/compound_cloud_system.cpp +++ b/src/microbe_stage/compound_cloud_system.cpp @@ -286,18 +286,24 @@ void // Clear data. Maybe there is a faster way for(size_t x = 0; x < m_density1.size(); ++x) { for(size_t y = 0; y < m_density1[x].size(); ++y) { + if(m_compoundId1 != NULL_COMPOUND) { + m_density1[x][y] = 0; + m_oldDens1[x][y] = 0; + } - m_density1[x][y] = 0; - m_oldDens1[x][y] = 0; - - m_density2[x][y] = 0; - m_oldDens2[x][y] = 0; - - m_density3[x][y] = 0; - m_oldDens3[x][y] = 0; + if(m_compoundId2 != NULL_COMPOUND) { + m_density2[x][y] = 0; + m_oldDens2[x][y] = 0; + } - m_density4[x][y] = 0; - m_oldDens4[x][y] = 0; + if(m_compoundId3 != NULL_COMPOUND) { + m_density3[x][y] = 0; + m_oldDens3[x][y] = 0; + } + if(m_compoundId4 != NULL_COMPOUND) { + m_density4[x][y] = 0; + m_oldDens4[x][y] = 0; + } } } } @@ -661,12 +667,13 @@ void const Float3& playerPos) { // Initial spawning if everything is empty + int cloudTypesNum = m_cloudTypes.size(); + if(m_managedClouds.empty()) { LOG_INFO("CompoundCloudSystem doing initial spawning"); m_cloudGridCenter = Float3(0, 0, 0); - for(size_t i = 0; i < m_cloudTypes.size(); i += CLOUDS_IN_ONE) { // Center @@ -713,8 +720,12 @@ void i); } } - - LEVIATHAN_ASSERT(m_managedClouds.size() == 9, + // This rounds up to the nearest multiple of 4, + // divides that by 4 and multiplies by 9 to get all the clouds we have + // (if we have 5 compounds that are clouds, we need 18 clouds, if 4 we need + // 9 etc) + LEVIATHAN_ASSERT( + m_managedClouds.size() == ((((cloudTypesNum + 4 - 1) / 4 * 4) / 4) * 9), "A CompoundCloud entity has mysteriously been destroyed"); const auto moved = playerPos - m_cloudGridCenter; @@ -772,9 +783,9 @@ void // Reposition clouds according to the origin - // MAX of 9 clouds can ever be repositioned (this is only the case when - // respawning) - constexpr size_t MAX_FAR_CLOUDS = 9; + // MAX of our cloud compounds is nearest multiple of 4 , divided by 4 + // and multiplied by 9 This case only happens when you respawn. + constexpr size_t MAX_FAR_CLOUDS = 18; std::array tooFarAwayClouds; size_t farAwayIndex = 0; @@ -818,39 +829,42 @@ void // where there isn't one size_t farAwayRepositionedIndex = 0; - for(size_t i = 0; i < std::size(requiredCloudPositions); ++i) { - - bool hasCloud = false; - const auto& requiredPos = requiredCloudPositions[i]; - - for(auto iter = m_managedClouds.begin(); - iter != m_managedClouds.end(); ++iter) { + // Loop through the cloud groups + for(size_t c = 0; c < m_cloudTypes.size(); c += CLOUDS_IN_ONE) { + // Loop for moving clouds + for(size_t i = 0; i < std::size(requiredCloudPositions); ++i) { + bool hasCloud = false; + const auto& requiredPos = requiredCloudPositions[i]; + for(auto iter = m_managedClouds.begin(); + iter != m_managedClouds.end(); ++iter) { + const auto pos = iter->second->m_position; + // An exact check might work but just to be safe slight + // inaccuracy is allowed here + if(((pos - requiredPos).HAddAbs() < Leviathan::EPSILON) && + (m_cloudTypes[c].id == + iter->second->getCompoundId1())) { + LOG_INFO("Clouds were at same position"); + hasCloud = true; + break; + } + } - const auto pos = iter->second->m_position; + if(hasCloud) + continue; - // An exact check might work but just to be safe slight - // inaccuracy is allowed here - if((pos - requiredPos).HAddAbs() < Leviathan::EPSILON) { - hasCloud = true; + if(farAwayRepositionedIndex >= farAwayIndex) { + LOG_FATAL("CompoundCloudSystem: Logic error in moving far " + "clouds (ran out), total to reposition: " + + std::to_string(farAwayIndex + 1) + + ", current index: " + + std::to_string(farAwayRepositionedIndex) + + ", position grid index: " + std::to_string(i)); break; } - } - if(hasCloud) - continue; - - if(farAwayRepositionedIndex >= farAwayIndex) { - LOG_FATAL("CompoundCloudSystem: Logic error in moving far " - "clouds (ran out), total to reposition: " + - std::to_string(farAwayIndex + 1) + - ", current index: " + - std::to_string(farAwayRepositionedIndex) + - ", position grid index: " + std::to_string(i)); - break; + tooFarAwayClouds[farAwayRepositionedIndex++]->recycleToPosition( + requiredPos); } - - tooFarAwayClouds[farAwayRepositionedIndex++]->recycleToPosition( - requiredPos); } } } From 9e4cb9324ae8de074b2112f51d0a4f5cff11983b Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Wed, 23 Jan 2019 17:25:29 -0600 Subject: [PATCH 06/42] increased base opacity of cells (this was undone?) added space that was unnessasarily removed made change suggested by hhenri, --- .../MicrobeStage/Compounds.json | 26 +++++++++---------- scripts/microbe_stage/configs.as | 2 +- src/microbe_stage/compound_cloud_system.cpp | 22 +++++++++++++--- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/scripts/SimulationParameters/MicrobeStage/Compounds.json b/scripts/SimulationParameters/MicrobeStage/Compounds.json index d7f4d5cbd30..3ada35d96f1 100644 --- a/scripts/SimulationParameters/MicrobeStage/Compounds.json +++ b/scripts/SimulationParameters/MicrobeStage/Compounds.json @@ -77,6 +77,19 @@ } }, + "iron": { + "name": "Iron", + "volume": 1, + "isCloud": true, + "isUseful": false, + "isEnvironmental": false, + "colour": { + "r": 0.28, + "g": 0.098, + "b": 0.02 + } + }, + "oxygen": { "name": "Oxygen", "volume": 1, @@ -101,18 +114,5 @@ "g": 0.0, "b": 0.0 } - }, - - "iron": { - "name": "Iron", - "volume": 1, - "isCloud": true, - "isUseful": false, - "isEnvironmental": false, - "colour": { - "r": 0.28, - "g": 0.098, - "b": 0.02 - } } } diff --git a/scripts/microbe_stage/configs.as b/scripts/microbe_stage/configs.as index 0703beaea50..884a67a5b0c 100644 --- a/scripts/microbe_stage/configs.as +++ b/scripts/microbe_stage/configs.as @@ -20,7 +20,7 @@ const auto MAX_COLOR = 0.9f; const auto MIN_COLOR_MUTATION = -0.005f; const auto MAX_COLOR_MUTATION = 0.005f; -const auto MIN_OPACITY = 0.2f; +const auto MIN_OPACITY = 0.5f; const auto MAX_OPACITY = 1.8f; const auto MIN_OPACITY_CHITIN = 0.4f; diff --git a/src/microbe_stage/compound_cloud_system.cpp b/src/microbe_stage/compound_cloud_system.cpp index ddf378b196e..2162a272cab 100644 --- a/src/microbe_stage/compound_cloud_system.cpp +++ b/src/microbe_stage/compound_cloud_system.cpp @@ -284,23 +284,36 @@ void m_position.X, CLOUD_Y_COORDINATE, m_position.Z); // Clear data. Maybe there is a faster way + if(m_compoundId1 != NULL_COMPOUND) { for(size_t x = 0; x < m_density1.size(); ++x) { for(size_t y = 0; y < m_density1[x].size(); ++y) { - if(m_compoundId1 != NULL_COMPOUND) { m_density1[x][y] = 0; m_oldDens1[x][y] = 0; } + } + } - if(m_compoundId2 != NULL_COMPOUND) { + if(m_compoundId2 != NULL_COMPOUND) { + for(size_t x = 0; x < m_density2.size(); ++x) { + for(size_t y = 0; y < m_density2[x].size(); ++y) { m_density2[x][y] = 0; m_oldDens2[x][y] = 0; } + } + } - if(m_compoundId3 != NULL_COMPOUND) { + if(m_compoundId3 != NULL_COMPOUND) { + for(size_t x = 0; x < m_density3.size(); ++x) { + for(size_t y = 0; y < m_density3[x].size(); ++y) { m_density3[x][y] = 0; m_oldDens3[x][y] = 0; } - if(m_compoundId4 != NULL_COMPOUND) { + } + } + + if(m_compoundId4 != NULL_COMPOUND) { + for(size_t x = 0; x < m_density4.size(); ++x) { + for(size_t y = 0; y < m_density4[x].size(); ++y) { m_density4[x][y] = 0; m_oldDens4[x][y] = 0; } @@ -1134,6 +1147,7 @@ void // Etc. if(cloud.m_compoundId3 != NULL_COMPOUND) fillCloudChannel(cloud.m_density3, 2, rowBytes, pDest); + if(cloud.m_compoundId4 != NULL_COMPOUND) fillCloudChannel(cloud.m_density4, 3, rowBytes, pDest); From 09113a8187bccd5b3c97953e44cd8de151293ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henri=20Hyyryl=C3=A4inen?= Date: Thu, 24 Jan 2019 18:15:25 +0200 Subject: [PATCH 07/42] Updated engine to have newer SFML --- SetupThrive.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SetupThrive.rb b/SetupThrive.rb index 59809a5bd6d..f3cafa50d59 100755 --- a/SetupThrive.rb +++ b/SetupThrive.rb @@ -78,7 +78,7 @@ def parseExtraArgs leviathan = Leviathan.new( # Use this if you always want the latest commit # version: "develop", - version: "55f85074961175d8ffecfca2e318eb093b2d9c68", + version: "556a6584f4f74d2c16d85b85ba26281a88c02171", # Doesn't actually work, but leviathan doesn't install with sudo by # default, or install at all for that matter noInstallSudo: true From b92db01516e79c85be1b57d92e30de9c35344782 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Thu, 24 Jan 2019 13:48:59 -0600 Subject: [PATCH 08/42] Added some debug info, added whitespce to part of the cloud code for easier visibility, ive tried several things to fix this (, changng render que, base don cloud, etc,all of that, and it has had no effect, phosphate is still not showing up. aded more debug info, uncovered pretty bad JSON bug i need to fix, where everything we grab from there is in alphabetical order, but other places we load them are not, which causes values to mismatch, this could be th cause of numerous bugs, eg biome background bug may end up having to do with it aswell as the phosphate not spawning bug also is confirmed to have to do with it (though with this change it spawns properly just with the wrong color) removed redundant check, made the for loops use the value i defined earlier. added more null compound checks taht were missing and got rid of a redundant check, im locking this code down heh :P simplified compoundCount code, undid silly change i made earlier, added default color, made vector4's in color for clouds properly use floats, removed annoyting log when you hit iron. added default color, made it bright white, mad eit not check if compounds wer enull before grabbing color , and now phosphate appears as the default color, so its color is not being assigned properly. removed "fake" compounds added back original code for pushing back teh clouds as hhenri ordered Did alot of things i didnt commit (and didnt save) because they didnt work (including changing the way it loads compounds), got rid of old DEBUG info we no longer need added new debug info, got rid of unused variable, removed default colors, sorry about the deleted spaces i think tehy just got deleted because i put something new there then deleted that, will fix. --- scripts/microbe_stage/biome.as | 3 +- scripts/microbe_stage/setup.as | 8 +- src/ThriveGame.cpp | 3 +- src/microbe_stage/compound_cloud_system.cpp | 174 ++++++++++---------- 4 files changed, 90 insertions(+), 98 deletions(-) diff --git a/scripts/microbe_stage/biome.as b/scripts/microbe_stage/biome.as index 2c57b47f0d6..2f3611cb64a 100644 --- a/scripts/microbe_stage/biome.as +++ b/scripts/microbe_stage/biome.as @@ -56,13 +56,12 @@ void setBiome(uint64 biomeId, CellStageWorld@ world){ LOG_INFO("Setting biome to: " + biomeId); // Getting the base biome to change to. currentBiome = biomeId; - auto biome = getCurrentBiome(); auto biomeCompounds = biome.getCompoundKeys(); LOG_INFO("biomeCompounds.length = " + biomeCompounds.length()); for(uint i = 0; i < biomeCompounds.length(); ++i){ - auto compoundId = biomeCompounds[i]; + auto compoundId = SimulationParameters::compoundRegistry().getTypeData(biomeCompounds[i]).id; if(SimulationParameters::compoundRegistry().getTypeData(compoundId).isCloud){ diff --git a/scripts/microbe_stage/setup.as b/scripts/microbe_stage/setup.as index b7f35fdd6ee..b7a6b993180 100644 --- a/scripts/microbe_stage/setup.as +++ b/scripts/microbe_stage/setup.as @@ -293,7 +293,7 @@ void cellHitFloatingOrganelle(GameWorld@ world, ObjectID firstEntity, ObjectID s world.QueueDestroyEntity(floatingEntity); } -// TODO: also put these physics callback somewhere more sensible (maybe physics_callbacks.as?) + void cellHitIron(GameWorld@ world, ObjectID firstEntity, ObjectID secondEntity) { // Determine which is the iron @@ -310,12 +310,6 @@ void cellHitIron(GameWorld@ world, ObjectID firstEntity, ObjectID secondEntity) floatingEntity = secondEntity; cellEntity = firstEntity; } - - // TODO: use this to detect stuff - LOG_INFO("Model: " + model.GraphicalObject.getMesh().getName()); - LOG_INFO("TODO: organelle unlock progress if cell: " + cellEntity + " is the player"); - - //world.QueueDestroyEntity(floatingEntity); } // Cell Hit Oxytoxy diff --git a/src/ThriveGame.cpp b/src/ThriveGame.cpp index 140dd11f36f..a72302ccc89 100644 --- a/src/ThriveGame.cpp +++ b/src/ThriveGame.cpp @@ -304,10 +304,9 @@ void // This is needed for the compound clouds to work in general const auto compoundCount = SimulationParameters::compoundRegistry.getSize(); + LEVIATHAN_ASSERT(SimulationParameters::compoundRegistry.getSize() > 0, "compound registry is empty when creating cloud entities for them"); - std::unordered_map u = - {}; std::vector clouds; diff --git a/src/microbe_stage/compound_cloud_system.cpp b/src/microbe_stage/compound_cloud_system.cpp index 2162a272cab..a04e48073a8 100644 --- a/src/microbe_stage/compound_cloud_system.cpp +++ b/src/microbe_stage/compound_cloud_system.cpp @@ -42,38 +42,37 @@ CompoundCloudComponent::CompoundCloudComponent(CompoundCloudSystem& owner, m_textureName("cloud_" + std::to_string(++CloudTextureNumber)), m_owner(owner) { + LOG_INFO("got here"); if(!first) throw std::runtime_error( "CompoundCloudComponent needs at least one Compound type"); // Read data - // Redundant check (see the throw above) - if(first) { - - m_compoundId1 = first->id; - m_color1 = - Ogre::Vector4(first->colour.r, first->colour.g, first->colour.b, 1); - } + m_color1 = + Ogre::Vector4(first->colour.r, first->colour.g, first->colour.b, 1.0f); + m_compoundId1 = first->id; + LOG_INFO("cloud colors are " + std::to_string(first->colour.r)); + LOG_INFO("cloud first compound ID is " + std::to_string(m_compoundId1)); if(second) { m_compoundId2 = second->id; m_color2 = Ogre::Vector4( - second->colour.r, second->colour.g, second->colour.b, 1); + second->colour.r, second->colour.g, second->colour.b, 1.0f); } if(third) { m_compoundId3 = third->id; - m_color3 = - Ogre::Vector4(third->colour.r, third->colour.g, third->colour.b, 1); + m_color3 = Ogre::Vector4( + third->colour.r, third->colour.g, third->colour.b, 1.0f); } if(fourth) { m_compoundId4 = fourth->id; m_color4 = Ogre::Vector4( - fourth->colour.r, fourth->colour.g, fourth->colour.b, 1); + fourth->colour.r, fourth->colour.g, fourth->colour.b, 1.0f); } } @@ -160,12 +159,13 @@ void if(x >= m_density1.size() || y >= m_density1[0].size()) throw std::runtime_error( "CompoundCloudComponent coordinates out of range"); - - switch(getSlotForCompound(compound)) { - case SLOT::FIRST: m_density1[x][y] += dens; break; - case SLOT::SECOND: m_density2[x][y] += dens; break; - case SLOT::THIRD: m_density3[x][y] += dens; break; - case SLOT::FOURTH: m_density4[x][y] += dens; break; + if(compound != NULL_COMPOUND) { + switch(getSlotForCompound(compound)) { + case SLOT::FIRST: m_density1[x][y] += dens; break; + case SLOT::SECOND: m_density2[x][y] += dens; break; + case SLOT::THIRD: m_density3[x][y] += dens; break; + case SLOT::FOURTH: m_density4[x][y] += dens; break; + } } } @@ -175,39 +175,41 @@ int size_t y, float rate) { - switch(getSlotForCompound(compound)) { - case SLOT::FIRST: { - int amountToGive = static_cast(m_density1[x][y] * rate); - m_density1[x][y] -= amountToGive; - if(m_density1[x][y] < 1) - m_density1[x][y] = 0; - - return amountToGive; - } - case SLOT::SECOND: { - int amountToGive = static_cast(m_density2[x][y] * rate); - m_density2[x][y] -= amountToGive; - if(m_density2[x][y] < 1) - m_density2[x][y] = 0; + if(compound != NULL_COMPOUND) { + switch(getSlotForCompound(compound)) { + case SLOT::FIRST: { + int amountToGive = static_cast(m_density1[x][y] * rate); + m_density1[x][y] -= amountToGive; + if(m_density1[x][y] < 1) + m_density1[x][y] = 0; - return amountToGive; - } - case SLOT::THIRD: { - int amountToGive = static_cast(m_density3[x][y] * rate); - m_density3[x][y] -= amountToGive; - if(m_density3[x][y] < 1) - m_density3[x][y] = 0; + return amountToGive; + } + case SLOT::SECOND: { + int amountToGive = static_cast(m_density2[x][y] * rate); + m_density2[x][y] -= amountToGive; + if(m_density2[x][y] < 1) + m_density2[x][y] = 0; - return amountToGive; - } - case SLOT::FOURTH: { - int amountToGive = static_cast(m_density4[x][y] * rate); - m_density4[x][y] -= amountToGive; - if(m_density4[x][y] < 1) - m_density4[x][y] = 0; + return amountToGive; + } + case SLOT::THIRD: { + int amountToGive = static_cast(m_density3[x][y] * rate); + m_density3[x][y] -= amountToGive; + if(m_density3[x][y] < 1) + m_density3[x][y] = 0; - return amountToGive; - } + return amountToGive; + } + case SLOT::FOURTH: { + int amountToGive = static_cast(m_density4[x][y] * rate); + m_density4[x][y] -= amountToGive; + if(m_density4[x][y] < 1) + m_density4[x][y] = 0; + + return amountToGive; + } + } } LEVIATHAN_ASSERT(false, "Shouldn't get here"); @@ -220,25 +222,26 @@ int size_t y, float rate) { - switch(getSlotForCompound(compound)) { - case SLOT::FIRST: { - int amountToGive = static_cast(m_density1[x][y] * rate); - return amountToGive; - } - case SLOT::SECOND: { - int amountToGive = static_cast(m_density2[x][y] * rate); - return amountToGive; - } - case SLOT::THIRD: { - int amountToGive = static_cast(m_density3[x][y] * rate); - return amountToGive; - } - case SLOT::FOURTH: { - int amountToGive = static_cast(m_density4[x][y] * rate); - return amountToGive; - } + if(compound != NULL_COMPOUND) { + switch(getSlotForCompound(compound)) { + case SLOT::FIRST: { + int amountToGive = static_cast(m_density1[x][y] * rate); + return amountToGive; + } + case SLOT::SECOND: { + int amountToGive = static_cast(m_density2[x][y] * rate); + return amountToGive; + } + case SLOT::THIRD: { + int amountToGive = static_cast(m_density3[x][y] * rate); + return amountToGive; + } + case SLOT::FOURTH: { + int amountToGive = static_cast(m_density4[x][y] * rate); + return amountToGive; + } + } } - LEVIATHAN_ASSERT(false, "Shouldn't get here"); return -1; } @@ -285,13 +288,13 @@ void // Clear data. Maybe there is a faster way if(m_compoundId1 != NULL_COMPOUND) { - for(size_t x = 0; x < m_density1.size(); ++x) { - for(size_t y = 0; y < m_density1[x].size(); ++y) { + for(size_t x = 0; x < m_density1.size(); ++x) { + for(size_t y = 0; y < m_density1[x].size(); ++y) { m_density1[x][y] = 0; m_oldDens1[x][y] = 0; } - } - } + } + } if(m_compoundId2 != NULL_COMPOUND) { for(size_t x = 0; x < m_density2.size(); ++x) { @@ -687,7 +690,7 @@ void LOG_INFO("CompoundCloudSystem doing initial spawning"); m_cloudGridCenter = Float3(0, 0, 0); - for(size_t i = 0; i < m_cloudTypes.size(); i += CLOUDS_IN_ONE) { + for(size_t i = 0; i < cloudTypesNum; i += CLOUDS_IN_ONE) { // Center _spawnCloud(world, m_cloudGridCenter, i); @@ -843,7 +846,7 @@ void size_t farAwayRepositionedIndex = 0; // Loop through the cloud groups - for(size_t c = 0; c < m_cloudTypes.size(); c += CLOUDS_IN_ONE) { + for(size_t c = 0; c < cloudTypesNum; c += CLOUDS_IN_ONE) { // Loop for moving clouds for(size_t i = 0; i < std::size(requiredCloudPositions); ++i) { bool hasCloud = false; @@ -856,7 +859,6 @@ void if(((pos - requiredPos).HAddAbs() < Leviathan::EPSILON) && (m_cloudTypes[c].id == iter->second->getCompoundId1())) { - LOG_INFO("Clouds were at same position"); hasCloud = true; break; } @@ -888,26 +890,26 @@ void size_t startIndex) { auto entity = world.CreateEntity(); - Compound* first = startIndex < m_cloudTypes.size() ? &m_cloudTypes[startIndex] : nullptr; + Compound* second = startIndex + 1 < m_cloudTypes.size() ? &m_cloudTypes[startIndex + 1] : nullptr; + Compound* third = startIndex + 2 < m_cloudTypes.size() ? &m_cloudTypes[startIndex + 2] : nullptr; + Compound* fourth = startIndex + 3 < m_cloudTypes.size() ? &m_cloudTypes[startIndex + 3] : nullptr; - CompoundCloudComponent& cloud = world.Create_CompoundCloudComponent( entity, *this, first, second, third, fourth); // Set correct position // TODO: this should probably be made a constructor parameter cloud.m_position = pos; - initializeCloud(cloud, world.GetScene()); m_managedClouds[entity] = &cloud; } @@ -917,6 +919,8 @@ void CompoundCloudSystem::initializeCloud(CompoundCloudComponent& cloud, Ogre::SceneManager* scene) { + LOG_INFO( + "cloud first compound ID is " + std::to_string(cloud.m_compoundId1)); LOG_INFO("Initializing a new compound cloud entity"); // All the densities @@ -993,18 +997,14 @@ void pass->setFragmentProgram("CompoundCloud_PS"); // Set colour parameter // - if(cloud.m_compoundId1 != NULL_COMPOUND) - pass->getFragmentProgramParameters()->setNamedConstant( - "cloudColour1", cloud.m_color1); - if(cloud.m_compoundId2 != NULL_COMPOUND) - pass->getFragmentProgramParameters()->setNamedConstant( - "cloudColour2", cloud.m_color2); - if(cloud.m_compoundId3 != NULL_COMPOUND) - pass->getFragmentProgramParameters()->setNamedConstant( - "cloudColour3", cloud.m_color3); - if(cloud.m_compoundId4 != NULL_COMPOUND) - pass->getFragmentProgramParameters()->setNamedConstant( - "cloudColour4", cloud.m_color4); + pass->getFragmentProgramParameters()->setNamedConstant( + "cloudColour1", cloud.m_color1); + pass->getFragmentProgramParameters()->setNamedConstant( + "cloudColour2", cloud.m_color2); + pass->getFragmentProgramParameters()->setNamedConstant( + "cloudColour3", cloud.m_color3); + pass->getFragmentProgramParameters()->setNamedConstant( + "cloudColour4", cloud.m_color4); // The perlin noise texture needs to be tileable. We can't do tricks with // the cloud's position From 46d9232e1a84ae7994dbe4b1d0e62a4bad75b7b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henri=20Hyyryl=C3=A4inen?= Date: Sat, 26 Jan 2019 15:24:27 +0200 Subject: [PATCH 09/42] Wrote tests for initial cloud positioning by the cloud manager Includes a lot of supporting changes. Also did some changes unrelated to the tests to the cloud code, like undoing the variable I didn't like. Contains a few changes that I started to make to the cloud positioning, but I'll probably undo later. --- SetupThrive.rb | 2 +- src/ThriveGame.cpp | 25 ++- src/ThriveGame.h | 8 + src/general/json_registry.h | 7 + src/microbe_stage/compound_cloud_system.cpp | 126 ++++--------- src/microbe_stage/compound_cloud_system.h | 39 ++++ src/microbe_stage/compounds.cpp | 11 ++ src/microbe_stage/compounds.h | 8 + src/microbe_stage/player_microbe_control.cpp | 14 +- test/CMakeLists.txt | 2 + test/engine.cpp | 19 -- test/entity.cpp | 70 -------- test/entity_filter.cpp | 171 ------------------ test/rng.cpp | 75 -------- test/rolling_grid.cpp | 84 --------- test/script_bindings.cpp | 27 --- test/sky_system.cpp | 32 ---- test/test_clouds.cpp | 180 +++++++++++++++++++ test/test_component.h | 45 ----- test/test_thrive_game.h | 33 ++++ 20 files changed, 357 insertions(+), 621 deletions(-) delete mode 100644 test/engine.cpp delete mode 100644 test/entity.cpp delete mode 100644 test/entity_filter.cpp delete mode 100644 test/rng.cpp delete mode 100644 test/rolling_grid.cpp delete mode 100644 test/script_bindings.cpp delete mode 100644 test/sky_system.cpp delete mode 100644 test/test_component.h create mode 100644 test/test_thrive_game.h diff --git a/SetupThrive.rb b/SetupThrive.rb index f3cafa50d59..23a602a6d11 100755 --- a/SetupThrive.rb +++ b/SetupThrive.rb @@ -78,7 +78,7 @@ def parseExtraArgs leviathan = Leviathan.new( # Use this if you always want the latest commit # version: "develop", - version: "556a6584f4f74d2c16d85b85ba26281a88c02171", + version: "ebaf03d6086c5cac39b66a54093e3926e1c0c359", # Doesn't actually work, but leviathan doesn't install with sudo by # default, or install at all for that matter noInstallSudo: true diff --git a/src/ThriveGame.cpp b/src/ThriveGame.cpp index a72302ccc89..8616c61eafd 100644 --- a/src/ThriveGame.cpp +++ b/src/ThriveGame.cpp @@ -246,6 +246,10 @@ void netSettings.IsAuthoritative = true; netSettings.DoInterpolation = true; + // TODO: switch to + // Leviathan::WorldNetworkSettings::GetSettingsForSinglePlayer() once we + // no longer do the interpolation once variable rate ticks are supported + LOG_INFO("ThriveGame: startNewGame: Creating new cellstage world"); m_impl->m_cellStage = std::dynamic_pointer_cast(engine->CreateWorld( @@ -494,7 +498,8 @@ void m_impl->m_microbeEditor = std::dynamic_pointer_cast(engine->CreateWorld( window1, static_cast(THRIVE_WORLD_TYPE::MICROBE_EDITOR), - createPhysicsMaterials(), netSettings)); + createPhysicsMaterials(), + Leviathan::WorldNetworkSettings::GetSettingsForSinglePlayer())); } LEVIATHAN_ASSERT( @@ -984,17 +989,27 @@ void ThriveGame::Tick(int mspassed) {} -void - ThriveGame::CustomizeEnginePostLoad() +bool + ThriveGame::createImpl() { - Engine* engine = Engine::Get(); - try { m_impl = std::make_unique(*this); } catch(const Leviathan::InvalidArgument& e) { LOG_ERROR("ThriveGame: loading configuration data failed: "); e.PrintToLog(); + return false; + } + + return true; +} + +void + ThriveGame::CustomizeEnginePostLoad() +{ + Engine* engine = Engine::Get(); + + if(!createImpl()) { MarkAsClosing(); return; } diff --git a/src/ThriveGame.h b/src/ThriveGame.h index 8b0c26b2b52..f0ff6c49037 100644 --- a/src/ThriveGame.h +++ b/src/ThriveGame.h @@ -13,6 +13,10 @@ namespace thrive { +namespace test { +class TestThriveGame; +} + class CellStageWorld; class ThriveNetHandler; @@ -25,6 +29,7 @@ class PlayerMicrobeControl; //! running the engine and the event loop class ThriveGame : public Leviathan::ClientApplication, public ThriveCommon { class Implementation; + friend test::TestThriveGame; public: ThriveGame(); @@ -150,6 +155,9 @@ class ThriveGame : public Leviathan::ClientApplication, public ThriveCommon { void _ShutdownApplicationPacketHandler() override; + bool + createImpl(); + private: std::unique_ptr m_network; diff --git a/src/general/json_registry.h b/src/general/json_registry.h index 877fc5b89e8..ea18d13f97f 100644 --- a/src/general/json_registry.h +++ b/src/general/json_registry.h @@ -17,6 +17,13 @@ // Base class of things to register. class RegistryType { public: + RegistryType() {} + + //! \brief Helper for derived test constructors + RegistryType(size_t id, const std::string& name) : + id(id), displayName(name), internalName(name) + {} + // Used to search by id. size_t id = std::numeric_limits::max(); // This would mean an error. diff --git a/src/microbe_stage/compound_cloud_system.cpp b/src/microbe_stage/compound_cloud_system.cpp index a04e48073a8..1ca41d25519 100644 --- a/src/microbe_stage/compound_cloud_system.cpp +++ b/src/microbe_stage/compound_cloud_system.cpp @@ -350,6 +350,11 @@ void const auto meshName = "CompoundCloudSystem_Plane_" + std::to_string(++CloudMeshNumberCounter); + // TODO: fix this in the engine to make this method simpler + // This crashes when used with RenderDoc and doesn't render anything + // m_planeMesh = Leviathan::GeometryHelpers::CreateXZPlane( + // meshName, CLOUD_WIDTH, CLOUD_HEIGHT); + // Create a background plane on which the fluid clouds will be drawn. m_planeMesh = Ogre::MeshManager::getSingleton().createManual( meshName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); @@ -683,65 +688,29 @@ void const Float3& playerPos) { // Initial spawning if everything is empty - int cloudTypesNum = m_cloudTypes.size(); - if(m_managedClouds.empty()) { LOG_INFO("CompoundCloudSystem doing initial spawning"); m_cloudGridCenter = Float3(0, 0, 0); - for(size_t i = 0; i < cloudTypesNum; i += CLOUDS_IN_ONE) { - - // Center - _spawnCloud(world, m_cloudGridCenter, i); - - // Top left - _spawnCloud(world, - m_cloudGridCenter + - Float3(-CLOUD_WIDTH * 2, 0, -CLOUD_HEIGHT * 2), - i); - - // Up - _spawnCloud( - world, m_cloudGridCenter + Float3(0, 0, -CLOUD_HEIGHT * 2), i); - - // Top right - _spawnCloud(world, - m_cloudGridCenter + - Float3(CLOUD_WIDTH * 2, 0, -CLOUD_HEIGHT * 2), - i); - - // Left - _spawnCloud( - world, m_cloudGridCenter + Float3(-CLOUD_WIDTH * 2, 0, 0), i); - - // Right - _spawnCloud( - world, m_cloudGridCenter + Float3(CLOUD_WIDTH * 2, 0, 0), i); - - // Bottom left - _spawnCloud(world, - m_cloudGridCenter + - Float3(-CLOUD_WIDTH * 2, 0, CLOUD_HEIGHT * 2), - i); - - // Down - _spawnCloud( - world, m_cloudGridCenter + Float3(0, 0, CLOUD_HEIGHT * 2), i); - - // Bottom right - _spawnCloud(world, - m_cloudGridCenter + - Float3(CLOUD_WIDTH * 2, 0, CLOUD_HEIGHT * 2), - i); + + const auto requiredCloudPositions{ + calculateGridPositions(m_cloudGridCenter)}; + + for(size_t i = 0; i < m_cloudTypes.size(); i += CLOUDS_IN_ONE) { + + // All positions + for(const auto& pos : requiredCloudPositions) { + _spawnCloud(world, pos, i); + } } } // This rounds up to the nearest multiple of 4, // divides that by 4 and multiplies by 9 to get all the clouds we have // (if we have 5 compounds that are clouds, we need 18 clouds, if 4 we need // 9 etc) - LEVIATHAN_ASSERT( - m_managedClouds.size() == ((((cloudTypesNum + 4 - 1) / 4 * 4) / 4) * 9), + LEVIATHAN_ASSERT(m_managedClouds.size() == + ((((m_cloudTypes.size() + 4 - 1) / 4 * 4) / 4) * 9), "A CompoundCloud entity has mysteriously been destroyed"); const auto moved = playerPos - m_cloudGridCenter; @@ -767,42 +736,18 @@ void } // Calculate the new positions - const Float3 requiredCloudPositions[] = { - // Center - m_cloudGridCenter, - - // Top left - m_cloudGridCenter + Float3(-CLOUD_WIDTH * 2, 0, -CLOUD_HEIGHT * 2), - - // Up - m_cloudGridCenter + Float3(0, 0, -CLOUD_HEIGHT * 2), - - // Top right - m_cloudGridCenter + Float3(CLOUD_WIDTH * 2, 0, -CLOUD_HEIGHT * 2), - - // Left - m_cloudGridCenter + Float3(-CLOUD_WIDTH * 2, 0, 0), - - // Right - m_cloudGridCenter + Float3(CLOUD_WIDTH * 2, 0, 0), - - // Bottom left - m_cloudGridCenter + Float3(-CLOUD_WIDTH * 2, 0, CLOUD_HEIGHT * 2), - - // Down - m_cloudGridCenter + Float3(0, 0, CLOUD_HEIGHT * 2), - - // Bottom right - m_cloudGridCenter + Float3(CLOUD_WIDTH * 2, 0, CLOUD_HEIGHT * 2), - }; + const auto requiredCloudPositions{ + calculateGridPositions(m_cloudGridCenter)}; + // Reposition clouds according to the origin + // The max amount of clouds is that all need to be moved + const size_t MAX_FAR_CLOUDS = m_managedClouds.size(); + // According to spec this check is superfluous, but it makes me feel + // better + if(m_tooFarAwayClouds.size() != MAX_FAR_CLOUDS) + m_tooFarAwayClouds.resize(MAX_FAR_CLOUDS); - // Reposition clouds according to the origin - // MAX of our cloud compounds is nearest multiple of 4 , divided by 4 - // and multiplied by 9 This case only happens when you respawn. - constexpr size_t MAX_FAR_CLOUDS = 18; - std::array tooFarAwayClouds; size_t farAwayIndex = 0; // All clouds that aren't at one of the requiredCloudPositions needs to @@ -822,6 +767,7 @@ void // An exact check might work but just to be safe slight // inaccuracy is allowed here if((pos - requiredPos).HAddAbs() < Leviathan::EPSILON) { + matched = true; break; } @@ -836,7 +782,7 @@ void break; } - tooFarAwayClouds[farAwayIndex++] = iter->second; + m_tooFarAwayClouds[farAwayIndex++] = iter->second; } } @@ -846,8 +792,8 @@ void size_t farAwayRepositionedIndex = 0; // Loop through the cloud groups - for(size_t c = 0; c < cloudTypesNum; c += CLOUDS_IN_ONE) { - // Loop for moving clouds + for(size_t c = 0; c < m_cloudTypes.size(); c += CLOUDS_IN_ONE) { + // Loop for moving clouds to all needed positions for each group for(size_t i = 0; i < std::size(requiredCloudPositions); ++i) { bool hasCloud = false; const auto& requiredPos = requiredCloudPositions[i]; @@ -877,8 +823,8 @@ void break; } - tooFarAwayClouds[farAwayRepositionedIndex++]->recycleToPosition( - requiredPos); + m_tooFarAwayClouds[farAwayRepositionedIndex++] + ->recycleToPosition(requiredPos); } } } @@ -906,12 +852,13 @@ void nullptr; CompoundCloudComponent& cloud = world.Create_CompoundCloudComponent( entity, *this, first, second, third, fourth); + m_managedClouds[entity] = &cloud; // Set correct position // TODO: this should probably be made a constructor parameter cloud.m_position = pos; + initializeCloud(cloud, world.GetScene()); - m_managedClouds[entity] = &cloud; } @@ -1041,7 +988,6 @@ void auto* densityState = pass->createTextureUnitState(); densityState->setTexture(cloud.m_texture); - // densityState->setTextureName("TestImageThing.png"); densityState->setSamplerblock(wrappedBlock); Ogre::TexturePtr texturePtr = @@ -1052,8 +998,8 @@ void noiseState->setSamplerblock(wrappedBlock); - // Maybe compiling this here is the best place - cloud.m_planeMaterial->compile(); + // // Maybe compiling this here is the best place + // cloud.m_planeMaterial->compile(); // Needs to create a plane instance on which the material is used on cloud.m_compoundCloudsPlane = scene->createItem(m_planeMesh); diff --git a/src/microbe_stage/compound_cloud_system.h b/src/microbe_stage/compound_cloud_system.h index ae94e5c681a..3e7a550e557 100644 --- a/src/microbe_stage/compound_cloud_system.h +++ b/src/microbe_stage/compound_cloud_system.h @@ -331,6 +331,9 @@ class CompoundCloudComponent : public Leviathan::Component { //! \todo This can be removed once there is a proper clear method available //! for systems to detect CompoundCloudSystem& m_owner; + + // //! A helper value to handle cloud repositioning + // bool m_repositioned = false; }; @@ -443,6 +446,39 @@ class CompoundCloudSystem { convertWorldToCloudLocalForGrab(const Float3& cloudPosition, const Float3& worldPosition); + static inline auto + calculateGridPositions(const Float3& center) + { + return std::array{ + // Center + center, + + // Top left + center + Float3(-CLOUD_WIDTH * 2, 0, -CLOUD_HEIGHT * 2), + + // Up + center + Float3(0, 0, -CLOUD_HEIGHT * 2), + + // Top right + center + Float3(CLOUD_WIDTH * 2, 0, -CLOUD_HEIGHT * 2), + + // Left + center + Float3(-CLOUD_WIDTH * 2, 0, 0), + + // Right + center + Float3(CLOUD_WIDTH * 2, 0, 0), + + // Bottom left + center + Float3(-CLOUD_WIDTH * 2, 0, CLOUD_HEIGHT * 2), + + // Down + center + Float3(0, 0, CLOUD_HEIGHT * 2), + + // Bottom right + center + Float3(CLOUD_WIDTH * 2, 0, CLOUD_HEIGHT * 2), + }; + } + protected: //! \brief Removes deleted clouds from m_managedClouds void @@ -514,6 +550,9 @@ class CompoundCloudSystem { //! the best way to simulate fluid velocity std::vector> m_xVelocity; std::vector> m_yVelocity; + + //! This is here to not have to allocate memory every tick + std::vector m_tooFarAwayClouds; }; } // namespace thrive diff --git a/src/microbe_stage/compounds.cpp b/src/microbe_stage/compounds.cpp index 4a8189b0cfc..573ed878eb1 100644 --- a/src/microbe_stage/compounds.cpp +++ b/src/microbe_stage/compounds.cpp @@ -5,6 +5,17 @@ using namespace thrive; Compound::Compound() {} +Compound::Compound(size_t id, + const std::string& name, + bool isCloud, + bool isUseful, + bool isEnvironmental, + Ogre::ColourValue colour) : + RegistryType(id, name), + isCloud(isCloud), isUseful(isUseful), isEnvironmental(isEnvironmental), + colour(colour) +{} + Compound::Compound(Json::Value value) { volume = value["volume"].asDouble(); diff --git a/src/microbe_stage/compounds.h b/src/microbe_stage/compounds.h index 2e2c83eff4f..a2f92150dfc 100644 --- a/src/microbe_stage/compounds.h +++ b/src/microbe_stage/compounds.h @@ -16,6 +16,14 @@ class Compound : public RegistryType { Compound(); + //! \brief Constructor for test use + Compound(size_t id, + const std::string& name, + bool isCloud, + bool isUseful, + bool isEnvironmental, + Ogre::ColourValue colour); + Compound(Json::Value value); }; diff --git a/src/microbe_stage/player_microbe_control.cpp b/src/microbe_stage/player_microbe_control.cpp index 9db2102803f..73e1be6e43b 100644 --- a/src/microbe_stage/player_microbe_control.cpp +++ b/src/microbe_stage/player_microbe_control.cpp @@ -256,8 +256,14 @@ void auto module = thrive->getMicrobeScripts(); - if(!module) - LOG_FATAL("PlayerMicrobeControlSystem: microbe scripts aren't loaded"); + if(!module) { + // Skip here to allow running better in unit tests + // This makes finding errors about this a bit more difficult but the + // game shouldn't start with invalid scripts + // LOG_FATAL("PlayerMicrobeControlSystem: microbe scripts aren't + // loaded"); + return; + } // Debug for movement keys // std::stringstream msg; @@ -319,6 +325,10 @@ Float3 PlayerMicrobeControlSystem::getTargetPoint( Leviathan::GameWorld& worldWithCamera) { + // Skip when there is no window to allow running headless + if(!Engine::Get()->GetWindowEntity()) + return Float3(0, 0, 0); + float x, y; Engine::Get()->GetWindowEntity()->GetNormalizedRelativeMouse(x, y); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index deeaa041d46..528a7655048 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -8,6 +8,8 @@ include_directories("${LEVIATHAN_SRC}") set(CurrentProjectName ThriveTest) set(AllProjectFiles "test_main.cpp" + "test_thrive_game.h" + "test_script_compile.cpp" "test_simulation_parameters.cpp" "test_clouds.cpp" diff --git a/test/engine.cpp b/test/engine.cpp deleted file mode 100644 index b54e088f359..00000000000 --- a/test/engine.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "engine/engine.h" - -#include "engine/entity_manager.h" -#include "engine/tests/test_component.h" -#include "util/make_unique.h" - -#include -#include - -using namespace thrive; - -namespace { - -class TestEngine : public Engine { -public: - TestEngine(EntityManager& entityManager) : Engine(entityManager) {} -}; - -} // namespace diff --git a/test/entity.cpp b/test/entity.cpp deleted file mode 100644 index 1b9df70bc15..00000000000 --- a/test/entity.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "engine/entity.h" - -#include "engine/engine.h" -#include "engine/entity_manager.h" -#include "engine/game_state.h" -#include "engine/system.h" -#include "engine/tests/test_component.h" -#include "util/make_unique.h" - -#include - - -using namespace thrive; - -// TODO: this needs to be basically rewritten in Lua - -// struct EntityTest : public ::testing::Test { - -// EntityTest() -// : gameState(engine.createGameState("test", {}, -// GameState::Initializer(), "DragDropDemo")) -// { - -// } - -// Engine engine; - -// GameState* gameState = nullptr; - -// }; - -// TEST_F(EntityTest, Exists) { -// // Null Id should never exist -// Entity nullEntity(NULL_ENTITY, gameState); -// EXPECT_FALSE(nullEntity.exists()); -// // Entity without components doesn't exist either -// Entity entity(gameState); -// EXPECT_FALSE(entity.exists()); -// // Add some component, then it should exist -// entity.addComponent(make_unique>()); -// EXPECT_TRUE(entity.exists()); -// } - - -// TEST_F(EntityTest, HasComponent) { -// Entity entity(gameState); -// EXPECT_FALSE(entity.hasComponent(TestComponent<0>::TYPE_ID)); -// entity.addComponent(make_unique>()); -// EXPECT_TRUE(entity.hasComponent(TestComponent<0>::TYPE_ID)); -// } - - -// TEST_F(EntityTest, RemoveComponent) { -// Entity entity(gameState); -// EXPECT_FALSE(entity.hasComponent(TestComponent<0>::TYPE_ID)); -// entity.addComponent(make_unique>()); -// EXPECT_TRUE(entity.hasComponent(TestComponent<0>::TYPE_ID)); -// entity.removeComponent(TestComponent<0>::TYPE_ID); -// gameState->entityManager().processRemovals(); -// EXPECT_FALSE(entity.hasComponent(TestComponent<0>::TYPE_ID)); -// } - - -// TEST_F(EntityTest, NamedEntity) { -// Entity unnamed(gameState); -// Entity named("named", gameState); -// Entity namedCopy("named", gameState); -// EXPECT_FALSE(named == unnamed); -// EXPECT_TRUE(named == namedCopy); -// } diff --git a/test/entity_filter.cpp b/test/entity_filter.cpp deleted file mode 100644 index 5142fbfda56..00000000000 --- a/test/entity_filter.cpp +++ /dev/null @@ -1,171 +0,0 @@ -#include "engine/entity_filter.h" - -#include "engine/entity_manager.h" -#include "engine/tests/test_component.h" -#include "util/make_unique.h" - -#include - -using namespace thrive; - -TEST(EntityFilter, Initialization) -{ - EntityManager entityManager; - // Add component - EntityId entityId = entityManager.generateNewId(); - entityManager.addComponent(entityId, make_unique>()); - EXPECT_TRUE(nullptr != entityManager.getComponent( - entityId, TestComponent<0>::TYPE_ID)); - // Set up filter - EntityFilter> filter; - filter.setEntityManager(&entityManager); - // Check filter - auto filteredEntities = filter.entities(); - EXPECT_EQ(1, filteredEntities.count(entityId)); - EXPECT_EQ(1, filteredEntities.size()); -} - -TEST(EntityFilter, Single) -{ - EntityManager entityManager; - // Set up filter - EntityFilter> filter; - filter.setEntityManager(&entityManager); - // Add component - EntityId entityId = entityManager.generateNewId(); - entityManager.addComponent(entityId, make_unique>()); - // Check filter - auto filteredEntities = filter.entities(); - EXPECT_EQ(1, filteredEntities.count(entityId)); - EXPECT_EQ(1, filteredEntities.size()); - // Remove component - entityManager.removeComponent(entityId, TestComponent<0>::TYPE_ID); - entityManager.processRemovals(); - // Check filter - filteredEntities = filter.entities(); - EXPECT_EQ(0, filteredEntities.count(entityId)); - EXPECT_EQ(0, filteredEntities.size()); -} - - -TEST(EntityFilter, Multiple) -{ - EntityManager entityManager; - // Set up filter - EntityFilter, TestComponent<1>> filter; - filter.setEntityManager(&entityManager); - auto filteredEntities = filter.entities(); - // Add first component - EntityId entityId = entityManager.generateNewId(); - entityManager.addComponent(entityId, make_unique>()); - // Check filter - filteredEntities = filter.entities(); - // Add first component - EXPECT_EQ(0, filteredEntities.count(entityId)); - EXPECT_EQ(0, filteredEntities.size()); - // Add second component - entityManager.addComponent(entityId, make_unique>()); - // Check filter - filteredEntities = filter.entities(); - EXPECT_EQ(1, filteredEntities.count(entityId)); - EXPECT_EQ(1, filteredEntities.size()); - // Remove component - entityManager.removeComponent(entityId, TestComponent<1>::TYPE_ID); - entityManager.processRemovals(); - // Check filter - filteredEntities = filter.entities(); - EXPECT_EQ(0, filteredEntities.count(entityId)); - EXPECT_EQ(0, filteredEntities.size()); -} - - -TEST(EntityFilter, Optional) -{ - EntityManager entityManager; - using TestFilter = - EntityFilter, Optional>>; - // Set up filter - TestFilter filter; - filter.setEntityManager(&entityManager); - TestFilter::EntityMap filteredEntities = filter.entities(); - // Add first component - EntityId entityId = entityManager.generateNewId(); - entityManager.addComponent(entityId, make_unique>()); - // Check filter - filteredEntities = filter.entities(); - EXPECT_EQ(1, filteredEntities.count(entityId)); - EXPECT_EQ(1, filteredEntities.size()); - // Check group - TestFilter::ComponentGroup group = filteredEntities[entityId]; - EXPECT_TRUE(std::get<0>(group) != nullptr); - EXPECT_TRUE(std::get<1>(group) == nullptr); - // Add second component - entityManager.addComponent(entityId, make_unique>()); - // Check filter - filteredEntities = filter.entities(); - EXPECT_EQ(1, filteredEntities.count(entityId)); - EXPECT_EQ(1, filteredEntities.size()); - // Check group - group = filteredEntities[entityId]; - EXPECT_TRUE(std::get<0>(group) != nullptr); - EXPECT_TRUE(std::get<1>(group) != nullptr); - // Remove component - entityManager.removeComponent(entityId, TestComponent<1>::TYPE_ID); - entityManager.processRemovals(); - // Check filter - filteredEntities = filter.entities(); - EXPECT_EQ(1, filteredEntities.count(entityId)); - EXPECT_EQ(1, filteredEntities.size()); - // Check group - group = filteredEntities[entityId]; - EXPECT_TRUE(std::get<0>(group) != nullptr); -} - - -TEST(EntityFilter, OptionalOnly) -{ - EntityManager entityManager; - using TestFilter = EntityFilter>>; - // Set up filter - TestFilter filter; - filter.setEntityManager(&entityManager); - TestFilter::EntityMap filteredEntities = filter.entities(); - // Add first component - EntityId entityId = entityManager.generateNewId(); - entityManager.addComponent(entityId, make_unique>()); - // Check filter - filteredEntities = filter.entities(); - EXPECT_EQ(1, filteredEntities.count(entityId)); - EXPECT_EQ(1, filteredEntities.size()); - // Check group - TestFilter::ComponentGroup group = filteredEntities[entityId]; - EXPECT_TRUE(std::get<0>(group) != nullptr); - // Remove component - entityManager.removeComponent(entityId, TestComponent<0>::TYPE_ID); - entityManager.processRemovals(); - // Check filter - filteredEntities = filter.entities(); - EXPECT_EQ(0, filteredEntities.count(entityId)); - EXPECT_EQ(0, filteredEntities.size()); -} - - -TEST(EntityFilter, Record) -{ - EntityManager entityManager; - using TestFilter = EntityFilter>; - // Set up filter - TestFilter filter(true); - filter.setEntityManager(&entityManager); - TestFilter::EntityMap filteredEntities = filter.entities(); - // Add first component - EntityId entityId = entityManager.generateNewId(); - entityManager.addComponent(entityId, make_unique>()); - // Check added entities - EXPECT_EQ(1, filter.addedEntities().count(entityId)); - // Remove component - entityManager.removeComponent(entityId, TestComponent<0>::TYPE_ID); - entityManager.processRemovals(); - // Check removed entities - EXPECT_EQ(0, filter.removedEntities().count(entityId)); -} diff --git a/test/rng.cpp b/test/rng.cpp deleted file mode 100644 index bdfafb1ca4d..00000000000 --- a/test/rng.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "engine/rng.h" -#include "engine/tests/test_component.h" - -#include -#include -#include -#include - -#include - - -using namespace thrive; - - -TEST(RNG, getInt) -{ - RNG rng; - std::set rngIntValues; - // A series of random integers should not result in the same number - // repeatedly. (These test will unintentionally fail once every 1x10^200 - // times, feeling lucky?) - for(int i = 0; i < 100; ++i) - rngIntValues.insert(rng.getInt(1, 100)); - EXPECT_FALSE(rngIntValues.size() == 1); - // Random numbers produced must be in the provided range - EXPECT_TRUE((*rngIntValues.begin()) >= 1); - EXPECT_TRUE((*rngIntValues.end()) <= 100); -} - -TEST(RNG, getDouble) -{ - RNG rng; - // A series of random doubles should not result in the same number - // repeatedly. - std::set rngDoubleValues; - for(int i = 0; i < 100; ++i) - rngDoubleValues.insert(rng.getDouble(1.0, 100.0)); - EXPECT_FALSE(rngDoubleValues.size() == 1); - // Random numbers produced must be in the provided range - EXPECT_TRUE((*rngDoubleValues.begin()) >= 1.0); - EXPECT_TRUE((*rngDoubleValues.end()) <= 100.0); -} - -TEST(RNG, generateRandomSeed) -{ - RNG rng; - std::unordered_set rngSeedValues; - // A series of random seeds should not result in the same number repeatedly. - for(int i = 0; i < 100; ++i) - rngSeedValues.insert(rng.generateRandomSeed()); - EXPECT_FALSE(rngSeedValues.size() == 1); -} - -TEST(RNG, getSeed) -{ - RNG rng(1337); - EXPECT_EQ(1337, rng.getSeed()); -} - -TEST(RNG, setSeed) -{ - RNG rng(1337); - rng.setSeed(1234); - EXPECT_EQ(1234, rng.getSeed()); -} - -TEST(RNG, shuffle) -{ - RNG rng; - std::vector original{ - 5, 12, 16, 18, 19, 25, 33, 41, 53, 69, 71, 87, 90}; - std::vector shuffled(original); - rng.shuffle(shuffled.begin(), shuffled.end()); - EXPECT_TRUE(shuffled != original); -} diff --git a/test/rolling_grid.cpp b/test/rolling_grid.cpp deleted file mode 100644 index 9796f1a8ec4..00000000000 --- a/test/rolling_grid.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "engine/rolling_grid.h" -#include "gtest/gtest.h" - -using namespace thrive; - -TEST(RollingGrid, Initialization) -{ - RollingGrid grid(1920, 1080, 1); -} - -TEST(RollingGrid, Read) -{ - RollingGrid grid(1920, 1080, 1); - EXPECT_EQ(0, grid(0, 0)); // somewhere in-range - EXPECT_EQ(0, grid(15649, 986984)); // somewhere out-of-range -} - -TEST(RollingGrid, Edit) -{ - RollingGrid grid(1920, 1080, 1); - EXPECT_EQ(0, grid(20, 20)); - grid(20, 20) = 5; - // std::cout << "set (20,20) to 5" << std::endl; - EXPECT_EQ(5, grid(20, 20)); - // std::cout << "checked (20,20) == 5" << std::endl; - // make sure neighbors haven't been screwed with - for(int i = 18; i < 23; i++) { - for(int j = 18; j < 23; j++) { - if(i != 20 || j != 20) { - EXPECT_EQ(0, grid(i, j)); - } - } - } -} - -TEST(RollingGrid, SmallMove) -{ - RollingGrid grid(1920, 1080, 1); - grid(100, 100) = 1; - // std::cout << "set (100,100) to 1" << std::endl; - grid.move(1, 0); - // std::cout << "moved by (15, -12)" << std::endl; - EXPECT_EQ(1, grid(100, 100)); - // std::cout << "checked (100,100)" << std::endl; - EXPECT_EQ(0, grid(115, 88)); - EXPECT_EQ(0, grid(85, 112)); - for(int i = 0; i < 1920; i++) { - for(int j = 0; j < 1080; j++) { - int k = grid(i, j); - if(k) - std::cout << "(" << i << "," << j << ") = " << k << std::endl; - } - } -} - -TEST(RollingGrid, BigMove) -{ - RollingGrid grid(1920, 1080, 1); - grid(0, 0) = 1; - grid.move(71280, 90506); - EXPECT_EQ(0, grid(0, 0)); - grid(71281, 90507) = 1; - EXPECT_EQ(1, grid(71281, 90507)); -} - -TEST(RollingGrid, TinyGrid) -{ - RollingGrid grid(1, 2, 1); - grid(0, 0) = 1; - grid.move(0, -1); - EXPECT_EQ(1, grid(0, 0)); -} - -TEST(RollingGrid, NullMoves) -{ - RollingGrid grid(100, 200, 1); - grid(0, 0) = 1; - grid.move(0, 0); - EXPECT_EQ(1, grid(0, 0)); - - grid.move(0, -1); - grid.move(0, 1); - EXPECT_EQ(1, grid(0, 0)); -} diff --git a/test/script_bindings.cpp b/test/script_bindings.cpp deleted file mode 100644 index 800ebc7d925..00000000000 --- a/test/script_bindings.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "scripting/script_initializer.h" - -#include "scripting/luajit.h" - -#include -#include - -using namespace Ogre; -using namespace thrive; - -TEST(OgreVector3, Lua) -{ - - sol::state lua; - - initializeLua(lua); - - lua.do_string("a = Vector3(1, 2, 3)\n" - "b = Vector3(10, 20, 30)\n" - "sum = a + b\n" - "dot = a:dotProduct(b)\n"); - - Vector3 sum = lua.get("sum"); - Real dot = lua.get("dot"); - EXPECT_EQ(Vector3(11, 22, 33), sum); - EXPECT_EQ(140, dot); -} diff --git a/test/sky_system.cpp b/test/sky_system.cpp deleted file mode 100644 index 81ffee14257..00000000000 --- a/test/sky_system.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "ogre/sky_system.h" - -#include "scripting/script_initializer.h" - -#include "scripting/luajit.h" - -#include "util/make_unique.h" - -#include - -using namespace thrive; - - -TEST(SkyPlaneComponent, ScriptBindings) -{ - sol::state lua; - - initializeLua(lua); - - auto skyPlane = make_unique(); - lua["skyPlane"] = skyPlane.get(); - - ; - - // Enabled - EXPECT_TRUE(lua.do_string("skyPlane.properties.enabled = false").valid()); - - EXPECT_FALSE(skyPlane->m_properties.enabled); - // Plane.d - EXPECT_TRUE(lua.do_string("skyPlane.properties.plane.d = 42.0").valid()); - EXPECT_EQ(42.0f, skyPlane->m_properties.plane.d); -} diff --git a/test/test_clouds.cpp b/test/test_clouds.cpp index 1b1e5ea8a73..3497be6aeaa 100644 --- a/test/test_clouds.cpp +++ b/test/test_clouds.cpp @@ -1,9 +1,15 @@ //! Tests compound cloud operations that don't need Ogre +#include "engine/player_data.h" +#include "generated/cell_stage_world.h" #include "microbe_stage/compound_cloud_system.h" +#include "test_thrive_game.h" +#include +#include #include "catch.hpp" using namespace thrive; +using namespace thrive::test; TEST_CASE("Cloud contains check is correct", "[microbe]") { @@ -145,3 +151,177 @@ TEST_CASE("Cloud local coordinate calculation math is right", "[microbe]") Leviathan::InvalidArgument); } } + +class CloudManagerTestsFixture { +public: + CloudManagerTestsFixture() + { + thrive.lightweightInit(); + + world.SetRunInBackground(true); + + // TODO: change type when the clouds are made to run again with the + // variable rate ticks + REQUIRE(world.Init( + Leviathan::WorldNetworkSettings::GetSettingsForHybrid(), nullptr)); + + // Create player pos + player = world.CreateEntity(); + + thrive.playerData().setActiveCreature(player); + + REQUIRE_NOTHROW(playerPos = &world.Create_Position(player, + Float3(0, 0, 0), Float4::IdentityQuaternion())); + } + ~CloudManagerTestsFixture() + { + world.Release(); + } + + void + setCloudsAndRunInitial(const std::vector& cloudTypes) + { + world.GetCompoundCloudSystem().registerCloudTypes(world, cloudTypes); + + // Let it run a bit + world.Tick(1); + } + + std::vector + findClouds() + { + std::vector clouds; + + for(ObjectID entity : world.GetEntities()) { + + if(entity == player) + continue; + + REQUIRE_NOTHROW(clouds.emplace_back( + &world.GetComponent_CompoundCloudComponent(entity))); + } + + return clouds; + } + +protected: + Leviathan::Test::PartialEngine engine; + TestThriveGame thrive; + Leviathan::IDFactory ids; + + CellStageWorld world{nullptr}; + + Leviathan::Position* playerPos = nullptr; + ObjectID player = NULL_OBJECT; +}; + +TEST_CASE_METHOD(CloudManagerTestsFixture, + "Cloud manager creates and positions clouds with 1 compound type correctly", + "[microbe]") +{ + setCloudsAndRunInitial( + {Compound{1, "a", true, true, false, Ogre::ColourValue(0, 1, 2, 3)}}); + + // Find the cloud entities + const auto clouds = findClouds(); + + CHECK(clouds.size() == 9); + + // Check that cloud positioning has worked + const auto targetPositions{ + CompoundCloudSystem::calculateGridPositions(Float3(0, 0, 0))}; + + std::vector valid; + valid.resize(targetPositions.size(), false); + + for(size_t i = 0; i < targetPositions.size(); ++i) { + + const auto& pos = targetPositions[i]; + + for(CompoundCloudComponent* cloud : clouds) { + + if(cloud->getPosition() == pos) { + + CHECK(!valid[i]); + valid[i] = true; + } + } + } + + for(bool entry : valid) + CHECK(entry); +} + +TEST_CASE_METHOD(CloudManagerTestsFixture, + "Cloud manager creates and positions clouds with 5 compound types " + "correctly", + "[microbe]") +{ + // This test assumes + static_assert(CLOUDS_IN_ONE == 4, "this test assumes this"); + + const std::vector types{ + Compound{1, "a", true, true, false, Ogre::ColourValue(0, 1, 2, 1)}, + Compound{2, "b", true, true, false, Ogre::ColourValue(3, 4, 5, 1)}, + Compound{3, "c", true, true, false, Ogre::ColourValue(6, 7, 8, 1)}, + Compound{4, "d", true, true, false, Ogre::ColourValue(9, 10, 11, 1)}, + Compound{5, "e", true, true, false, Ogre::ColourValue(12, 13, 14, 1)}}; + + setCloudsAndRunInitial(types); + + // Find the cloud entities + const auto clouds = findClouds(); + + CHECK(clouds.size() == 18); + + // Check that cloud positioning has worked + const auto targetPositions{ + CompoundCloudSystem::calculateGridPositions(Float3(0, 0, 0))}; + + std::vector> valid; + valid.resize(targetPositions.size(), {false, false}); + + for(size_t i = 0; i < targetPositions.size(); ++i) { + + const auto& pos = targetPositions[i]; + + for(CompoundCloudComponent* cloud : clouds) { + + if(cloud->getPosition() == pos) { + + // First or second + CAPTURE(cloud->getCompoundId1()); + if(cloud->getCompoundId1() == types[0].id) { + + // Make sure the rest of the cloud entries are also right + CHECK(cloud->getCompoundId2() == types[1].id); + CHECK(cloud->getCompoundId3() == types[2].id); + CHECK(cloud->getCompoundId4() == types[3].id); + + // Position check + CHECK(!valid[i][0]); + valid[i][0] = true; + + } else if(cloud->getCompoundId1() == types[4].id) { + + // Make sure the rest of the cloud entries are also right + CHECK(cloud->getCompoundId2() == NULL_COMPOUND); + CHECK(cloud->getCompoundId3() == NULL_COMPOUND); + CHECK(cloud->getCompoundId4() == NULL_COMPOUND); + + // Position check + CHECK(!valid[i][1]); + valid[i][1] = true; + + } else { + FAIL_CHECK("cloud has unexpected id"); + } + } + } + } + + for(const auto& entry : valid) { + CHECK(entry[0]); + CHECK(entry[1]); + } +} diff --git a/test/test_component.h b/test/test_component.h deleted file mode 100644 index 9a17b44338c..00000000000 --- a/test/test_component.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include "engine/component.h" -#include "engine/serialization.h" -#include "engine/typedefs.h" - -#include - -template class TestComponent : public thrive::Component { - -public: - static const thrive::ComponentTypeId TYPE_ID = ID + 10000; - - thrive::ComponentTypeId - typeId() const override - { - return TYPE_ID; - }; - - static const std::string& - TYPE_NAME() - { - static std::string string = - "TestComponent" + boost::lexical_cast(ID); - return string; - } - - std::string - typeName() const override - { - return TYPE_NAME(); - }; - - void - load(const thrive::StorageContainer& storage) override - { - Component::load(storage); - } - - thrive::StorageContainer - storage() const override - { - return Component::storage(); - } -}; diff --git a/test/test_thrive_game.h b/test/test_thrive_game.h new file mode 100644 index 00000000000..467c48d51ca --- /dev/null +++ b/test/test_thrive_game.h @@ -0,0 +1,33 @@ +// Thrive Game +// Copyright (C) 2013-2019 Revolutionary Games +#pragma once +// ------------------------------------ // +#include "ThriveGame.h" + +#include "catch.hpp" + +namespace thrive { namespace test { +//! \brief A test dummy for tests needing ThriveGame +class TestThriveGame : public ThriveGame { +public: + TestThriveGame() + { + // We need to fake key configurations for things + ApplicationConfiguration = new Leviathan::AppDef(true); + ApplicationConfiguration->ReplaceGameAndKeyConfigInMemory( + nullptr, &ThriveGame::CheckGameKeyConfigVariables); + } + + ~TestThriveGame() + { + delete ApplicationConfiguration; + } + + void + lightweightInit() + { + REQUIRE(createImpl()); + } +}; + +}} // namespace thrive::test From 3647c1c0886757ac4d40f9a95b6fa22fd70457b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henri=20Hyyryl=C3=A4inen?= Date: Sun, 27 Jan 2019 13:38:59 +0200 Subject: [PATCH 10/42] Refactored cloud position calculation now to always work in single step Finally managed to write a test that shows that the cloud positioning fails then there are more than 4 compound types Fixed cloud positions not staying consistent. Now everything works except phosphates are invisible --- SetupThrive.rb | 2 +- src/ThriveGame.cpp | 6 + src/ThriveGame.h | 4 + src/microbe_stage/compound_cloud_system.cpp | 228 +++++++++----- src/microbe_stage/compound_cloud_system.h | 12 + src/microbe_stage/player_hover_info.cpp | 121 ++++---- test/test_clouds.cpp | 328 ++++++++++++++++---- test/test_thrive_game.h | 2 +- 8 files changed, 511 insertions(+), 192 deletions(-) diff --git a/SetupThrive.rb b/SetupThrive.rb index 23a602a6d11..30270d2fe5d 100755 --- a/SetupThrive.rb +++ b/SetupThrive.rb @@ -78,7 +78,7 @@ def parseExtraArgs leviathan = Leviathan.new( # Use this if you always want the latest commit # version: "develop", - version: "ebaf03d6086c5cac39b66a54093e3926e1c0c359", + version: "28cd2c52dd583e9537f1df32cac91d9b4ed2da2d", # Doesn't actually work, but leviathan doesn't install with sudo by # default, or install at all for that matter noInstallSudo: true diff --git a/src/ThriveGame.cpp b/src/ThriveGame.cpp index 8616c61eafd..153d73924a7 100644 --- a/src/ThriveGame.cpp +++ b/src/ThriveGame.cpp @@ -170,6 +170,12 @@ ThriveGame::ThriveGame() StaticGame = this; } +ThriveGame::ThriveGame(Leviathan::Engine* engine) : + Leviathan::ClientApplication(engine) +{ + StaticGame = this; +} + ThriveGame::~ThriveGame() { StaticGame = nullptr; diff --git a/src/ThriveGame.h b/src/ThriveGame.h index f0ff6c49037..a2c522bdf92 100644 --- a/src/ThriveGame.h +++ b/src/ThriveGame.h @@ -33,6 +33,10 @@ class ThriveGame : public Leviathan::ClientApplication, public ThriveCommon { public: ThriveGame(); + + //! \brief Version for tests with incomplete engine instance + ThriveGame(Leviathan::Engine* engine); + virtual ~ThriveGame(); // ------------------------------------ // diff --git a/src/microbe_stage/compound_cloud_system.cpp b/src/microbe_stage/compound_cloud_system.cpp index 1ca41d25519..49481653b09 100644 --- a/src/microbe_stage/compound_cloud_system.cpp +++ b/src/microbe_stage/compound_cloud_system.cpp @@ -633,6 +633,17 @@ std::tuple return std::make_tuple(localX, localY); } +Float3 + CompoundCloudSystem::calculateGridCenterForPlayerPos(const Float3& pos) +{ + // The gaps between the positions is used for calculations here. Otherwise + // all clouds get moved when the player moves + return Float3( + static_cast(std::round(pos.X / CLOUD_X_EXTENT)) * CLOUD_X_EXTENT, + 0, + static_cast(std::round(pos.Z / CLOUD_Y_EXTENT)) * CLOUD_Y_EXTENT); +} + // ------------------------------------ // void CompoundCloudSystem::Run(CellStageWorld& world) @@ -713,121 +724,176 @@ void ((((m_cloudTypes.size() + 4 - 1) / 4 * 4) / 4) * 9), "A CompoundCloud entity has mysteriously been destroyed"); - const auto moved = playerPos - m_cloudGridCenter; + // Calculate what our center should be + const auto targetCenter = calculateGridCenterForPlayerPos(playerPos); // TODO: because we no longer check if the player has moved at least a bit // it is possible that this gets triggered very often if the player spins - // around a cloud edge, but hopefully there isn't a performance problem and - // that case can just be ignored. - // Z is used here because these are world coordinates - if(std::abs(moved.X) > CLOUD_WIDTH || std::abs(moved.Z) > CLOUD_HEIGHT) { - - // Calculate the new center - if(moved.X < -CLOUD_WIDTH) { - m_cloudGridCenter -= Float3(CLOUD_WIDTH * 2, 0, 0); - } else if(moved.X > CLOUD_WIDTH) { - m_cloudGridCenter += Float3(CLOUD_WIDTH * 2, 0, 0); - } + // around a cloud edge. - if(moved.Z < -CLOUD_HEIGHT) { - m_cloudGridCenter -= Float3(0, 0, CLOUD_HEIGHT * 2); - } else if(moved.Z > CLOUD_HEIGHT) { - m_cloudGridCenter += Float3(0, 0, CLOUD_HEIGHT * 2); - } + // This needs an extra variable to track how much the player has moved + // auto moved = playerPos - m_cloudGridCenter; - // Calculate the new positions - const auto requiredCloudPositions{ - calculateGridPositions(m_cloudGridCenter)}; + if(m_cloudGridCenter != targetCenter) { + + m_cloudGridCenter = targetCenter; + applyNewCloudPositioning(); + } +} + +void + CompoundCloudSystem::applyNewCloudPositioning() +{ + // Calculate the new positions + const auto requiredCloudPositions{ + calculateGridPositions(m_cloudGridCenter)}; - // Reposition clouds according to the origin - // The max amount of clouds is that all need to be moved - const size_t MAX_FAR_CLOUDS = m_managedClouds.size(); + // Reposition clouds according to the origin + // The max amount of clouds is that all need to be moved + const size_t MAX_FAR_CLOUDS = m_managedClouds.size(); - // According to spec this check is superfluous, but it makes me feel - // better - if(m_tooFarAwayClouds.size() != MAX_FAR_CLOUDS) - m_tooFarAwayClouds.resize(MAX_FAR_CLOUDS); + // According to spec this check is superfluous, but it makes me feel + // better + if(m_tooFarAwayClouds.size() != MAX_FAR_CLOUDS) + m_tooFarAwayClouds.resize(MAX_FAR_CLOUDS); - size_t farAwayIndex = 0; + size_t farAwayIndex = 0; - // All clouds that aren't at one of the requiredCloudPositions needs to - // be moved - for(auto iter = m_managedClouds.begin(); iter != m_managedClouds.end(); - ++iter) { + // All clouds that aren't at one of the requiredCloudPositions needs to + // be moved. Also only one from each cloud group needs to be at each + // position + for(auto iter = m_managedClouds.begin(); iter != m_managedClouds.end(); + ++iter) { - const auto pos = iter->second->m_position; + const auto pos = iter->second->m_position; - bool matched = false; + bool matched = false; - // Check if it is at any of the valid positions - for(size_t i = 0; i < std::size(requiredCloudPositions); ++i) { + // Check if it is at any of the valid positions + for(size_t i = 0; i < std::size(requiredCloudPositions); ++i) { - const auto& requiredPos = requiredCloudPositions[i]; + const auto& requiredPos = requiredCloudPositions[i]; - // An exact check might work but just to be safe slight - // inaccuracy is allowed here - if((pos - requiredPos).HAddAbs() < Leviathan::EPSILON) { + // An exact check might work but just to be safe slight + // inaccuracy is allowed here + if((pos - requiredPos).HAddAbs() < Leviathan::EPSILON) { - matched = true; - break; - } - } + // TODO: this is probably not needed and can be removed + // // It also has to be the only cloud with the first + // // compound id that it has (this is used to filter out + // // multiple clouds of a group being at some position) + // bool duplicate = false; - if(!matched) { + // const auto toCheckID = iter->second->getCompoundId1(); - if(farAwayIndex >= MAX_FAR_CLOUDS) { + // for(auto iter2 = m_managedClouds.begin(); + // iter2 != m_managedClouds.end(); ++iter2) { - LOG_FATAL("CompoundCloudSystem: Logic error in calculating " - "far away clouds that need to move"); - break; - } + // if(iter == iter2) + // continue; + + // if(toCheckID == iter2->second->getCompoundId1()) { + // duplicate = true; + // break; + // } + // } - m_tooFarAwayClouds[farAwayIndex++] = iter->second; + // if(!duplicate) { + matched = true; + break; + //} } } - // Move clouds that are too far away - // We check through each position that should have a cloud and move one - // where there isn't one - size_t farAwayRepositionedIndex = 0; - - // Loop through the cloud groups - for(size_t c = 0; c < m_cloudTypes.size(); c += CLOUDS_IN_ONE) { - // Loop for moving clouds to all needed positions for each group - for(size_t i = 0; i < std::size(requiredCloudPositions); ++i) { - bool hasCloud = false; - const auto& requiredPos = requiredCloudPositions[i]; - for(auto iter = m_managedClouds.begin(); - iter != m_managedClouds.end(); ++iter) { - const auto pos = iter->second->m_position; - // An exact check might work but just to be safe slight - // inaccuracy is allowed here - if(((pos - requiredPos).HAddAbs() < Leviathan::EPSILON) && - (m_cloudTypes[c].id == - iter->second->getCompoundId1())) { + if(!matched) { + + if(farAwayIndex >= MAX_FAR_CLOUDS) { + + LOG_FATAL("CompoundCloudSystem: Logic error in calculating " + "far away clouds that need to move"); + break; + } + + m_tooFarAwayClouds[farAwayIndex++] = iter->second; + } + } + + // Move clouds that are too far away + // We check through each position that should have a cloud and move one + // where there isn't one. This also needs to take into account the cloud + // groups + + // Loop through the cloud groups + for(size_t c = 0; c < m_cloudTypes.size(); c += CLOUDS_IN_ONE) { + + const CompoundId groupType = m_cloudTypes[c].id; + + // Loop for moving clouds to all needed positions for each group + for(size_t i = 0; i < std::size(requiredCloudPositions); ++i) { + + bool hasCloud = false; + + const auto& requiredPos = requiredCloudPositions[i]; + + for(auto iter = m_managedClouds.begin(); + iter != m_managedClouds.end(); ++iter) { + + const auto pos = iter->second->m_position; + // An exact check might work but just to be safe slight + // inaccuracy is allowed here + if(((pos - requiredPos).HAddAbs() < Leviathan::EPSILON)) { + + // Check that the group of the cloud is correct + if(groupType == iter->second->getCompoundId1()) { hasCloud = true; break; } } + } + + if(hasCloud) + continue; + + bool filled = false; + + // We need to find a cloud from the right group + for(size_t checkReposition = 0; checkReposition < farAwayIndex; + ++checkReposition) { - if(hasCloud) - continue; + if(m_tooFarAwayClouds[checkReposition] && + m_tooFarAwayClouds[checkReposition]->getCompoundId1() == + groupType) { - if(farAwayRepositionedIndex >= farAwayIndex) { - LOG_FATAL("CompoundCloudSystem: Logic error in moving far " - "clouds (ran out), total to reposition: " + - std::to_string(farAwayIndex + 1) + - ", current index: " + - std::to_string(farAwayRepositionedIndex) + - ", position grid index: " + std::to_string(i)); + // Found a candidate + m_tooFarAwayClouds[checkReposition]->recycleToPosition( + requiredPos); + + // Set to null to skip on next scan + m_tooFarAwayClouds[checkReposition] = nullptr; + + filled = true; break; } + } - m_tooFarAwayClouds[farAwayRepositionedIndex++] - ->recycleToPosition(requiredPos); + if(!filled) { + LOG_FATAL("CompoundCloudSystem: Logic error in moving far " + "clouds, didn't find any to use for needed pos"); + break; } } } + + // TODO: this can be removed once this has been fully confirmed to work fine + // Errors about clouds that should have been moved but haven't been + for(size_t checkReposition = 0; checkReposition < farAwayIndex; + ++checkReposition) { + if(m_tooFarAwayClouds[checkReposition]) { + LOG_FATAL( + "CompoundCloudSystem: Logic error in moving far " + "clouds, a cloud that should have been moved wasn't moved"); + } + } } void diff --git a/src/microbe_stage/compound_cloud_system.h b/src/microbe_stage/compound_cloud_system.h index 3e7a550e557..45f83d2046b 100644 --- a/src/microbe_stage/compound_cloud_system.h +++ b/src/microbe_stage/compound_cloud_system.h @@ -479,6 +479,9 @@ class CompoundCloudSystem { }; } + static Float3 + calculateGridCenterForPlayerPos(const Float3& pos); + protected: //! \brief Removes deleted clouds from m_managedClouds void @@ -486,9 +489,18 @@ class CompoundCloudSystem { private: //! \brief Spawns and despawns the cloud entities around the player + //! \todo This should check if the player has moved at least 10 units to + //! avoid excessive recalculations if the player goes in a circle around a + //! cloud boundary void doSpawnCycle(CellStageWorld& world, const Float3& playerPos); + //! \brief This method handles moving the clouds + //! + //! This has been separated from doSpawnCycle to be more manageable + void + applyNewCloudPositioning(); + void _spawnCloud(CellStageWorld& world, const Float3& pos, diff --git a/src/microbe_stage/player_hover_info.cpp b/src/microbe_stage/player_hover_info.cpp index a2c2a01ba8a..6eafa2bce17 100644 --- a/src/microbe_stage/player_hover_info.cpp +++ b/src/microbe_stage/player_hover_info.cpp @@ -85,85 +85,94 @@ void auto microbeComponents = world.GetScriptComponentHolder("MicrobeComponent"); - // The world will keep this alive (this is released immediately to reduce - // chance of leaks) - microbeComponents->Release(); + // Only run when scripts are loaded + // TODO: move this to a sub function to not have this huge indended block + // here + if(microbeComponents) { - const auto stringType = - Leviathan::AngelScriptTypeIDResolver::Get( - Leviathan::GetCurrentGlobalScriptExecutor()); + // The world will keep this alive (this is released immediately to + // reduce chance of leaks) + microbeComponents->Release(); - // This is used to skip the player - auto controlledEntity = ThriveGame::Get()->playerData().activeCreature(); + const auto stringType = + Leviathan::AngelScriptTypeIDResolver::Get( + Leviathan::GetCurrentGlobalScriptExecutor()); - const auto& allSpecies = world.GetComponentIndex_SpeciesComponent(); + // This is used to skip the player + auto controlledEntity = + ThriveGame::Get()->playerData().activeCreature(); - auto& index = CachedComponents.GetIndex(); - for(auto iter = index.begin(); iter != index.end(); ++iter) { + const auto& allSpecies = world.GetComponentIndex_SpeciesComponent(); - const float distance = - (std::get<1>(*iter->second).Members._Position - lookPoint).Length(); + auto& index = CachedComponents.GetIndex(); + for(auto iter = index.begin(); iter != index.end(); ++iter) { - // Find only cells that have the mouse position within their membrane - if(distance > - std::get<0>(*iter->second).calculateEncompassingCircleRadius()) - continue; + const float distance = + (std::get<1>(*iter->second).Members._Position - lookPoint) + .Length(); - // Skip player - if(iter->first == controlledEntity) - continue; + // Find only cells that have the mouse position within their + // membrane + if(distance > + std::get<0>(*iter->second).calculateEncompassingCircleRadius()) + continue; - // Hovered over this. Find the name of the species - auto microbeComponent = microbeComponents->Find(iter->first); + // Skip player + if(iter->first == controlledEntity) + continue; - if(!microbeComponent) - continue; + // Hovered over this. Find the name of the species + auto microbeComponent = microbeComponents->Find(iter->first); - // We don't store the reference to the object. The holder will keep - // the reference alive while we work on it - microbeComponent->Release(); + if(!microbeComponent) + continue; - if(microbeComponent->GetPropertyCount() < 1) { + // We don't store the reference to the object. The holder will keep + // the reference alive while we work on it + microbeComponent->Release(); - LOG_ERROR("PlayerHoverInfoSystem: Run: MicrobeComponent object " - "has no properties"); - continue; - } + if(microbeComponent->GetPropertyCount() < 1) { - if(microbeComponent->GetPropertyTypeId(0) != stringType || - std::strncmp(microbeComponent->GetPropertyName(0), "speciesName", - sizeof("speciesName") - 1) != 0) { + LOG_ERROR("PlayerHoverInfoSystem: Run: MicrobeComponent object " + "has no properties"); + continue; + } - LOG_ERROR( - "PlayerHoverInfoSystem: Run: MicrobeComponent object doesn't " - "have \"string speciesName\" as the first property"); - continue; - } + if(microbeComponent->GetPropertyTypeId(0) != stringType || + std::strncmp(microbeComponent->GetPropertyName(0), + "speciesName", sizeof("speciesName") - 1) != 0) { - const auto* name = static_cast( - microbeComponent->GetAddressOfProperty(0)); + LOG_ERROR("PlayerHoverInfoSystem: Run: MicrobeComponent object " + "doesn't " + "have \"string speciesName\" as the first property"); + continue; + } - bool found = false; + const auto* name = static_cast( + microbeComponent->GetAddressOfProperty(0)); - for(const auto& tuple : allSpecies) { + bool found = false; - SpeciesComponent* species = std::get<1>(tuple); + for(const auto& tuple : allSpecies) { - if(species->name == *name) { + SpeciesComponent* species = std::get<1>(tuple); - hovered->PushValue( - std::make_unique(new Leviathan::StringBlock( - species->genus + " " + species->epithet))); - found = true; - break; + if(species->name == *name) { + + hovered->PushValue(std::make_unique( + new Leviathan::StringBlock( + species->genus + " " + species->epithet))); + found = true; + break; + } } - } - if(!found) { + if(!found) { - // If we can't find the species, assume that it is extinct - hovered->PushValue(std::make_unique( - new Leviathan::StringBlock("Extinct(" + *name + ")"))); + // If we can't find the species, assume that it is extinct + hovered->PushValue(std::make_unique( + new Leviathan::StringBlock("Extinct(" + *name + ")"))); + } } } diff --git a/test/test_clouds.cpp b/test/test_clouds.cpp index 3497be6aeaa..529fa4de049 100644 --- a/test/test_clouds.cpp +++ b/test/test_clouds.cpp @@ -152,6 +152,39 @@ TEST_CASE("Cloud local coordinate calculation math is right", "[microbe]") } } +TEST_CASE("CloudManager grid center calculation", "[microbe]") +{ + CHECK(CompoundCloudSystem::calculateGridCenterForPlayerPos( + Float3(0, 0, 0)) == Float3(0, 0, 0)); + + CHECK(CompoundCloudSystem::calculateGridCenterForPlayerPos( + Float3(CLOUD_WIDTH - 1, 0, 0)) == Float3(0, 0, 0)); + + CHECK(CompoundCloudSystem::calculateGridCenterForPlayerPos( + Float3(CLOUD_WIDTH, 0, 0)) == Float3(CLOUD_X_EXTENT, 0, 0)); + + CHECK(CompoundCloudSystem::calculateGridCenterForPlayerPos( + Float3(CLOUD_WIDTH + 1, 0, 0)) == Float3(CLOUD_X_EXTENT, 0, 0)); + + CHECK(CompoundCloudSystem::calculateGridCenterForPlayerPos( + Float3(CLOUD_WIDTH, 0, CLOUD_HEIGHT)) == + Float3(CLOUD_X_EXTENT, 0, CLOUD_Y_EXTENT)); + + CHECK(CompoundCloudSystem::calculateGridCenterForPlayerPos( + Float3(CLOUD_WIDTH, 0, CLOUD_HEIGHT * 2)) == + Float3(CLOUD_X_EXTENT, 0, CLOUD_Y_EXTENT)); + + CHECK(CompoundCloudSystem::calculateGridCenterForPlayerPos( + Float3(-CLOUD_X_EXTENT, 0, 0)) == Float3(-CLOUD_Y_EXTENT, 0, 0)); + + CHECK(CompoundCloudSystem::calculateGridCenterForPlayerPos( + Float3(-CLOUD_WIDTH, 0, -CLOUD_HEIGHT)) == + Float3(-CLOUD_X_EXTENT, 0, -CLOUD_Y_EXTENT)); + + CHECK(CompoundCloudSystem::calculateGridCenterForPlayerPos(Float3( + -CLOUD_WIDTH + 1, 0, -CLOUD_HEIGHT + 1)) == Float3(0, 0, 0)); +} + class CloudManagerTestsFixture { public: CloudManagerTestsFixture() @@ -204,9 +237,20 @@ class CloudManagerTestsFixture { return clouds; } + void + movePlayerXUnits(float amount) + { + // Move player + playerPos->Members._Position.X += amount; + playerPos->Marked = true; + + // And tick + world.Tick(1); + } + protected: Leviathan::Test::PartialEngine engine; - TestThriveGame thrive; + TestThriveGame thrive{&engine}; Leviathan::IDFactory ids; CellStageWorld world{nullptr}; @@ -215,22 +259,11 @@ class CloudManagerTestsFixture { ObjectID player = NULL_OBJECT; }; -TEST_CASE_METHOD(CloudManagerTestsFixture, - "Cloud manager creates and positions clouds with 1 compound type correctly", - "[microbe]") +template +auto + simpleCloudPosCheck(const std::vector& clouds, + const PosArrayT& targetPositions) { - setCloudsAndRunInitial( - {Compound{1, "a", true, true, false, Ogre::ColourValue(0, 1, 2, 3)}}); - - // Find the cloud entities - const auto clouds = findClouds(); - - CHECK(clouds.size() == 9); - - // Check that cloud positioning has worked - const auto targetPositions{ - CompoundCloudSystem::calculateGridPositions(Float3(0, 0, 0))}; - std::vector valid; valid.resize(targetPositions.size(), false); @@ -248,13 +281,164 @@ TEST_CASE_METHOD(CloudManagerTestsFixture, } } + return valid; +} + +//! A pretty inefficient but simple way to calculate how many clouds are at the +//! same pos and what types +auto + calculateCloudsAtSamePos(const std::vector& clouds) +{ + std::map> counts; + + for(auto cloud : clouds) { + + std::stringstream stream; + stream << cloud->getPosition(); + + if(counts.find(stream.str()) == counts.end()) { + counts.insert(std::make_pair(stream.str(), + std::vector{cloud->getCompoundId1()})); + } else { + counts[stream.str()].push_back(cloud->getCompoundId1()); + } + } + + return counts; +} + +template +void + checkCloudsAtPos( + const std::map>& counts, + const std::array& types) +{ + CAPTURE(types); + + for(const auto& pair : counts) { + CAPTURE(pair.first); + CAPTURE(pair.second); + + CHECK(pair.second.size() == types.size()); + + std::vector foundStatuses; + foundStatuses.resize(types.size(), false); + + for(auto id : pair.second) { + for(size_t i = 0; i < types.size(); ++i) { + if(id == types[i]) { + + CHECK(!foundStatuses[i]); + foundStatuses[i] = true; + break; + } + } + } + + CAPTURE(foundStatuses); + for(bool found : foundStatuses) + CHECK(found); + } +} + +template +auto + multiOverlapCloudPosCheck( + const std::vector& clouds, + const PosArrayT& targetPositions, + const std::array& cloudFirstTypes) +{ + std::vector> valid; + + std::array falseArray; + for(bool& entry : falseArray) + entry = false; + + valid.resize(targetPositions.size(), falseArray); + + for(size_t i = 0; i < targetPositions.size(); ++i) { + + CAPTURE(i); + + const auto& pos = targetPositions[i]; + + for(CompoundCloudComponent* cloud : clouds) { + + if(cloud->getPosition() == pos) { + + CAPTURE(cloud->getCompoundId1(), pos, cloudFirstTypes); + + bool matched = false; + + // Check which group it is + for(size_t targetTypeIndex = 0; + targetTypeIndex < cloudFirstTypes.size(); + ++targetTypeIndex) { + + if(cloud->getCompoundId1() == + cloudFirstTypes[targetTypeIndex]) { + + // Position check + CHECK(!valid[i][targetTypeIndex]); + valid[i][targetTypeIndex] = true; + matched = true; + break; + } + } + + CHECK(matched); + } + } + } + + return valid; +} + +template +void + multiCloudPositionCheckHelper( + const std::vector& clouds, + const Float3& playerPos, + const std::array& cloudFirstTypes) +{ + // There needs to be 2 clouds at each position + checkCloudsAtPos(calculateCloudsAtSamePos(clouds), cloudFirstTypes); + + // And then check that update succeeded + const auto valid = multiOverlapCloudPosCheck(clouds, + CompoundCloudSystem::calculateGridPositions( + CompoundCloudSystem::calculateGridCenterForPlayerPos(playerPos)), + cloudFirstTypes); + + for(const auto& entry : valid) { + CAPTURE(entry); + for(auto subentry : entry) + CHECK(subentry); + } +} + +TEST_CASE_METHOD(CloudManagerTestsFixture, + "Cloud manager creates and positions clouds with 1 compound type", + "[microbe]") +{ + setCloudsAndRunInitial( + {Compound{1, "a", true, true, false, Ogre::ColourValue(0, 1, 2, 3)}}); + + // Find the cloud entities + const auto clouds = findClouds(); + + CHECK(clouds.size() == 9); + + // Check that cloud positioning has worked + const auto valid = simpleCloudPosCheck( + clouds, CompoundCloudSystem::calculateGridPositions(Float3(0, 0, 0))); + for(bool entry : valid) CHECK(entry); } TEST_CASE_METHOD(CloudManagerTestsFixture, - "Cloud manager creates and positions clouds with 5 compound types " - "correctly", + "Cloud manager creates and positions clouds with 5 compound types", "[microbe]") { // This test assumes @@ -267,6 +451,10 @@ TEST_CASE_METHOD(CloudManagerTestsFixture, Compound{4, "d", true, true, false, Ogre::ColourValue(9, 10, 11, 1)}, Compound{5, "e", true, true, false, Ogre::ColourValue(12, 13, 14, 1)}}; + std::array cloudFirstTypes; + cloudFirstTypes[0] = types[0].id; + cloudFirstTypes[1] = types[4].id; + setCloudsAndRunInitial(types); // Find the cloud entities @@ -274,54 +462,88 @@ TEST_CASE_METHOD(CloudManagerTestsFixture, CHECK(clouds.size() == 18); + multiCloudPositionCheckHelper( + clouds, playerPos->Members._Position, cloudFirstTypes); +} + + +TEST_CASE_METHOD(CloudManagerTestsFixture, + "Cloud manager repositions on player move clouds with 1 compound type", + "[microbe]") +{ + constexpr auto PLAYER_MOVE_AMOUNT = 1000; + + setCloudsAndRunInitial( + {Compound{1, "a", true, true, false, Ogre::ColourValue(0, 1, 2, 3)}}); + + // Find the cloud entities + const auto clouds = findClouds(); + + CHECK(clouds.size() == 9); + // Check that cloud positioning has worked - const auto targetPositions{ - CompoundCloudSystem::calculateGridPositions(Float3(0, 0, 0))}; + auto valid = simpleCloudPosCheck( + clouds, CompoundCloudSystem::calculateGridPositions(Float3(0, 0, 0))); - std::vector> valid; - valid.resize(targetPositions.size(), {false, false}); + for(bool entry : valid) + CHECK(entry); - for(size_t i = 0; i < targetPositions.size(); ++i) { + // Move player + playerPos->Members._Position.X += PLAYER_MOVE_AMOUNT; + playerPos->Marked = true; - const auto& pos = targetPositions[i]; + // And tick + world.Tick(1); - for(CompoundCloudComponent* cloud : clouds) { + // And then check that update succeeded + valid = simpleCloudPosCheck( + clouds, CompoundCloudSystem::calculateGridPositions( + CompoundCloudSystem::calculateGridCenterForPlayerPos( + Float3(PLAYER_MOVE_AMOUNT, 0, 0)))); - if(cloud->getPosition() == pos) { + for(bool entry : valid) + CHECK(entry); +} - // First or second - CAPTURE(cloud->getCompoundId1()); - if(cloud->getCompoundId1() == types[0].id) { +TEST_CASE_METHOD(CloudManagerTestsFixture, + "Cloud manager repositions on player move clouds with 5 compound types", + "[microbe]") +{ + // This test assumes + static_assert(CLOUDS_IN_ONE == 4, "this test assumes this"); - // Make sure the rest of the cloud entries are also right - CHECK(cloud->getCompoundId2() == types[1].id); - CHECK(cloud->getCompoundId3() == types[2].id); - CHECK(cloud->getCompoundId4() == types[3].id); + const std::vector types{ + Compound{1, "a", true, true, false, Ogre::ColourValue(0, 1, 2, 1)}, + Compound{2, "b", true, true, false, Ogre::ColourValue(3, 4, 5, 1)}, + Compound{3, "c", true, true, false, Ogre::ColourValue(6, 7, 8, 1)}, + Compound{4, "d", true, true, false, Ogre::ColourValue(9, 10, 11, 1)}, + Compound{5, "e", true, true, false, Ogre::ColourValue(12, 13, 14, 1)}}; - // Position check - CHECK(!valid[i][0]); - valid[i][0] = true; + std::array cloudFirstTypes; + cloudFirstTypes[0] = types[0].id; + cloudFirstTypes[1] = types[4].id; - } else if(cloud->getCompoundId1() == types[4].id) { + setCloudsAndRunInitial(types); - // Make sure the rest of the cloud entries are also right - CHECK(cloud->getCompoundId2() == NULL_COMPOUND); - CHECK(cloud->getCompoundId3() == NULL_COMPOUND); - CHECK(cloud->getCompoundId4() == NULL_COMPOUND); + // Find the cloud entities + const auto clouds = findClouds(); - // Position check - CHECK(!valid[i][1]); - valid[i][1] = true; + CHECK(clouds.size() == 18); - } else { - FAIL_CHECK("cloud has unexpected id"); - } - } - } - } + multiCloudPositionCheckHelper( + clouds, playerPos->Members._Position, cloudFirstTypes); - for(const auto& entry : valid) { - CHECK(entry[0]); - CHECK(entry[1]); + // SECTION("Moving CLOUD_WIDTH/2 units") {} + + SECTION("Moving 1000 units") + { + constexpr auto PLAYER_MOVE_AMOUNT = 1000; + + movePlayerXUnits(PLAYER_MOVE_AMOUNT); + + multiCloudPositionCheckHelper( + clouds, playerPos->Members._Position, cloudFirstTypes); } + + // SECTION("Moving CLOUD_WIDTH * 1.5 units") {} } diff --git a/test/test_thrive_game.h b/test/test_thrive_game.h index 467c48d51ca..3bdfc364e15 100644 --- a/test/test_thrive_game.h +++ b/test/test_thrive_game.h @@ -10,7 +10,7 @@ namespace thrive { namespace test { //! \brief A test dummy for tests needing ThriveGame class TestThriveGame : public ThriveGame { public: - TestThriveGame() + TestThriveGame(Leviathan::Engine* engine) : ThriveGame(engine) { // We need to fake key configurations for things ApplicationConfiguration = new Leviathan::AppDef(true); From 9c2904e19b4375ec60c9a535c62be311e255b444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henri=20Hyyryl=C3=A4inen?= Date: Sun, 27 Jan 2019 14:56:13 +0200 Subject: [PATCH 11/42] Added cheat to spawn phosphate for testing --- src/ThriveGame.cpp | 1 + src/microbe_stage/compound_cloud_system.h | 3 --- src/microbe_stage/player_microbe_control.cpp | 25 +++++++++++++++++++- src/microbe_stage/player_microbe_control.h | 10 ++++++++ 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/ThriveGame.cpp b/src/ThriveGame.cpp index 153d73924a7..b3aa2239fcd 100644 --- a/src/ThriveGame.cpp +++ b/src/ThriveGame.cpp @@ -1110,6 +1110,7 @@ void keyconfigobj->AddKeyIfMissing(guard, "MoveRight", {"D"}); keyconfigobj->AddKeyIfMissing(guard, "ReproduceCheat", {"P"}); keyconfigobj->AddKeyIfMissing(guard, "SpawnGlucoseCheat", {"O"}); + keyconfigobj->AddKeyIfMissing(guard, "SpawnPhosphateCheat", {"I"}); keyconfigobj->AddKeyIfMissing(guard, "EngulfMode", {"G"}); keyconfigobj->AddKeyIfMissing(guard, "ShootToxin", {"E"}); keyconfigobj->AddKeyIfMissing(guard, "Screenshot", {"PrintScreen"}); diff --git a/src/microbe_stage/compound_cloud_system.h b/src/microbe_stage/compound_cloud_system.h index 45f83d2046b..d132c5f6ac5 100644 --- a/src/microbe_stage/compound_cloud_system.h +++ b/src/microbe_stage/compound_cloud_system.h @@ -331,9 +331,6 @@ class CompoundCloudComponent : public Leviathan::Component { //! \todo This can be removed once there is a proper clear method available //! for systems to detect CompoundCloudSystem& m_owner; - - // //! A helper value to handle cloud repositioning - // bool m_repositioned = false; }; diff --git a/src/microbe_stage/player_microbe_control.cpp b/src/microbe_stage/player_microbe_control.cpp index 73e1be6e43b..b86b9a7af9f 100644 --- a/src/microbe_stage/player_microbe_control.cpp +++ b/src/microbe_stage/player_microbe_control.cpp @@ -24,6 +24,8 @@ PlayerMicrobeControl::PlayerMicrobeControl(KeyConfiguration& keys) : m_left(keys.ResolveControlNameToFirstKey("MoveLeft")), m_right(keys.ResolveControlNameToFirstKey("MoveRight")), m_spawnGlucoseCheat(keys.ResolveControlNameToFirstKey("SpawnGlucoseCheat")), + m_spawnPhosphateCheat( + keys.ResolveControlNameToFirstKey("SpawnPhosphateCheat")), m_zoomIn(keys.ResolveControlNameToKeyVector("ZoomIn")), m_zoomOut(keys.ResolveControlNameToKeyVector("ZoomOut")) {} @@ -43,6 +45,13 @@ bool return true; } + if(!active && cheatPhosphateCloudsDown && + m_spawnPhosphateCheat.Match(key, modifiers)) { + + cheatPhosphateCloudsDown = false; + return true; + } + if(!active) return false; @@ -77,6 +86,14 @@ bool cheatCloudsDown = true; } return true; + } else if(m_spawnPhosphateCheat.Match(key, modifiers)) { + + if(ThriveGame::get()->areCheatsEnabled()) { + + LOG_INFO("Phosphate cloud cheat pressed"); + cheatPhosphateCloudsDown = true; + } + return true; } @@ -314,11 +331,17 @@ void if(thrive->getPlayerInput()->getSpamClouds()) { - LOG_INFO("Spawning cheat cloud"); world.GetCompoundCloudSystem().addCloud( SimulationParameters::compoundRegistry.getTypeId("glucose"), 15000, lookPoint); } + + if(thrive->getPlayerInput()->getCheatPhosphateCloudsDown()) { + + world.GetCompoundCloudSystem().addCloud( + SimulationParameters::compoundRegistry.getTypeId("phosphates"), + 15000, lookPoint); + } } // ------------------------------------ // Float3 diff --git a/src/microbe_stage/player_microbe_control.h b/src/microbe_stage/player_microbe_control.h index 0b60e553142..4da3705dea2 100644 --- a/src/microbe_stage/player_microbe_control.h +++ b/src/microbe_stage/player_microbe_control.h @@ -47,6 +47,12 @@ class PlayerMicrobeControl : public Leviathan::InputReceiver { return cheatCloudsDown; } + inline bool + getCheatPhosphateCloudsDown() const + { + return cheatPhosphateCloudsDown; + } + bool getPressedEngulf() const { @@ -88,6 +94,7 @@ class PlayerMicrobeControl : public Leviathan::InputReceiver { Leviathan::GKey m_right; Leviathan::GKey m_spawnGlucoseCheat; + Leviathan::GKey m_spawnPhosphateCheat; std::vector m_zoomIn; std::vector m_zoomOut; @@ -103,6 +110,9 @@ class PlayerMicrobeControl : public Leviathan::InputReceiver { //! True when cheat clouds should be spawned all the time bool cheatCloudsDown = false; + //! Phosphate cheat cloud + bool cheatPhosphateCloudsDown = false; + //! Set to false when not in the microbe stage (or maybe editor as //! well could use this) to not send control events bool m_enabled = false; From 437b92ff3c2460358254ef7cf47173c60c7541da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henri=20Hyyryl=C3=A4inen?= Date: Sun, 27 Jan 2019 17:38:10 +0200 Subject: [PATCH 12/42] Clouds should now properly work with the new iron The blending between the cloud groups isn't that great but at least they are kinda blending. --- src/microbe_stage/compound_cloud_system.cpp | 149 +++++++++++--------- src/microbe_stage/compound_cloud_system.h | 8 +- test/test_clouds.cpp | 82 ++++++++++- 3 files changed, 165 insertions(+), 74 deletions(-) diff --git a/src/microbe_stage/compound_cloud_system.cpp b/src/microbe_stage/compound_cloud_system.cpp index 49481653b09..03781591a4c 100644 --- a/src/microbe_stage/compound_cloud_system.cpp +++ b/src/microbe_stage/compound_cloud_system.cpp @@ -159,13 +159,12 @@ void if(x >= m_density1.size() || y >= m_density1[0].size()) throw std::runtime_error( "CompoundCloudComponent coordinates out of range"); - if(compound != NULL_COMPOUND) { - switch(getSlotForCompound(compound)) { - case SLOT::FIRST: m_density1[x][y] += dens; break; - case SLOT::SECOND: m_density2[x][y] += dens; break; - case SLOT::THIRD: m_density3[x][y] += dens; break; - case SLOT::FOURTH: m_density4[x][y] += dens; break; - } + + switch(getSlotForCompound(compound)) { + case SLOT::FIRST: m_density1[x][y] += dens; break; + case SLOT::SECOND: m_density2[x][y] += dens; break; + case SLOT::THIRD: m_density3[x][y] += dens; break; + case SLOT::FOURTH: m_density4[x][y] += dens; break; } } @@ -175,41 +174,39 @@ int size_t y, float rate) { - if(compound != NULL_COMPOUND) { - switch(getSlotForCompound(compound)) { - case SLOT::FIRST: { - int amountToGive = static_cast(m_density1[x][y] * rate); - m_density1[x][y] -= amountToGive; - if(m_density1[x][y] < 1) - m_density1[x][y] = 0; - - return amountToGive; - } - case SLOT::SECOND: { - int amountToGive = static_cast(m_density2[x][y] * rate); - m_density2[x][y] -= amountToGive; - if(m_density2[x][y] < 1) - m_density2[x][y] = 0; + switch(getSlotForCompound(compound)) { + case SLOT::FIRST: { + int amountToGive = static_cast(m_density1[x][y] * rate); + m_density1[x][y] -= amountToGive; + if(m_density1[x][y] < 1) + m_density1[x][y] = 0; + + return amountToGive; + } + case SLOT::SECOND: { + int amountToGive = static_cast(m_density2[x][y] * rate); + m_density2[x][y] -= amountToGive; + if(m_density2[x][y] < 1) + m_density2[x][y] = 0; - return amountToGive; - } - case SLOT::THIRD: { - int amountToGive = static_cast(m_density3[x][y] * rate); - m_density3[x][y] -= amountToGive; - if(m_density3[x][y] < 1) - m_density3[x][y] = 0; + return amountToGive; + } + case SLOT::THIRD: { + int amountToGive = static_cast(m_density3[x][y] * rate); + m_density3[x][y] -= amountToGive; + if(m_density3[x][y] < 1) + m_density3[x][y] = 0; - return amountToGive; - } - case SLOT::FOURTH: { - int amountToGive = static_cast(m_density4[x][y] * rate); - m_density4[x][y] -= amountToGive; - if(m_density4[x][y] < 1) - m_density4[x][y] = 0; + return amountToGive; + } + case SLOT::FOURTH: { + int amountToGive = static_cast(m_density4[x][y] * rate); + m_density4[x][y] -= amountToGive; + if(m_density4[x][y] < 1) + m_density4[x][y] = 0; - return amountToGive; - } - } + return amountToGive; + } } LEVIATHAN_ASSERT(false, "Shouldn't get here"); @@ -222,26 +219,25 @@ int size_t y, float rate) { - if(compound != NULL_COMPOUND) { - switch(getSlotForCompound(compound)) { - case SLOT::FIRST: { - int amountToGive = static_cast(m_density1[x][y] * rate); - return amountToGive; - } - case SLOT::SECOND: { - int amountToGive = static_cast(m_density2[x][y] * rate); - return amountToGive; - } - case SLOT::THIRD: { - int amountToGive = static_cast(m_density3[x][y] * rate); - return amountToGive; - } - case SLOT::FOURTH: { - int amountToGive = static_cast(m_density4[x][y] * rate); - return amountToGive; - } - } + switch(getSlotForCompound(compound)) { + case SLOT::FIRST: { + int amountToGive = static_cast(m_density1[x][y] * rate); + return amountToGive; + } + case SLOT::SECOND: { + int amountToGive = static_cast(m_density2[x][y] * rate); + return amountToGive; + } + case SLOT::THIRD: { + int amountToGive = static_cast(m_density3[x][y] * rate); + return amountToGive; + } + case SLOT::FOURTH: { + int amountToGive = static_cast(m_density4[x][y] * rate); + return amountToGive; } + } + LEVIATHAN_ASSERT(false, "Shouldn't get here"); return -1; } @@ -435,7 +431,6 @@ void doSpawnCycle(world, Float3(0, 0, 0)); } -//! \brief Places specified amount of compound at position bool CompoundCloudSystem::addCloud(CompoundId compound, float density, @@ -472,7 +467,6 @@ bool return false; } -//! \param rate should be less than one. float CompoundCloudSystem::takeCompound(CompoundId compound, const Float3& worldPosition, @@ -507,7 +501,6 @@ float return 0; } -//! \param rate should be less than one. float CompoundCloudSystem::amountAvailable(CompoundId compound, const Float3& worldPosition, @@ -1022,6 +1015,8 @@ void // The perlin noise texture needs to be tileable. We can't do tricks with // the cloud's position + // Even though we ask for the RGBA format the actual order of pixels when + // locked for writing is something completely different cloud.m_texture = Ogre::TextureManager::getSingleton().createManual( cloud.m_textureName, "Generated", Ogre::TEX_TYPE_2D, CLOUD_SIMULATION_WIDTH, CLOUD_SIMULATION_HEIGHT, 0, Ogre::PF_BYTE_RGBA, @@ -1150,16 +1145,36 @@ void // This is probably branch predictor friendly to move each bunch of pixels // separately - // First channel - if(cloud.m_compoundId1 != NULL_COMPOUND) - fillCloudChannel(cloud.m_density1, 0, rowBytes, pDest); - // Second + // Due to Ogre making the pixelbox lock however it wants the order is + // actually: Ogre::PF_A8R8G8B8 + if(pixelBox.format != Ogre::PF_A8R8G8B8) { + LOG_INFO( + "Pixel format: " + Ogre::PixelUtil::getFormatName(pixelBox.format)); + LEVIATHAN_ASSERT(false, + "Ogre created texture write lock with unexpected pixel order"); + } + + // Even with that pixel format the actual channel indexes are: + // so PF_B8G8R8A8 for some reason + // R - 2 + // G - 1 + // B - 0 + // A - 3 + + if(cloud.m_compoundId1 == NULL_COMPOUND) + LEVIATHAN_ASSERT(false, "cloud with not even the first compound"); + + // First density. R goes to channel 2 (see above for the mapping) + fillCloudChannel(cloud.m_density1, 2, rowBytes, pDest); + + // Second. G - 1 if(cloud.m_compoundId2 != NULL_COMPOUND) fillCloudChannel(cloud.m_density2, 1, rowBytes, pDest); - // Etc. + // Etc. B - 0 if(cloud.m_compoundId3 != NULL_COMPOUND) - fillCloudChannel(cloud.m_density3, 2, rowBytes, pDest); + fillCloudChannel(cloud.m_density3, 0, rowBytes, pDest); + // A - 3 if(cloud.m_compoundId4 != NULL_COMPOUND) fillCloudChannel(cloud.m_density4, 3, rowBytes, pDest); diff --git a/src/microbe_stage/compound_cloud_system.h b/src/microbe_stage/compound_cloud_system.h index d132c5f6ac5..4aa8a187231 100644 --- a/src/microbe_stage/compound_cloud_system.h +++ b/src/microbe_stage/compound_cloud_system.h @@ -315,10 +315,10 @@ class CompoundCloudComponent : public Leviathan::Component { //! The color of the compound cloud. //! Every used channel must have alpha of 1. The others have alpha 0 so that //! they don't need to be worried about affecting the resulting colours - Ogre::Vector4 m_color1; - Ogre::Vector4 m_color2; - Ogre::Vector4 m_color3; - Ogre::Vector4 m_color4; + Ogre::Vector4 m_color1 = Ogre::Vector4(0, 0, 0, 0); + Ogre::Vector4 m_color2 = Ogre::Vector4(0, 0, 0, 0); + Ogre::Vector4 m_color3 = Ogre::Vector4(0, 0, 0, 0); + Ogre::Vector4 m_color4 = Ogre::Vector4(0, 0, 0, 0); //! \brief The compound id. //! \note NULL_COMPOUND means that this cloud doesn't have that slot filled diff --git a/test/test_clouds.cpp b/test/test_clouds.cpp index 529fa4de049..971d7921a98 100644 --- a/test/test_clouds.cpp +++ b/test/test_clouds.cpp @@ -533,8 +533,6 @@ TEST_CASE_METHOD(CloudManagerTestsFixture, multiCloudPositionCheckHelper( clouds, playerPos->Members._Position, cloudFirstTypes); - // SECTION("Moving CLOUD_WIDTH/2 units") {} - SECTION("Moving 1000 units") { constexpr auto PLAYER_MOVE_AMOUNT = 1000; @@ -544,6 +542,84 @@ TEST_CASE_METHOD(CloudManagerTestsFixture, multiCloudPositionCheckHelper( clouds, playerPos->Members._Position, cloudFirstTypes); } +} + +TEST_CASE_METHOD(CloudManagerTestsFixture, + "Cloud manager puts spawned cloud in right entity with 5 compound types", + "[microbe]") +{ + // This test assumes + static_assert(CLOUDS_IN_ONE == 4, "this test assumes this"); + + const std::vector types{ + Compound{1, "a", true, true, false, Ogre::ColourValue(0, 1, 2, 1)}, + Compound{2, "b", true, true, false, Ogre::ColourValue(3, 4, 5, 1)}, + Compound{3, "c", true, true, false, Ogre::ColourValue(6, 7, 8, 1)}, + Compound{4, "d", true, true, false, Ogre::ColourValue(9, 10, 11, 1)}, + Compound{5, "e", true, true, false, Ogre::ColourValue(12, 13, 14, 1)}}; + + std::array cloudFirstTypes; + cloudFirstTypes[0] = types[0].id; + cloudFirstTypes[1] = types[4].id; + + setCloudsAndRunInitial(types); + + // Find the cloud entities + const auto clouds = findClouds(); + + CHECK(clouds.size() == 18); + + CompoundCloudComponent* cloudGroup1AtOrigin = nullptr; + CompoundCloudComponent* cloudGroup2AtOrigin = nullptr; + + for(auto* cloud : clouds) { + + if(cloud->getPosition() != Float3(0, 0, 0)) + continue; + + if(cloudFirstTypes[0] == cloud->getCompoundId1()) { + + CHECK(!cloudGroup1AtOrigin); + cloudGroup1AtOrigin = cloud; + + } else if(cloudFirstTypes[1] == cloud->getCompoundId1()) { + + CHECK(!cloudGroup2AtOrigin); + cloudGroup2AtOrigin = cloud; + } + } + + REQUIRE(cloudGroup1AtOrigin); + REQUIRE(cloudGroup2AtOrigin); + + const auto centerCoords = CompoundCloudSystem::convertWorldToCloudLocal( + Float3(0, 0, 0), Float3(0, 0, 0)); + + // Spawn clouds one by one and make sure they went to the right place + world.GetCompoundCloudSystem().addCloud(3, 10, Float3(0, 0, 0)); + + CHECK(cloudGroup1AtOrigin->amountAvailable(3, std::get<0>(centerCoords), + std::get<1>(centerCoords), 1) == 10); + + + world.GetCompoundCloudSystem().addCloud(4, 12, Float3(0, 0, 0)); + + CHECK(cloudGroup1AtOrigin->amountAvailable(4, std::get<0>(centerCoords), + std::get<1>(centerCoords), 1) == 12); + + world.GetCompoundCloudSystem().addCloud(1, 13, Float3(0, 0, 0)); + + CHECK(cloudGroup1AtOrigin->amountAvailable(1, std::get<0>(centerCoords), + std::get<1>(centerCoords), 1) == 13); + + world.GetCompoundCloudSystem().addCloud(2, 14, Float3(0, 0, 0)); + + CHECK(cloudGroup1AtOrigin->amountAvailable(2, std::get<0>(centerCoords), + std::get<1>(centerCoords), 1) == 14); + + // Second group + world.GetCompoundCloudSystem().addCloud(5, 15, Float3(0, 0, 0)); - // SECTION("Moving CLOUD_WIDTH * 1.5 units") {} + CHECK(cloudGroup2AtOrigin->amountAvailable(5, std::get<0>(centerCoords), + std::get<1>(centerCoords), 1) == 15); } From 0a3e4cb7d81db473dfa245ce078e79e40c6953cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henri=20Hyyryl=C3=A4inen?= Date: Sun, 27 Jan 2019 17:38:51 +0200 Subject: [PATCH 13/42] Changed the non-release text to be development as I think that's nicer --- src/ThriveGame.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ThriveGame.cpp b/src/ThriveGame.cpp index b3aa2239fcd..5edfd828ff9 100644 --- a/src/ThriveGame.cpp +++ b/src/ThriveGame.cpp @@ -163,7 +163,7 @@ class ThriveGame::Implementation { ThriveGame::ThriveGame() { #ifndef MAKE_RELEASE - LOG_INFO("Enabling cheats because this is a non-release build"); + LOG_INFO("Enabling cheats because this is a development build"); m_cheatsEnabled = true; #endif // MAKE_RELEASE @@ -186,7 +186,7 @@ std::string { return "Thrive " GAME_VERSIONS #ifndef MAKE_RELEASE - " (non-release)" + " (development)" #endif ; } From 17856a40a3b59e520cb5e8a6d2177eac4c125518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henri=20Hyyryl=C3=A4inen?= Date: Wed, 30 Jan 2019 19:27:52 +0200 Subject: [PATCH 14/42] Put the editor button update when entering to the right place --- scripts/microbe_stage/microbe_editor/microbe_editor.as | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/microbe_stage/microbe_editor/microbe_editor.as b/scripts/microbe_stage/microbe_editor/microbe_editor.as index a60c6007f10..3d213c2121b 100644 --- a/scripts/microbe_stage/microbe_editor/microbe_editor.as +++ b/scripts/microbe_stage/microbe_editor/microbe_editor.as @@ -70,7 +70,6 @@ class MicrobeEditor{ //! This is called each time the editor is entered so this needs to properly reset state void init() { - updateGuiButtonStatus(checkIsNucleusPresent()); gridSceneNode = hudSystem.world.CreateEntity(); auto node = hudSystem.world.Create_RenderNode(gridSceneNode); node.Scale = Float3(HEX_SIZE, 1, HEX_SIZE); @@ -131,6 +130,9 @@ class MicrobeEditor{ LOG_INFO("Starting microbe editor with: " + editedMicrobe.length() + " organelles in the microbe"); + // Update GUI buttons now that we have correct organelles + updateGuiButtonStatus(checkIsNucleusPresent()); + // Reset to cytoplasm if nothing is selected if(activeActionName == ""){ LOG_INFO("Selecting cytoplasm"); From 2bcfa23c91495b9e08dbfb336c7dea039e4707d0 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Sun, 27 Jan 2019 10:06:20 -0600 Subject: [PATCH 15/42] Swapped ammonia and sulfide colors as they were wrong. --- .../SimulationParameters/MicrobeStage/Compounds.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/SimulationParameters/MicrobeStage/Compounds.json b/scripts/SimulationParameters/MicrobeStage/Compounds.json index 3ada35d96f1..4cc5fc50dcd 100644 --- a/scripts/SimulationParameters/MicrobeStage/Compounds.json +++ b/scripts/SimulationParameters/MicrobeStage/Compounds.json @@ -19,9 +19,9 @@ "isUseful": true, "isEnvironmental": false, "colour": { - "r": 0.6, - "g": 0.7, - "b": 0.2 + "r": 1.0, + "g": 0.4, + "b": 0.1 } }, @@ -45,9 +45,9 @@ "isUseful": false, "isEnvironmental": false, "colour": { - "r": 1.0, - "g": 0.4, - "b": 0.1 + "r": 0.6, + "g": 0.7, + "b": 0.2 } }, From 0daad6cde7ad64e9d75c361aa46d8f7d4a891a59 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Sun, 27 Jan 2019 13:54:01 -0600 Subject: [PATCH 16/42] doubled hide time for win text so that people actually have time to read it. --- scripts/gui/microbe_hud.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gui/microbe_hud.mjs b/scripts/gui/microbe_hud.mjs index 3e159265140..3c5d4da71ea 100644 --- a/scripts/gui/microbe_hud.mjs +++ b/scripts/gui/microbe_hud.mjs @@ -425,7 +425,7 @@ function checkGeneration (generation, population){ document.getElementById("winBody").style.display = "inline-block"; document.getElementById("winContainer").style.display = "inline-block"; wonOnce = true; - setTimeout(hideWinText, 7000); + setTimeout(hideWinText, 14000); } } From a803c9032126b0e2a29e903f52b936b55853f3e6 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Sun, 27 Jan 2019 16:55:37 -0600 Subject: [PATCH 17/42] There is now an Iron Ions bar. Which gets filled up when you gather iron. --- scripts/gui/microbe_hud.mjs | 7 +++++++ scripts/gui/thrive_gui.html | 15 ++++++++++++++- scripts/gui/thrive_style.css | 8 ++++++++ scripts/microbe_stage/microbe_stage_hud.as | 13 +++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/scripts/gui/microbe_hud.mjs b/scripts/gui/microbe_hud.mjs index 3c5d4da71ea..9893c011d82 100644 --- a/scripts/gui/microbe_hud.mjs +++ b/scripts/gui/microbe_hud.mjs @@ -493,4 +493,11 @@ function updateMicrobeHUDBars(values){ document.getElementById("microbeHUDPlayerHydrogenSulfideBar").style.width = common.barHelper(values.compoundHydrogenSulfide, values.HydrogenSulfideMax); + document.getElementById("microbeHUDPlayerIron").textContent = + values.compoundIron.toFixed(1); + document.getElementById("microbeHUDPlayerIronMax").textContent = + values.IronMax; + document.getElementById("microbeHUDPlayerIronBar").style.width = + common.barHelper(values.compoundIron, values.IronMax); + } diff --git a/scripts/gui/thrive_gui.html b/scripts/gui/thrive_gui.html index 615fbfe7992..265a11e29fc 100644 --- a/scripts/gui/thrive_gui.html +++ b/scripts/gui/thrive_gui.html @@ -251,7 +251,20 @@ - + + +
+
+
+
+
Iron Ions
+
+ 0 / + 0 +
+
+
+
diff --git a/scripts/gui/thrive_style.css b/scripts/gui/thrive_style.css index be1a60e5c95..5bd06bb9487 100644 --- a/scripts/gui/thrive_style.css +++ b/scripts/gui/thrive_style.css @@ -476,6 +476,14 @@ video { background-color: #a02355; } +#IronIcon { + background-image: url("../../Textures/gui/bevel/Iron.png"); +} + +#microbeHUDPlayerIronBar { + background-color: #b7410e; +} + #HealthIcon { background-image: url("../../Textures/gui/bevel/Hitpoints.png"); } diff --git a/scripts/microbe_stage/microbe_stage_hud.as b/scripts/microbe_stage/microbe_stage_hud.as index 5564f1c7efe..552f88b3d82 100644 --- a/scripts/microbe_stage/microbe_stage_hud.as +++ b/scripts/microbe_stage/microbe_stage_hud.as @@ -74,6 +74,10 @@ class MicrobeStageHudSystem : ScriptSystem{ this.hydrogenSulfideVolume = SimulationParameters::compoundRegistry().getTypeData( this.hydrogenSulfideId).volume; + this.ironId = SimulationParameters::compoundRegistry().getTypeId("iron"); + this.ironVolume = SimulationParameters::compoundRegistry().getTypeData( + this.ironId).volume; + } void handleAmbientSound() @@ -160,6 +164,9 @@ class MicrobeStageHudSystem : ScriptSystem{ const auto oxytoxyAmount = bag.getCompoundAmount(oxytoxyId); const auto maxOxytoxy = microbeComponent.capacity; + const auto ironAmount = bag.getCompoundAmount(ironId); + const auto maxIron = microbeComponent.capacity; + // Write data vars.AddValue(ScriptSafeVariableBlock("compoundPhosphate", phosphateAmount)); vars.AddValue(ScriptSafeVariableBlock("PhosphateMax", maxPhosphate)); @@ -178,6 +185,9 @@ class MicrobeStageHudSystem : ScriptSystem{ vars.AddValue(ScriptSafeVariableBlock("compoundOxytoxy", oxytoxyAmount)); vars.AddValue(ScriptSafeVariableBlock("OxytoxyMax", maxOxytoxy)); + + vars.AddValue(ScriptSafeVariableBlock("compoundIron", ironAmount)); + vars.AddValue(ScriptSafeVariableBlock("IronMax", maxIron)); } // Fire it off so that the GUI scripts will get it and update the GUI state @@ -398,6 +408,9 @@ class MicrobeStageHudSystem : ScriptSystem{ CompoundId oxytoxyId; float oxytoxyVolume; + CompoundId ironId; + float ironVolume; + } From cded168a893f8687bb4a794c7bae1f699bd7aba5 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Sun, 27 Jan 2019 18:19:09 -0600 Subject: [PATCH 18/42] Added new organelle for respirating iron, you can also add it in the editor, added process: Iron CHemolithotrophy --- .../MicrobeStage/BioProcesses.json | 13 +++++++++ scripts/gui/microbe_editor.mjs | 4 +++ scripts/gui/thrive_gui.html | 28 +++++++++++++++++++ scripts/gui/thrive_style.css | 9 ++++++ .../microbe_editor/microbe_editor.as | 1 + scripts/microbe_stage/organelle_table.as | 25 +++++++++++++++++ scripts/microbe_stage/species_system.as | 6 +++- 7 files changed, 85 insertions(+), 1 deletion(-) diff --git a/scripts/SimulationParameters/MicrobeStage/BioProcesses.json b/scripts/SimulationParameters/MicrobeStage/BioProcesses.json index 2bea03ce98e..ba5b36f3690 100644 --- a/scripts/SimulationParameters/MicrobeStage/BioProcesses.json +++ b/scripts/SimulationParameters/MicrobeStage/BioProcesses.json @@ -110,5 +110,18 @@ "outputs": { "glucose": 0.33 } + }, + + "iron_chemolithoautotrophy": { + "name": "Iron Chemolithoautotrophy", + + "inputs": { + "carbondioxide": 0.09, + "iron": 1.0 + }, + + "outputs": { + "atp": 10.0 + } } } diff --git a/scripts/gui/microbe_editor.mjs b/scripts/gui/microbe_editor.mjs index 408bc803cfc..d486079e533 100644 --- a/scripts/gui/microbe_editor.mjs +++ b/scripts/gui/microbe_editor.mjs @@ -52,6 +52,10 @@ const organelleSelectionElements = [ element: document.getElementById("addChemoSynthisizingProteins"), organelle: "chemoSynthisizingProteins" }, + { + element: document.getElementById("addRusticyanin"), + organelle: "rusticyanin" + }, { element: document.getElementById("addFlagellum"), organelle: "flagellum" diff --git a/scripts/gui/thrive_gui.html b/scripts/gui/thrive_gui.html index 265a11e29fc..7907a69d24b 100644 --- a/scripts/gui/thrive_gui.html +++ b/scripts/gui/thrive_gui.html @@ -487,6 +487,34 @@
Toxin Vacuole
70 MP
Bioluminescent Vacuole
N/A MP + + + Chromatophores

Cost: 25 mutation points

+ Performs Process: Chromatophore Photosynthesis
(0.09 CO2 -> 0.33 glucose)/Second (Depending On Environmental C02)
+ Performs Process: Glycolysis
(0.125 glucose -> 5 ATP)/Second (Depending On Environmental C02)

+ Storage Space: 10

+ Coloured, membrane-associated vesicles used by various prokaryotes perform photosynthesis. + Chromatophores contain bacteriochlorophyll pigments and carotenoids.
+
Chromatophores
25 MP + + + ChemosynthisizingProteins

Cost: 20 mutation points

+ Performs Process: Bacterial Chemosynthesis
(1 CO2 + 1 Hydrogen Sulfide -> 1 Glucose)/Second (Depending On Environmental C02)
+ Performs Process: Glycolysis
(0.125 glucose -> 5 ATP)/Second

+ Storage Space: 20

+ Small membrane-associated structures that convert the noxious soup containing hydrogen + sulfide from hydrothermal vents into usable energy in the form of glucose.
+
Chemosynthisizing Proteins
20 MP + + + + Rusticyanin

Cost: 20 mutation points

+ Performs Process: Iron Chemolithotrophy
(0.09 CO2 + 1 Iron Ion -> 10 ATP)/Second (Depending On Environmental C02)
+ Storage Space: 5

+ Siderophores and Rusticyanin for storing and using iron ions and carbon from atmospheric carbon dioxide to produce ATP. + Iron Chemolithotrophy is a process by which organisms obtain their energy from the oxidation of reduced inorganic ions. +
+
Rusticyanin
20 MP diff --git a/scripts/gui/thrive_style.css b/scripts/gui/thrive_style.css index 5bd06bb9487..1a76af88e4a 100644 --- a/scripts/gui/thrive_style.css +++ b/scripts/gui/thrive_style.css @@ -1266,6 +1266,15 @@ video { background-image: url("../../Textures/gui/bevel/ChemoproteinsIcon.png"); } +#RusticyaninIcon { + position: relative; + left: calc(50% - 30px); + width: 60px; + height: 60px; + background-size: contain; + background-image: url("../../Textures/gui/bevel/ChemoproteinsIcon.png"); +} + #PilusIcon { position: relative; left: calc(50% - 30px); diff --git a/scripts/microbe_stage/microbe_editor/microbe_editor.as b/scripts/microbe_stage/microbe_editor/microbe_editor.as index 3d213c2121b..db08a0eae85 100644 --- a/scripts/microbe_stage/microbe_editor/microbe_editor.as +++ b/scripts/microbe_stage/microbe_editor/microbe_editor.as @@ -63,6 +63,7 @@ class MicrobeEditor{ {"chromatophors", PlacementFunctionType(this.addOrganelle)}, {"metabolosome", PlacementFunctionType(this.addOrganelle)}, {"chemoSynthisizingProteins", PlacementFunctionType(this.addOrganelle)}, + {"rusticyanin", PlacementFunctionType(this.addOrganelle)}, {"remove", PlacementFunctionType(this.removeOrganelle)} }; } diff --git a/scripts/microbe_stage/organelle_table.as b/scripts/microbe_stage/organelle_table.as index 0b8da35cccb..ce6f7476133 100644 --- a/scripts/microbe_stage/organelle_table.as +++ b/scripts/microbe_stage/organelle_table.as @@ -677,6 +677,31 @@ void setupOrganelles(){ _addOrganelleToTable(Organelle(nitrogenFixationProtein)); + // Rusticyanin + auto rusticyanin = OrganelleParameters("rusticyanin"); + + rusticyanin.mass = 0.1; + rusticyanin.gene = "f"; + rusticyanin.mesh = "chemoproteins.mesh"; + rusticyanin.chanceToCreate = 0.5f; + rusticyanin.prokaryoteChance = 1; + rusticyanin.mpCost = 20; + rusticyanin.initialComposition = { + {"phosphates", 1}, + {"ammonia", 1} + }; + rusticyanin.components = { + processorOrganelleFactory(1.0f), + storageOrganelleFactory(5.0f) + }; + rusticyanin.processes = { + TweakedProcess("iron_chemolithoautotrophy", 1) + }; + rusticyanin.hexes = { + Int2(0, 0), + }; + + _addOrganelleToTable(Organelle(rusticyanin)); // ------------------------------------ // // Setup the organelle letters setupOrganelleLetters(); diff --git a/scripts/microbe_stage/species_system.as b/scripts/microbe_stage/species_system.as index d4c336cc09b..652449b0750 100644 --- a/scripts/microbe_stage/species_system.as +++ b/scripts/microbe_stage/species_system.as @@ -703,7 +703,7 @@ class Species{ // respiratory Proteins, or Oxy Toxy Producing Proteins, also pure cytoplasm // aswell for variety. //TODO when chemosynthesis is added add a protein for that aswell - switch(GetEngine().GetRandom().GetNumber(1,7)) + switch(GetEngine().GetRandom().GetNumber(1,8)) { case 1: stringCode = getOrganelleDefinition("protoplasm").gene; @@ -723,6 +723,10 @@ class Species{ case 6: stringCode = getOrganelleDefinition("nitrogenFixationProteins").gene; break; + case 7: + stringCode = getOrganelleDefinition("rusticyanin").gene; + stringCode += getOrganelleDefinition("protoplasm").gene; + break; default: stringCode = getOrganelleDefinition("protoplasm").gene; break; From a64a7a8614c6c43f2c33a52aa7378c1b0979d49b Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Mon, 28 Jan 2019 12:59:16 -0600 Subject: [PATCH 19/42] when you die now your cell gets reset and it disabled the editor button (so that you cant be cheesy and get to the editor, then die, then enter the editor after you respawn) buffed iron respiration Cytoplasm is now the same mass as a nucleus. (so that the cytoplasm you start with acts like a nucleus) --- .../MicrobeStage/BioProcesses.json | 2 +- scripts/gui/microbe_hud.mjs | 12 ++++++++++++ scripts/gui/thrive_gui.html | 10 +++++----- scripts/microbe_stage/microbe_operations.as | 5 +++++ scripts/microbe_stage/microbe_stage_hud.as | 13 +++++++++++++ scripts/microbe_stage/organelle_table.as | 2 +- 6 files changed, 37 insertions(+), 7 deletions(-) diff --git a/scripts/SimulationParameters/MicrobeStage/BioProcesses.json b/scripts/SimulationParameters/MicrobeStage/BioProcesses.json index ba5b36f3690..f212037ccde 100644 --- a/scripts/SimulationParameters/MicrobeStage/BioProcesses.json +++ b/scripts/SimulationParameters/MicrobeStage/BioProcesses.json @@ -117,7 +117,7 @@ "inputs": { "carbondioxide": 0.09, - "iron": 1.0 + "iron": 0.5 }, "outputs": { diff --git a/scripts/gui/microbe_hud.mjs b/scripts/gui/microbe_hud.mjs index 9893c011d82..9845d866587 100644 --- a/scripts/gui/microbe_hud.mjs +++ b/scripts/gui/microbe_hud.mjs @@ -91,6 +91,9 @@ export function runMicrobeHUDSetup(){ // Event that enables the editor button Leviathan.OnGeneric("PlayerReadyToEnterEditor", onReadyToEnterEditor); + // Event that disabled the editor button + Leviathan.OnGeneric("PlayerDiedBeforeEnter", onResetEditor); + // Add listner for sucide button document.getElementById("suicideButton").addEventListener("click", killPlayerCell, true); @@ -152,6 +155,15 @@ export function onReadyToEnterEditor(){ } +//! Disabled the editor button +export function onResetEditor(){ + + // Disable + document.getElementById("microbeToEditorButton").classList.add("DisabledButton"); + readyToEdit = false; +} + + function onCompoundPanelClicked() { common.playButtonPressSound(); diff --git a/scripts/gui/thrive_gui.html b/scripts/gui/thrive_gui.html index 7907a69d24b..72bbfc201db 100644 --- a/scripts/gui/thrive_gui.html +++ b/scripts/gui/thrive_gui.html @@ -508,11 +508,11 @@ - Rusticyanin

Cost: 20 mutation points

- Performs Process: Iron Chemolithotrophy
(0.09 CO2 + 1 Iron Ion -> 10 ATP)/Second (Depending On Environmental C02)
- Storage Space: 5

- Siderophores and Rusticyanin for storing and using iron ions and carbon from atmospheric carbon dioxide to produce ATP. - Iron Chemolithotrophy is a process by which organisms obtain their energy from the oxidation of reduced inorganic ions. + Rusticyanin

Cost: 20 mutation points

+ Performs Process: Iron Chemolithotrophy
(0.09 CO2 + 0.5 Iron Ion -> 10 ATP)/Second (Depending On Environmental C02)
+ Storage Space: 5

+ Siderophores and Rusticyanin for storing and using iron ions and carbon from atmospheric carbon dioxide to produce ATP. + Iron Chemolithotrophy is a process by which organisms obtain their energy from the oxidation of reduced inorganic ions.
Rusticyanin
20 MP diff --git a/scripts/microbe_stage/microbe_operations.as b/scripts/microbe_stage/microbe_operations.as index 9e0fbfa6a55..805d48507fc 100644 --- a/scripts/microbe_stage/microbe_operations.as +++ b/scripts/microbe_stage/microbe_operations.as @@ -295,6 +295,11 @@ void respawnPlayer(CellStageWorld@ world) // Reset membrane color to fix the bug that made membranes sometimes red after you respawn. MicrobeOperations::applyMembraneColour(world, playerEntity); + //If you died before entering the editor disable that + microbeComponent.reproductionStage = 0; + hideReproductionDialog(world); + // Reset the player cell to be the same as the species template + Species::restoreOrganelleLayout(world, playerEntity, microbeComponent, playerSpecies); } // Decrease the population by 20 diff --git a/scripts/microbe_stage/microbe_stage_hud.as b/scripts/microbe_stage/microbe_stage_hud.as index 552f88b3d82..20a429504e7 100644 --- a/scripts/microbe_stage/microbe_stage_hud.as +++ b/scripts/microbe_stage/microbe_stage_hud.as @@ -286,6 +286,14 @@ class MicrobeStageHudSystem : ScriptSystem{ } } + void hideReproductionDialog(){ + reproductionDialogOpened = false; + GenericEvent@ event = GenericEvent("PlayerDiedBeforeEnter"); + GetEngine().GetEventHandler().CallEvent(event); + } + + + void suicideButtonClicked(){ // getComponent("gui_sounds", this.gameState, SoundSourceComponent).playSound("button-hover-click"); if(boolean2 == false){ @@ -809,6 +817,11 @@ void showReproductionDialog(GameWorld@ world){ showReproductionDialog(); } +void hideReproductionDialog(GameWorld@ world){ + cast(world.GetScriptSystem("MicrobeStageHudSystem")). + hideReproductionDialog(); +} + void showMessage(const string &in msg){ LOG_INFO(msg + " (note, in-game messages currently disabled)"); //auto messagePanel = Engine.currentGameState().rootGUIWindow().getChild("MessagePanel") diff --git a/scripts/microbe_stage/organelle_table.as b/scripts/microbe_stage/organelle_table.as index ce6f7476133..735f37ae4de 100644 --- a/scripts/microbe_stage/organelle_table.as +++ b/scripts/microbe_stage/organelle_table.as @@ -288,7 +288,7 @@ void setupOrganelles(){ // Cytoplasm auto cytoplasmParameters = OrganelleParameters("cytoplasm"); - cytoplasmParameters.mass = 0.1; + cytoplasmParameters.mass = 0.7; cytoplasmParameters.gene = "Y"; cytoplasmParameters.mesh = ""; //it's an empty hex cytoplasmParameters.chanceToCreate = 1; From eddd88ae3d013fefcae18e2b145f35a881f9c37d Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Tue, 29 Jan 2019 13:39:08 -0600 Subject: [PATCH 20/42] changed variable name sin movement organelle to make more sense --- .../organelle_components/movement_organelle.as | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/microbe_stage/organelle_components/movement_organelle.as b/scripts/microbe_stage/organelle_components/movement_organelle.as index 1066481b112..162d7df41ae 100644 --- a/scripts/microbe_stage/organelle_components/movement_organelle.as +++ b/scripts/microbe_stage/organelle_components/movement_organelle.as @@ -7,11 +7,11 @@ // See organelle_component.as for more information about the // organelle component methods and the arguments they receive. -// Calculate the momentum of the movement organelle based on angle towards nucleus +// Calculate the momentum of the movement organelle based on angle towards middle of cell Float3 calculateForce(int q, int r, float momentum){ Float3 organelle = Hex::axialToCartesian(q, r); - Float3 nucleus = Hex::axialToCartesian(0, 0); - auto delta = nucleus - organelle; + Float3 middle = Hex::axialToCartesian(0, 0); + auto delta = middle - organelle; return delta.Normalize() * momentum; } @@ -42,9 +42,9 @@ class MovementOrganelle : OrganelleComponent{ this.force = calculateForce(q, r, this.force.X); this.organellePos = Hex::axialToCartesian(q, r); - Float3 nucleus = Hex::axialToCartesian(0, 0); + Float3 middle = Hex::axialToCartesian(0, 0); - auto delta = nucleus - organellePos; + auto delta = middle - organellePos; float angle = atan2(-delta.Z, delta.X); if(angle < 0){ @@ -176,9 +176,9 @@ class MovementOrganelle : OrganelleComponent{ // This is because GetExternalOrganelle only works after the membrane has initialized, // which happens on the next tick // This doesnt work properly - Float3 nucleus = Hex::axialToCartesian(0, 0); - auto delta = nucleus - organellePos; - const Float3 exit = nucleus - delta; + Float3 middle = Hex::axialToCartesian(0, 0); + auto delta = middle - organellePos; + const Float3 exit = middle - delta; auto membraneComponent = organelle.world.GetComponent_MembraneComponent(microbeEntity); auto membraneCoords = membraneComponent.GetExternalOrganelle(exit.X, exit.Z);; float angle = atan2(-delta.Z, delta.X); From 0e3758a0827e60a88caeb87673623449316c90b7 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Tue, 29 Jan 2019 13:42:20 -0600 Subject: [PATCH 21/42] cytoplasm is now only .1 mass again, however, set it up so that the game starts all cells out with a mass of .7 before adding all their organelles mass to compensate. --- scripts/microbe_stage/microbe_operations.as | 3 ++- scripts/microbe_stage/organelle_table.as | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/microbe_stage/microbe_operations.as b/scripts/microbe_stage/microbe_operations.as index 805d48507fc..12b4c062871 100644 --- a/scripts/microbe_stage/microbe_operations.as +++ b/scripts/microbe_stage/microbe_operations.as @@ -932,7 +932,8 @@ ObjectID spawnBacteria(CellStageWorld@ world, Float3 pos, const string &in speci void _applyMicrobeCollisionShape(CellStageWorld@ world, Physics@ rigidBody, MicrobeComponent@ microbeComponent, PhysicsShape@ shape) { - float mass = 0.f; + // This compensates for the lack of a nucleus for the player cell at the beginning and makes eukaryotes alot heavier. + float mass = 0.7f; // Organelles for(uint i = 0; i < microbeComponent.organelles.length(); ++i){ diff --git a/scripts/microbe_stage/organelle_table.as b/scripts/microbe_stage/organelle_table.as index 735f37ae4de..ce6f7476133 100644 --- a/scripts/microbe_stage/organelle_table.as +++ b/scripts/microbe_stage/organelle_table.as @@ -288,7 +288,7 @@ void setupOrganelles(){ // Cytoplasm auto cytoplasmParameters = OrganelleParameters("cytoplasm"); - cytoplasmParameters.mass = 0.7; + cytoplasmParameters.mass = 0.1; cytoplasmParameters.gene = "Y"; cytoplasmParameters.mesh = ""; //it's an empty hex cytoplasmParameters.chanceToCreate = 1; From 529c6652fa47cdf7df3a3addb925f1a154abdab7 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Tue, 29 Jan 2019 15:21:30 -0600 Subject: [PATCH 22/42] species with rusticyanin now start with some iron (not the player species though)(still need to figure out how to make that work) fixed typo --- scripts/microbe_stage/configs.as | 3 ++- scripts/microbe_stage/species_system.as | 27 +++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/scripts/microbe_stage/configs.as b/scripts/microbe_stage/configs.as index 884a67a5b0c..6035b743d8c 100644 --- a/scripts/microbe_stage/configs.as +++ b/scripts/microbe_stage/configs.as @@ -344,7 +344,8 @@ const dictionary STARTER_MICROBES = { {"ammonia", InitialCompound(0)}, {"phosphates", InitialCompound(0)}, {"hydrogensulfide", InitialCompound(0)}, - {"oxytoxy", InitialCompound(0)} + {"oxytoxy", InitialCompound(0)}, + {"iron", InitialCompound(0)} }, { OrganelleTemplatePlaced("cytoplasm", 0, 0, 0) diff --git a/scripts/microbe_stage/species_system.as b/scripts/microbe_stage/species_system.as index 652449b0750..b798e724c1e 100644 --- a/scripts/microbe_stage/species_system.as +++ b/scripts/microbe_stage/species_system.as @@ -247,6 +247,7 @@ string generateNameSection() return newName; } +// For normal microbes const dictionary DEFAULT_INITIAL_COMPOUNDS = { {"atp", InitialCompound(30,300)}, @@ -254,7 +255,20 @@ const dictionary DEFAULT_INITIAL_COMPOUNDS = {"ammonia", InitialCompound(30,100)}, {"phosphates", InitialCompound(0)}, {"hydrogensulfide", InitialCompound(0)}, - {"oxytoxy", InitialCompound(0)} + {"oxytoxy", InitialCompound(0)}, + {"iron", InitialCompound(0)} + }; + +// For iron phillic microbes +const dictionary DEFAULT_INITIAL_COMPOUNDS_IRON = + { + {"atp", InitialCompound(30,300)}, + {"glucose", InitialCompound(10,30)}, + {"ammonia", InitialCompound(30,100)}, + {"phosphates", InitialCompound(0)}, + {"hydrogensulfide", InitialCompound(0)}, + {"oxytoxy", InitialCompound(0)}, + {"iron", InitialCompound(30,300)} }; string randomSpeciesName() @@ -477,10 +491,19 @@ class Species{ @forWorld = world; auto organelles = positionOrganelles(stringCode); - + // If you have iron (f is the symbol for rusticyanin) + if (stringCode.findFirst('f') >= 0) + { + templateEntity = Species::createSpecies(forWorld, this.name, this.genus, this.epithet, + organelles, this.colour, this.isBacteria, this.speciesMembraneType, + DEFAULT_INITIAL_COMPOUNDS_IRON, this.aggression, this.fear, this.activity, this.focus); + } + else { templateEntity = Species::createSpecies(forWorld, this.name, this.genus, this.epithet, organelles, this.colour, this.isBacteria, this.speciesMembraneType, DEFAULT_INITIAL_COMPOUNDS, this.aggression, this.fear, this.activity, this.focus); + } + } // Delete a species From 17ebef54a53d3ad6ab4072a37f8739a40ca80ef7 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Wed, 30 Jan 2019 14:01:53 -0600 Subject: [PATCH 23/42] aded new giant iron model to the game, and altered all the shaders to comply with realism a bit. --- scripts/microbe_stage/setup.as | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/microbe_stage/setup.as b/scripts/microbe_stage/setup.as index b7a6b993180..27fd6ce1b08 100644 --- a/scripts/microbe_stage/setup.as +++ b/scripts/microbe_stage/setup.as @@ -659,8 +659,9 @@ ObjectID createIron(CellStageWorld@ world, Float3 pos) Ogre::Vector3(0,1,1))); renderNode.Node.setPosition(pos); string mesh=""; + int ironSize = 1; // There are four kinds - switch (GetEngine().GetRandom().GetNumber(0, 3)) + switch (GetEngine().GetRandom().GetNumber(0, 4)) { case 0: mesh="iron_01.mesh"; @@ -674,6 +675,10 @@ ObjectID createIron(CellStageWorld@ world, Float3 pos) case 3: mesh="iron_04.mesh"; break; + case 4: + mesh="iron_05.mesh"; + ironSize=8; + break; } auto model = world.Create_Model(ironEntity, renderNode.Node, mesh); // Need to set the tint @@ -681,7 +686,7 @@ ObjectID createIron(CellStageWorld@ world, Float3 pos) auto rigidBody = world.Create_Physics(ironEntity, position); auto body = rigidBody.CreatePhysicsBody(world.GetPhysicalWorld(), - world.GetPhysicalWorld().CreateSphere(1), 100, + world.GetPhysicalWorld().CreateSphere(ironSize),100, //iron world.GetPhysicalMaterial("iron")); From 30fb773b32f5c6aaf4c09cf261e239e0ee2a05ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henri=20Hyyryl=C3=A4inen?= Date: Wed, 30 Jan 2019 19:50:46 +0200 Subject: [PATCH 24/42] Updated style guide to emphasize clang format and manual squashing possibility --- doc/style_guide.md | 123 ++++++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 58 deletions(-) diff --git a/doc/style_guide.md b/doc/style_guide.md index fbb966a13a4..e1d50a208f0 100644 --- a/doc/style_guide.md +++ b/doc/style_guide.md @@ -1,14 +1,14 @@ Code Style Guide ================ -To maintain a consistent coding style, contributors should follow the rules -outlined on this page. This style guide is separated into four parts: common +To maintain a consistent coding style, contributors should follow the rules +outlined on this page. This style guide is separated into four parts: common rules, rules specific for C++, rules specific for AngelScript and guidelines for using git. -The style rules are intended to increase readability of the source code. The -most important rule of all is: **Use common sense**. If you have to break -some rules to make the code more readable (and not just for you, but for +The style rules are intended to increase readability of the source code. The +most important rule of all is: **Use common sense**. If you have to break +some rules to make the code more readable (and not just for you, but for everyone who has to read your code), break it. Common (Both C++ and AngelScript) @@ -17,11 +17,11 @@ Common (Both C++ and AngelScript) - Indentation is 4 spaces - Names (that includes variables, functions and classes) should be descriptive. - Avoid abbreviations. Do not shorten variable names just to save key strokes, + Avoid abbreviations. Do not shorten variable names just to save key strokes, it will be read far more often than it will be written. -- Variables and functions are camelCase with leading lower case. Classes are - CamelCase with leading upper case. Constants are CONSTANT_CASE with +- Variables and functions are camelCase with leading lower case. Classes are + CamelCase with leading upper case. Constants are CONSTANT_CASE with underscores. - Filenames are lower_case with underscores. The reason for this is @@ -34,26 +34,25 @@ Common (Both C++ and AngelScript) C++ --- +- Format your code with [clang-format](clang_format.md) this is the + official formatting and most important thing to consider. If you + don't automatic checks on your code will fail. + - Macros are CONSTANT_CASE - Header files end in .h, source files in .cpp -- Header files should begin with `#pragma once`. Old-style header +- Header files should begin with `#pragma once`. Old-style header guards (with `ifdef`) are discouraged because they are very verbose and the pragma is understood by all relevant compilers. - -- Format your code with [clang-format](clang_format.md) - -- Opening braces go in the same line as the control statement, closing braces - are aligned below the first character of the opening control statement - Keep header files minimal. Ideally, they show only functions / classes that are useful to other code. All internal helper functions / classes should be declared and defined in the source file. - All classes and their public and protected members should be documented by - doxygen comments in the header file. If the function's purpose is clear - from the name and its parameters (which should be the usual case), the + doxygen comments in the header file. If the function's purpose is clear + from the name and its parameters (which should be the usual case), the comment can be very basic and only serves to shut up doxygen warnings about undocumented stuff. @@ -61,19 +60,21 @@ C++ you wrote the function like this (and, sometimes more importantly, why you didn't go another way). -- Member variables of classes are prefixed with \p m_. This is to - differentiate them from local or global variables when using their +- Empty lines are encouraged between blocks of code to improve readability. + +- Member variables of classes are prefixed with \p m_. This is to + differentiate them from local or global variables when using their unqualified name (without `this->`) inside member functions. The prefix can be omitted for very simple structs if they don't have member functions and serve only as data container. -(- When calling member functions from another member function, their names are - qualified with `this->` to differentiate them from global non-member - functions.) +- When calling member functions from another member function, their names may be + qualified with `this->` to differentiate them from global non-member + functions. This rule is not enforced. -- Function signatures are formatted like the clang-format options file makes them to be formatted - -- For non-trivial classes that would pull in a lot of other headers, use the pimpl idiom to hide implem entation details and only include the ton of headers in the .cpp file. +- For non-trivial classes that would pull in a lot of other headers, + use the pimpl idiom to hide implementation details and only include + the ton of headers in the .cpp file. ```cpp // In the header: @@ -92,12 +93,12 @@ C++ ~MyClass(); private: - + struct Implementation; std::unique_ptr m_impl; }; ``` - + ```cpp // In the source file: @@ -112,24 +113,24 @@ C++ MyClass::~MyClass() {} // Define destructor ``` - -- Try to avoid include statements inside header files unless - absolutely necessary. Prefer forward declarations and put the - include inside the source file instead. And use the pimpl idiom if - this cannot be avoided and the headers are large. -- Prefer C++11's `using` over `typedef`. With the `using` keyword, type +- Try to avoid include statements inside header files. Prefer forward + declarations and put the include inside the source file instead. And + use the pimpl idiom if this cannot be avoided and the headers are + large. + +- Use C++11's `using` over `typedef`. With the `using` keyword, type aliases look more like familiar variable assignment, with no ambiguity as to which is the newly defined type name. -- Virtual member functions overridden in derived classes are marked with the - C++11 `override` keyword. This will (correctly) cause a compile time error - when the function signature in the base class changes and the programmer +- Virtual member functions overridden in derived classes are marked with the + C++11 `override` keyword. This will (correctly) cause a compile time error + when the function signature in the base class changes and the programmer forgot to update the derived class. - Classes not intended as base classes are marked with the `final` keyword like this: - + ```cpp class MyClass final { // ... @@ -147,7 +148,7 @@ C++ #include #include - + #include #include @@ -160,18 +161,16 @@ C++ AngelScript ----------- -- A class's public data members are *not* prefixed by `m_`, unlike C++. - -(This is because in AngelScript, all member variables are accessed with their qualified - names (like `this.memberVariable`), so there is no need to mark them.) +- A class's public data members don't need to be prefixed by `m_`, unlike C++. - A class's private data members and functions are declared `private` (everything is public by default) and optionally prefixed with an underscore. This is a convention adopted from Python's PEP8 style - guide. + guide. This same rule may also be used in C++. -- Doxygen does not support AngelScript natively, but for consistency's sake, AngelScript - classes and functions are still documented with doxygen style comments. +- Doxygen does not support AngelScript natively, but for consistency's + sake, AngelScript classes and functions are still documented with + doxygen style comments. - For consistency with C++ adding semicolons after class declarations is recommended, but not an error if omitted. This is one of the @@ -181,9 +180,11 @@ AngelScript Git --- -- Do not work in the master branch, always create a private feature branch - if you want to edit something - +- Do not work in the master branch, always create a private feature + branch if you want to edit something. Even when working with a fork + this is recommended to reduce problems with subsequent pull + requests. + - If you don't have access to the main repository yet (you will be granted access after your first accepted pull request) fork the Thrive repository and work in your fork and once done open a pull @@ -204,7 +205,10 @@ Git - When the master branch is updated, you should usually keep your feature branch as-is. If you really need the new features from master, do a merge. Or if there is a merge conflict preventing your - pull request from being merged. + pull request from being merged. Quite often the master branch needs + to be merged in before merging a pull request. For this it is + cleaner if the pull request is rebased onto master, but this is not + required. - When a feature branch is done, open a pull request on GitHub so that others can review it. Chances are that during this review, there will still be @@ -215,13 +219,16 @@ Git done (take note people accepting pull requests) from the Github accept pull request button, hit the arrow to the right side and select "merge and squash". Bigger feature branches that are dozens - of commits from multiple people will be merged normally to attribute - all of the authors on Github feeds. - -- For maintainers: When manually squashing GitHub (which is something - you should avoid) requires a merge commit to recognize the merging - of a pull request. A "git merge --squash" does not create a merge - commit and will leave the pull request's branch "dangling". To make - GitHub properly reflect the merge, follow the procedure outlined in - the previous bullet point, then click the "Merge Pull Request" - button on GitHub (or do a normal "git merge". + of commits or from multiple people need to be manually squashed into + a few commits while keeping commits from different authors separate + in order to attribute all of the authors on Github feeds. These kind + of pull requests can be merged normally **if** all the commits in them + are "clean" to not dirty up master. + +- For maintainers: When manually merging (which is something you + should avoid) GitHub requires a merge commit to recognize the + merging of a pull request. A "git merge --squash" does not create a + merge commit and will leave the pull request's branch "dangling". To + make GitHub properly reflect the merge, follow the procedure + outlined in the previous bullet point, then click the "Merge Pull + Request" button on GitHub (or do a normal "git merge"). From a0166f70e2003e018a230649d2e104efcb9953df Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Wed, 30 Jan 2019 14:54:37 -0600 Subject: [PATCH 25/42] increased size for collision for big iron --- scripts/microbe_stage/setup.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/microbe_stage/setup.as b/scripts/microbe_stage/setup.as index 27fd6ce1b08..625f048804d 100644 --- a/scripts/microbe_stage/setup.as +++ b/scripts/microbe_stage/setup.as @@ -677,7 +677,7 @@ ObjectID createIron(CellStageWorld@ world, Float3 pos) break; case 4: mesh="iron_05.mesh"; - ironSize=8; + ironSize=10; break; } auto model = world.Create_Model(ironEntity, renderNode.Node, mesh); From 4b8512dedb260d9ccf2d53cabe4d1643026bfab7 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Fri, 1 Feb 2019 13:34:42 -0600 Subject: [PATCH 26/42] removed free-floating chloroplasts --- scripts/microbe_stage/setup.as | 37 ---------------------------------- 1 file changed, 37 deletions(-) diff --git a/scripts/microbe_stage/setup.as b/scripts/microbe_stage/setup.as index 625f048804d..5b410746da6 100644 --- a/scripts/microbe_stage/setup.as +++ b/scripts/microbe_stage/setup.as @@ -610,38 +610,6 @@ ObjectID createToxin(CellStageWorld@ world, Float3 pos) return toxinEntity; } -ObjectID createChloroplast(CellStageWorld@ world, Float3 pos) -{ - // Chloroplasts - ObjectID chloroplastEntity = world.CreateEntity(); - - auto position = world.Create_Position(chloroplastEntity, pos, - Ogre::Quaternion(Ogre::Degree(GetEngine().GetRandom().GetNumber(0, 360)), - Ogre::Vector3(0,1,1))); - - auto renderNode = world.Create_RenderNode(chloroplastEntity); - renderNode.Scale = Float3(1, 1, 1); - renderNode.Marked = true; - renderNode.Node.setOrientation(Ogre::Quaternion( - Ogre::Degree(GetEngine().GetRandom().GetNumber(0, 360)), - Ogre::Vector3(0,1,1))); - renderNode.Node.setPosition(pos); - auto model = world.Create_Model(chloroplastEntity, renderNode.Node, "chloroplast.mesh"); - // Need to set the tint - model.GraphicalObject.setCustomParameter(1, Ogre::Vector4(1, 1, 1, 1)); - - auto rigidBody = world.Create_Physics(chloroplastEntity, position); - auto body = rigidBody.CreatePhysicsBody(world.GetPhysicalWorld(), - world.GetPhysicalWorld().CreateSphere(1), 1, - world.GetPhysicalMaterial("floatingOrganelle")); - - body.ConstraintMovementAxises(); - - rigidBody.JumpTo(position); - - return chloroplastEntity; -} - ObjectID createIron(CellStageWorld@ world, Float3 pos) { // Chloroplasts @@ -736,11 +704,6 @@ void setupFloatingOrganelles(CellStageWorld@ world){ LOG_INFO("setting up free floating organelles"); SpawnSystem@ spawnSystem = world.GetSpawnSystem(); - // chloroplasts - const auto chloroId = spawnSystem.addSpawnType( - @createChloroplast, DEFAULT_SPAWN_DENSITY, - MICROBE_SPAWN_RADIUS); - // toxins const auto toxinId = spawnSystem.addSpawnType( @createToxin, DEFAULT_SPAWN_DENSITY, From 101fa378440411fe129ac18099cf3dace920882a Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Sat, 2 Feb 2019 14:47:54 -0600 Subject: [PATCH 27/42] Iron no longer spawns as a normal cloud (because it needs to come from iron chunks instead), remove dnowq useless comments, made each iron chunk spawn a cloud (temporary) --- .../MicrobeStage/Biomes.json | 60 +------------------ scripts/microbe_stage/setup.as | 4 ++ src/microbe_stage/compound_cloud_system.cpp | 10 ++-- 3 files changed, 12 insertions(+), 62 deletions(-) diff --git a/scripts/SimulationParameters/MicrobeStage/Biomes.json b/scripts/SimulationParameters/MicrobeStage/Biomes.json index 59f57d9c141..83e6a70f4e5 100644 --- a/scripts/SimulationParameters/MicrobeStage/Biomes.json +++ b/scripts/SimulationParameters/MicrobeStage/Biomes.json @@ -42,12 +42,6 @@ "dissolved": 0.0 }, - "iron": { - "amount": 325000, - "density": 0.00002, - "dissolved": 0.0 - }, - "oxygen": { "amount": 0, "density": 0.0, @@ -105,12 +99,6 @@ "dissolved": 0.0 }, - "iron": { - "amount": 325000, - "density": 0.00002, - "dissolved": 0.0 - }, - "oxygen": { "amount": 0, "density": 0.0, @@ -166,13 +154,7 @@ "density": 0.00002, "dissolved": 0.0 }, - - "iron": { - "amount": 325000, - "density": 0.00002, - "dissolved": 0.0 - }, - + "oxygen": { "amount": 0, "density": 0.0, @@ -226,13 +208,7 @@ "density": 0.00002, "dissolved": 0.0 }, - - "iron": { - "amount": 325000, - "density": 0.00002, - "dissolved": 0.0 - }, - + "oxygen": { "amount": 0, "density": 0.0, @@ -288,12 +264,6 @@ "dissolved": 0.0 }, - "iron": { - "amount": 325000, - "density": 0.00002, - "dissolved": 0.0 - }, - "oxygen": { "amount": 0, "density": 0.0, @@ -349,12 +319,6 @@ "dissolved": 0.0 }, - "iron": { - "amount": 325000, - "density": 0.00002, - "dissolved": 0.0 - }, - "oxygen": { "amount": 0, "density": 0.0, @@ -410,12 +374,6 @@ "dissolved": 0.0 }, - "iron": { - "amount": 325000, - "density": 0.00002, - "dissolved": 0.0 - }, - "oxygen": { "amount": 0, "density": 0.0, @@ -472,13 +430,7 @@ "density": 0.00002, "dissolved": 0.0 }, - - "iron": { - "amount": 325000, - "density": 0.00002, - "dissolved": 0.0 - }, - + "oxygen": { "amount": 0, "density": 0.0, @@ -536,12 +488,6 @@ "dissolved": 0.0 }, - "iron": { - "amount": 325000, - "density": 0.00002, - "dissolved": 0.0 - }, - "oxygen": { "amount": 0, "density": 0.0, diff --git a/scripts/microbe_stage/setup.as b/scripts/microbe_stage/setup.as index 5b410746da6..3c600939e33 100644 --- a/scripts/microbe_stage/setup.as +++ b/scripts/microbe_stage/setup.as @@ -648,6 +648,10 @@ ObjectID createIron(CellStageWorld@ world, Float3 pos) ironSize=10; break; } + + + world.GetCompoundCloudSystem().addCloud(SimulationParameters::compoundRegistry().getTypeId("iron"), 325000, Float3(pos.X, 0, pos.Z)); + auto model = world.Create_Model(ironEntity, renderNode.Node, mesh); // Need to set the tint model.GraphicalObject.setCustomParameter(1, Ogre::Vector4(1, 1, 1, 1)); diff --git a/src/microbe_stage/compound_cloud_system.cpp b/src/microbe_stage/compound_cloud_system.cpp index 03781591a4c..a20b08f271e 100644 --- a/src/microbe_stage/compound_cloud_system.cpp +++ b/src/microbe_stage/compound_cloud_system.cpp @@ -42,7 +42,7 @@ CompoundCloudComponent::CompoundCloudComponent(CompoundCloudSystem& owner, m_textureName("cloud_" + std::to_string(++CloudTextureNumber)), m_owner(owner) { - LOG_INFO("got here"); + // LOG_INFO("got here"); if(!first) throw std::runtime_error( "CompoundCloudComponent needs at least one Compound type"); @@ -51,8 +51,8 @@ CompoundCloudComponent::CompoundCloudComponent(CompoundCloudSystem& owner, m_color1 = Ogre::Vector4(first->colour.r, first->colour.g, first->colour.b, 1.0f); m_compoundId1 = first->id; - LOG_INFO("cloud colors are " + std::to_string(first->colour.r)); - LOG_INFO("cloud first compound ID is " + std::to_string(m_compoundId1)); + // LOG_INFO("cloud colors are " + std::to_string(first->colour.r)); + // LOG_INFO("cloud first compound ID is " + std::to_string(m_compoundId1)); if(second) { @@ -925,8 +925,8 @@ void CompoundCloudSystem::initializeCloud(CompoundCloudComponent& cloud, Ogre::SceneManager* scene) { - LOG_INFO( - "cloud first compound ID is " + std::to_string(cloud.m_compoundId1)); + // LOG_INFO( + // "cloud first compound ID is " + std::to_string(cloud.m_compoundId1)); LOG_INFO("Initializing a new compound cloud entity"); // All the densities From 2c56cf3ad9584bf451d5d7f28c92b82dc7934864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henri=20Hyyryl=C3=A4inen?= Date: Sat, 2 Feb 2019 23:13:24 +0200 Subject: [PATCH 28/42] Removed the now unneeded logs from the cloud system --- src/microbe_stage/compound_cloud_system.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/microbe_stage/compound_cloud_system.cpp b/src/microbe_stage/compound_cloud_system.cpp index a20b08f271e..8def5d704ee 100644 --- a/src/microbe_stage/compound_cloud_system.cpp +++ b/src/microbe_stage/compound_cloud_system.cpp @@ -42,7 +42,6 @@ CompoundCloudComponent::CompoundCloudComponent(CompoundCloudSystem& owner, m_textureName("cloud_" + std::to_string(++CloudTextureNumber)), m_owner(owner) { - // LOG_INFO("got here"); if(!first) throw std::runtime_error( "CompoundCloudComponent needs at least one Compound type"); @@ -51,8 +50,6 @@ CompoundCloudComponent::CompoundCloudComponent(CompoundCloudSystem& owner, m_color1 = Ogre::Vector4(first->colour.r, first->colour.g, first->colour.b, 1.0f); m_compoundId1 = first->id; - // LOG_INFO("cloud colors are " + std::to_string(first->colour.r)); - // LOG_INFO("cloud first compound ID is " + std::to_string(m_compoundId1)); if(second) { @@ -694,8 +691,6 @@ void // Initial spawning if everything is empty if(m_managedClouds.empty()) { - LOG_INFO("CompoundCloudSystem doing initial spawning"); - m_cloudGridCenter = Float3(0, 0, 0); const auto requiredCloudPositions{ @@ -925,10 +920,6 @@ void CompoundCloudSystem::initializeCloud(CompoundCloudComponent& cloud, Ogre::SceneManager* scene) { - // LOG_INFO( - // "cloud first compound ID is " + std::to_string(cloud.m_compoundId1)); - LOG_INFO("Initializing a new compound cloud entity"); - // All the densities if(cloud.m_compoundId1 != NULL_COMPOUND) { cloud.m_density1.resize(CLOUD_SIMULATION_WIDTH, From 1e2dc678f376d156ca12eefceb407c383cf4aa67 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Sat, 2 Feb 2019 16:42:01 -0600 Subject: [PATCH 29/42] You can no longer delete your last organelle in the editor (to stop people from deleting their entire cell when they dont have a nucleus) --- scripts/microbe_stage/microbe_editor/microbe_editor.as | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/microbe_stage/microbe_editor/microbe_editor.as b/scripts/microbe_stage/microbe_editor/microbe_editor.as index db08a0eae85..2ae12085306 100644 --- a/scripts/microbe_stage/microbe_editor/microbe_editor.as +++ b/scripts/microbe_stage/microbe_editor/microbe_editor.as @@ -744,7 +744,8 @@ class MicrobeEditor{ PlacedOrganelle@ organelle = cast(organelleHere); if(organelleHere !is null){ - if(!(organelleHere.organelle.name == "nucleus")) { + // DOnt allow deletion of nucleus or the last organelle + if(!(organelleHere.organelle.name == "nucleus") && getMicrobeSize() > 1) { EditorAction@ action = EditorAction(ORGANELLE_REMOVE_COST, // redo We need data about the organelle we removed, and the location so we can "redo" it function(EditorAction@ action, MicrobeEditor@ editor){ From 87dad48129f66ca85635143e90647a82e15002e2 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Tue, 5 Feb 2019 15:48:38 -0600 Subject: [PATCH 30/42] Started implementing CompoundVenterSystem and CompoundVenterComponent ran clang format Continued work on compoundVenterSystem and component CompoundVenter now also uses position components Position component is now deleted properly when the venter is deleted Compound venter system now uses cell stage world --- src/engine/component_types.h | 1 + src/microbe_stage/compound_venter_system.cpp | 43 ++++++++++ src/microbe_stage/compound_venter_system.h | 84 ++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 src/microbe_stage/compound_venter_system.cpp create mode 100644 src/microbe_stage/compound_venter_system.h diff --git a/src/engine/component_types.h b/src/engine/component_types.h index 6f5c0b949c8..5311d147e6f 100644 --- a/src/engine/component_types.h +++ b/src/engine/component_types.h @@ -21,6 +21,7 @@ enum class THRIVE_COMPONENT : uint16_t { ABSORBER, TIMED_LIFE, PROPERTIES, + COMPOUND_VENTER, // TODO: check is this needed for anything // INVALID diff --git a/src/microbe_stage/compound_venter_system.cpp b/src/microbe_stage/compound_venter_system.cpp new file mode 100644 index 00000000000..1fe8dd05277 --- /dev/null +++ b/src/microbe_stage/compound_venter_system.cpp @@ -0,0 +1,43 @@ +#include +#include +#include +#include + +#include "engine/serialization.h" + +#include "general/thrive_math.h" +#include "simulation_parameters.h" + +#include "microbe_stage/compound_venter_system.h" +#include "microbe_stage/process_system.h" + +#include "generated/cell_stage_world.h" +#include + +using namespace thrive; + +void + CompoundVenterSystem::Run(CellStageWorld& world) +{ + if(!world.GetNetworkSettings().IsAuthoritative) + return; + + for(auto& value : CachedComponents.GetIndex()) { + + CompoundBagComponent& bag = std::get<0>(*value.second); + CompoundVenterComponent& venter = std::get<1>(*value.second); + Leviathan::Position& position = std::get<2>(*value.second); + + venter.ventCompound(position, + SimulationParameters::compoundRegistry.getTypeId("iron"), world); + } +} + +void + CompoundVenterComponent::ventCompound(Leviathan::Position& pos, + CompoundId compound, + CellStageWorld& world) +{ + world.GetCompoundCloudSystem().addCloud( + compound, 15000, pos.Members._Position); +} \ No newline at end of file diff --git a/src/microbe_stage/compound_venter_system.h b/src/microbe_stage/compound_venter_system.h new file mode 100644 index 00000000000..90f65695b7f --- /dev/null +++ b/src/microbe_stage/compound_venter_system.h @@ -0,0 +1,84 @@ +#pragma once +#include "engine/component_types.h" +#include "engine/typedefs.h" + +#include +#include +//#include +#include "process_system.h" +#include +#include + +namespace Leviathan { +class GameWorld; +} + +namespace thrive { + +class CellStageWorld; +class CompoundVenterComponent : public Leviathan::Component { +public: + CompoundVenterComponent(); + + double storageSpace; + double storageSpaceOccupied; + float x, y; + + REFERENCE_HANDLE_UNCOUNTED_TYPE(CompoundVenterComponent); + + static constexpr auto TYPE = + componentTypeConvert(THRIVE_COMPONENT::COMPOUND_VENTER); + + void + ventCompound(Leviathan::Position& pos, + CompoundId ourCompound, + CellStageWorld& world); +}; + +class CompoundVenterSystem + : public Leviathan::System> { +public: + /** + * @brief Updates the system + * @todo Make it releases a specific amount of compounds each second + */ + void + Run(CellStageWorld& world); + + void + CreateNodes( + const std::vector>& + firstdata, + const std::vector>& + seconddata, + const std::vector>& + thirdData, + const ComponentHolder& firstholder, + const ComponentHolder& secondholder, + const ComponentHolder& thirdHolder) + { + TupleCachedComponentCollectionHelper(CachedComponents, firstdata, + seconddata, thirdData, firstholder, secondholder, thirdHolder); + } + + void + DestroyNodes( + const std::vector>& + firstdata, + const std::vector>& + seconddata, + const std::vector>& + thirdData) + { + CachedComponents.RemoveBasedOnKeyTupleList(firstdata); + CachedComponents.RemoveBasedOnKeyTupleList(seconddata); + CachedComponents.RemoveBasedOnKeyTupleList(thirdData); + } + +protected: +private: + static constexpr double TIME_SCALING_FACTOR = 1000; +}; +} // namespace thrive \ No newline at end of file From 7ac0967b327ab148e3775af08b0f5168c6a68853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henri=20Hyyryl=C3=A4inen?= Date: Sat, 9 Feb 2019 14:52:50 +0200 Subject: [PATCH 31/42] Added back the useful comment about moving the physics callbacks somewhere sensible --- scripts/microbe_stage/setup.as | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/microbe_stage/setup.as b/scripts/microbe_stage/setup.as index 3c600939e33..07497ab9c52 100644 --- a/scripts/microbe_stage/setup.as +++ b/scripts/microbe_stage/setup.as @@ -269,6 +269,10 @@ void onReturnFromEditor(CellStageWorld@ world) } +// +// TODO: also put these physics callback somewhere more sensible (maybe physics_callbacks.as?) +// + void cellHitFloatingOrganelle(GameWorld@ world, ObjectID firstEntity, ObjectID secondEntity) { // Determine which is the organelle From b435c7384f133630b019751d35d25bf82fced924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henri=20Hyyryl=C3=A4inen?= Date: Sat, 9 Feb 2019 15:06:06 +0200 Subject: [PATCH 32/42] Removed the unneeded includes --- src/microbe_stage/microbe_editor_key_handler.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/microbe_stage/microbe_editor_key_handler.cpp b/src/microbe_stage/microbe_editor_key_handler.cpp index a6ccf789f50..3dd5e78f637 100644 --- a/src/microbe_stage/microbe_editor_key_handler.cpp +++ b/src/microbe_stage/microbe_editor_key_handler.cpp @@ -1,13 +1,9 @@ #include "microbe_editor_key_handler.h" -#include "generated/microbe_editor_world.h" -#include "microbe_stage/simulation_parameters.h" - #include #include #include #include -#include using namespace thrive; From e05e5a2265e19f9a9cf761b9a33ff7ae2a3095ea Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Sun, 10 Feb 2019 12:44:18 -0600 Subject: [PATCH 33/42] Added the new system and components to ruby, and made sure it runs. venter component is now initialized properly, system is no longer visible to scripts, and ventcompound now takes in an amount. Iron now vents iron ions, however theres still alot of work left (eg, make it actually grab from the compondBagComponet when emitting, and only emit once a second or something like that) They now vent every second, and a smaller amount, so they look like they are dissolving now reudced scaling factor by 3 times in venter system removed silly log that i somehow placed there --- scripts/microbe_stage/setup.as | 6 ++-- src/CMakeLists.txt | 2 ++ src/microbe_stage/compound_venter_system.cpp | 30 +++++++++++++------ src/microbe_stage/compound_venter_system.h | 6 ++-- .../generate_cell_stage_world.rb | 4 +++ src/scripting/script_initializer.cpp | 11 +++++++ 6 files changed, 44 insertions(+), 15 deletions(-) diff --git a/scripts/microbe_stage/setup.as b/scripts/microbe_stage/setup.as index 07497ab9c52..1f0dca2a921 100644 --- a/scripts/microbe_stage/setup.as +++ b/scripts/microbe_stage/setup.as @@ -616,7 +616,7 @@ ObjectID createToxin(CellStageWorld@ world, Float3 pos) ObjectID createIron(CellStageWorld@ world, Float3 pos) { - // Chloroplasts + // Iron ObjectID ironEntity = world.CreateEntity(); auto position = world.Create_Position(ironEntity, pos, @@ -654,8 +654,8 @@ ObjectID createIron(CellStageWorld@ world, Float3 pos) } - world.GetCompoundCloudSystem().addCloud(SimulationParameters::compoundRegistry().getTypeId("iron"), 325000, Float3(pos.X, 0, pos.Z)); - + world.Create_CompoundVenterComponent(ironEntity); + world.Create_CompoundBagComponent(ironEntity); auto model = world.Create_Model(ironEntity, renderNode.Node, mesh); // Need to set the tint model.GraphicalObject.setCustomParameter(1, Ogre::Vector4(1, 1, 1, 1)); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 94a66c626f0..5318108af09 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -51,6 +51,8 @@ set(GROUP_MICROBE_STAGE "microbe_stage/microbe_camera_system.h" "microbe_stage/process_system.cpp" "microbe_stage/process_system.h" + "microbe_stage/compound_venter_system.cpp" + "microbe_stage/compound_venter_system.h" "microbe_stage/simulation_parameters.cpp" "microbe_stage/simulation_parameters.h" "microbe_stage/spawn_system.cpp" diff --git a/src/microbe_stage/compound_venter_system.cpp b/src/microbe_stage/compound_venter_system.cpp index 1fe8dd05277..2c7e4d4baa8 100644 --- a/src/microbe_stage/compound_venter_system.cpp +++ b/src/microbe_stage/compound_venter_system.cpp @@ -16,28 +16,40 @@ using namespace thrive; + +// ------------------------------------ // +// CompoundVenterComponent +CompoundVenterComponent::CompoundVenterComponent() : Leviathan::Component(TYPE) +{} + void CompoundVenterSystem::Run(CellStageWorld& world) { if(!world.GetNetworkSettings().IsAuthoritative) return; - for(auto& value : CachedComponents.GetIndex()) { - - CompoundBagComponent& bag = std::get<0>(*value.second); - CompoundVenterComponent& venter = std::get<1>(*value.second); - Leviathan::Position& position = std::get<2>(*value.second); - - venter.ventCompound(position, - SimulationParameters::compoundRegistry.getTypeId("iron"), world); + const auto logicTime = Leviathan::TICKSPEED; + + timeSinceLastCycle++; + while(timeSinceLastCycle > TIME_SCALING_FACTOR) { + timeSinceLastCycle -= TIME_SCALING_FACTOR; + for(auto& value : CachedComponents.GetIndex()) { + CompoundBagComponent& bag = std::get<0>(*value.second); + CompoundVenterComponent& venter = std::get<1>(*value.second); + Leviathan::Position& position = std::get<2>(*value.second); + venter.ventCompound(position, + SimulationParameters::compoundRegistry.getTypeId("iron"), 5, + world); + } } } void CompoundVenterComponent::ventCompound(Leviathan::Position& pos, CompoundId compound, + double amount, CellStageWorld& world) { world.GetCompoundCloudSystem().addCloud( - compound, 15000, pos.Members._Position); + compound, amount * 1000, pos.Members._Position); } \ No newline at end of file diff --git a/src/microbe_stage/compound_venter_system.h b/src/microbe_stage/compound_venter_system.h index 90f65695b7f..30430a61f61 100644 --- a/src/microbe_stage/compound_venter_system.h +++ b/src/microbe_stage/compound_venter_system.h @@ -20,8 +20,6 @@ class CompoundVenterComponent : public Leviathan::Component { public: CompoundVenterComponent(); - double storageSpace; - double storageSpaceOccupied; float x, y; REFERENCE_HANDLE_UNCOUNTED_TYPE(CompoundVenterComponent); @@ -32,6 +30,7 @@ class CompoundVenterComponent : public Leviathan::Component { void ventCompound(Leviathan::Position& pos, CompoundId ourCompound, + double amount, CellStageWorld& world); }; @@ -79,6 +78,7 @@ class CompoundVenterSystem protected: private: - static constexpr double TIME_SCALING_FACTOR = 1000; + static constexpr double TIME_SCALING_FACTOR = 20; + int timeSinceLastCycle = 0; }; } // namespace thrive \ No newline at end of file diff --git a/src/microbe_stage/generate_cell_stage_world.rb b/src/microbe_stage/generate_cell_stage_world.rb index 2c8a0558420..db1e4defb63 100644 --- a/src/microbe_stage/generate_cell_stage_world.rb +++ b/src/microbe_stage/generate_cell_stage_world.rb @@ -21,6 +21,7 @@ generator.addInclude "microbe_stage/membrane_system.h" generator.addInclude "microbe_stage/compound_cloud_system.h" generator.addInclude "microbe_stage/process_system.h" +generator.addInclude "microbe_stage/compound_venter_system.h" generator.addInclude "microbe_stage/species_component.h" generator.addInclude "microbe_stage/spawn_system.h" generator.addInclude "microbe_stage/agent_cloud_system.h" @@ -36,6 +37,7 @@ "CellStageWorld", componentTypes: [ EntityComponent.new("ProcessorComponent", [ConstructorInfo.new([])]), EntityComponent.new("CompoundBagComponent", [ConstructorInfo.new([])]), + EntityComponent.new("CompoundVenterComponent", [ConstructorInfo.new([])]), EntityComponent.new("SpeciesComponent", [ConstructorInfo.new([ Variable.new("name", "std::string", memberaccess: "name", @@ -150,6 +152,8 @@ EntitySystem.new("ProcessSystem", ["CompoundBagComponent", "ProcessorComponent"], runtick: {group: 10, parameters: []}, visibletoscripts: true), + EntitySystem.new("CompoundVenterSystem", ["CompoundBagComponent", "CompoundVenterComponent", "Position"], + runtick: {group: 11, parameters: []}), EntitySystem.new("TimedLifeSystem", [], runtick: {group: 45, parameters: [ "ComponentTimedLifeComponent.GetIndex()" diff --git a/src/scripting/script_initializer.cpp b/src/scripting/script_initializer.cpp index 6b816a227fb..1d18c0db86b 100644 --- a/src/scripting/script_initializer.cpp +++ b/src/scripting/script_initializer.cpp @@ -431,6 +431,8 @@ bool static uint16_t ProcessorComponentTYPEProxy = static_cast(ProcessorComponent::TYPE); +static uint16_t CompoundVenterTYPEProxy = + static_cast(CompoundVenterComponent::TYPE); static uint16_t SpawnedComponentTYPEProxy = static_cast(SpawnedComponent::TYPE); static uint16_t AgentCloudComponentTYPEProxy = @@ -504,6 +506,15 @@ bool asMETHOD(ProcessorComponent, getCapacity), asCALL_THISCALL) < 0) { ANGELSCRIPT_REGISTERFAIL; } + // ------------------------------------ // + if(engine->RegisterObjectType( + "CompoundVenterComponent", 0, asOBJ_REF | asOBJ_NOCOUNT) < 0) { + ANGELSCRIPT_REGISTERFAIL; + } + + if(!bindComponentTypeId( + engine, "CompoundVenterComponent", &CompoundVenterTYPEProxy)) + return false; // ------------------------------------ // if(engine->RegisterObjectType( From 1cc8c37e362e6b9f62a795d4b08a0282ae684d54 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Tue, 12 Feb 2019 15:50:17 -0600 Subject: [PATCH 34/42] Seperated auto-evo step into its own callable function. And made it run auto-evo every time you enter the editor. --- .../microbe_editor/microbe_editor.as | 3 +- scripts/microbe_stage/species_system.as | 237 +++++++++--------- 2 files changed, 116 insertions(+), 124 deletions(-) diff --git a/scripts/microbe_stage/microbe_editor/microbe_editor.as b/scripts/microbe_stage/microbe_editor/microbe_editor.as index 2ae12085306..76980186888 100644 --- a/scripts/microbe_stage/microbe_editor/microbe_editor.as +++ b/scripts/microbe_stage/microbe_editor/microbe_editor.as @@ -133,7 +133,8 @@ class MicrobeEditor{ // Update GUI buttons now that we have correct organelles updateGuiButtonStatus(checkIsNucleusPresent()); - + //force an auto-evo step + cast(GetThriveGame().getCellStage().GetScriptSystem("SpeciesSystem")).doAutoEvoStep(); // Reset to cytoplasm if nothing is selected if(activeActionName == ""){ LOG_INFO("Selecting cytoplasm"); diff --git a/scripts/microbe_stage/species_system.as b/scripts/microbe_stage/species_system.as index b798e724c1e..05a1a02110c 100644 --- a/scripts/microbe_stage/species_system.as +++ b/scripts/microbe_stage/species_system.as @@ -966,6 +966,7 @@ class SpeciesSystem : ScriptSystem{ resetAutoEvo(); } + void Run() { //LOG_INFO("autoevo running"); @@ -973,155 +974,146 @@ class SpeciesSystem : ScriptSystem{ timeSinceLastCycle++; while(this.timeSinceLastCycle > SPECIES_SIM_INTERVAL){ - LOG_INFO("Processing Auto-evo Step"); - this.timeSinceLastCycle -= SPECIES_SIM_INTERVAL; - bool ranEventThisStep=false; - - // Every 8 steps or so do a cambrian explosion style - // Event, this should increase variablility significantly - if(GetEngine().GetRandom().GetNumber(0, 200) <= 25){ - LOG_INFO("Cambrian Explosion"); - ranEventThisStep = true; - // TODO: add a notification for when this happens - doCambrianExplosion(); - } - - // Various mass extinction events - // Only run one "big event" per turn - if(species.length() > MAX_SPECIES+MAX_BACTERIA && !ranEventThisStep){ - - LOG_INFO("Mass extinction time"); - // F to pay respects: TODO: add a notification for when this happens - ranEventThisStep = true; - doMassExtinction(); - } - - // Add some variability, this is a less deterministic mass - // Extinction eg, a meteor, etc. - if(GetEngine().GetRandom().GetNumber(0, 1000) == 1 && !ranEventThisStep){ - LOG_INFO("Black swan event"); - ranEventThisStep = true; - // F to pay respects: TODO: add a notification for when this happens - doMassExtinction(); - } + doAutoEvoStep(); + } + } - // Super extinction event - if(GetEngine().GetRandom().GetNumber(0, 1000) == 1 && !ranEventThisStep){ - LOG_INFO("Great Dying"); - ranEventThisStep = true; - // Do mass extinction code then devastate all species, - //this should extinct quite a few of the ones that - //arent doing well. *Shudders* - doMassExtinction(); - doDevestation(); - } + void doAutoEvoStep(){ + LOG_INFO("Processing Auto-evo Step"); + this.timeSinceLastCycle -= SPECIES_SIM_INTERVAL; + bool ranEventThisStep=false; + // Every 8 steps or so do a cambrian explosion style + // Event, this should increase variablility significantly + if(GetEngine().GetRandom().GetNumber(0, 200) <= 25){ + LOG_INFO("Cambrian Explosion"); + ranEventThisStep = true; + // TODO: add a notification for when this happens + doCambrianExplosion(); + } - auto numberOfSpecies = species.length(); - for(uint i = 0; i < numberOfSpecies; i++){ - // Traversing the population backwards to avoid - // "chopping down the branch i'm sitting in" - auto index = numberOfSpecies - 1 - i; - auto currentSpecies = species[index]; - currentSpecies.updatePopulation(); - auto population = currentSpecies.population; - LOG_INFO(currentSpecies.name + " " + currentSpecies.population); + // Various mass extinction events + // Only run one "big event" per turn + if(species.length() > MAX_SPECIES+MAX_BACTERIA && !ranEventThisStep){ + LOG_INFO("Mass extinction time"); + // F to pay respects: TODO: add a notification for when this happens + ranEventThisStep = true; + doMassExtinction(); + } - bool ranSpeciesEvent = false; + // Add some variability, this is a less deterministic mass + // Extinction eg, a meteor, etc. + if(GetEngine().GetRandom().GetNumber(0, 1000) == 1 && !ranEventThisStep){ + LOG_INFO("Black swan event"); + ranEventThisStep = true; + // F to pay respects: TODO: add a notification for when this happens + doMassExtinction(); + } + // Super extinction event + if(GetEngine().GetRandom().GetNumber(0, 1000) == 1 && !ranEventThisStep){ + LOG_INFO("Great Dying"); + ranEventThisStep = true; + // Do mass extinction code then devastate all species, + //this should extinct quite a few of the ones that + //arent doing well. *Shudders* + doMassExtinction(); + doDevestation(); + } - // This is also just to shake things up occassionally - // Cambrian Explosion - if ( currentSpecies.population > 0 && - GetEngine().GetRandom().GetNumber(0, 10) <= 2) - { - // P to pat back: TODO: add a notification for when this happens - LOG_INFO(currentSpecies.name + " is diversifying!"); - currentSpecies.boom(); - LOG_INFO(currentSpecies.name+" population is now "+ - currentSpecies.population); - ranSpeciesEvent=true; - } + auto numberOfSpecies = species.length(); + for(uint i = 0; i < numberOfSpecies; i++){ + // Traversing the population backwards to avoid + // "chopping down the branch i'm sitting in" + auto index = numberOfSpecies - 1 - i; + auto currentSpecies = species[index]; + currentSpecies.updatePopulation(); + auto population = currentSpecies.population; + LOG_INFO(currentSpecies.name + " " + currentSpecies.population); + bool ranSpeciesEvent = false; + // This is also just to shake things up occassionally + // Cambrian Explosion + if ( currentSpecies.population > 0 && + GetEngine().GetRandom().GetNumber(0, 10) <= 2) + { + // P to pat back: TODO: add a notification for when this happens + LOG_INFO(currentSpecies.name + " is diversifying!"); + currentSpecies.boom(); + LOG_INFO(currentSpecies.name+" population is now "+ + currentSpecies.population); + ranSpeciesEvent=true; + } // This is just to shake things up occassionally - if ( currentSpecies.population > 0 && + if ( currentSpecies.population > 0 && GetEngine().GetRandom().GetNumber(0, 10) <= 2 && !ranSpeciesEvent) - { + { // F to pay respects: TODO: add a notification for when this happens LOG_INFO(currentSpecies.name + " has been devestated by disease."); currentSpecies.devestate(); LOG_INFO(currentSpecies.name+" population is now "+ currentSpecies.population); ranSpeciesEvent=true; - } + } // 50% chance of splitting off two species instead of one - if(GetEngine().GetRandom().GetNumber(0, 10) <= 5 && ranSpeciesEvent == false && - currentSpecies.population >= MAX_POP_SIZE){ + if(GetEngine().GetRandom().GetNumber(0, 10) <= 5 && ranSpeciesEvent == false && + currentSpecies.population >= MAX_POP_SIZE){ - // To prevent ridiculous population numbers - currentSpecies.population=MAX_POP_SIZE; + // To prevent ridiculous population numbers + currentSpecies.population=MAX_POP_SIZE; + auto oldPop = currentSpecies.population; + auto newSpecies = Species(currentSpecies, world, + currentSpecies.isBacteria); - auto oldPop = currentSpecies.population; - auto newSpecies = Species(currentSpecies, world, - currentSpecies.isBacteria); - - if (newSpecies.isBacteria) - { - currentBacteriaAmount+=1; + if (newSpecies.isBacteria){ + currentBacteriaAmount+=1; } - else - { - currentEukaryoteAmount+=1; + else{ + currentEukaryoteAmount+=1; } - ranSpeciesEvent=true; - species.insertLast(newSpecies); - LOG_INFO("Species " + currentSpecies.name + - " split off several species, the first is:" + - newSpecies.name); - // Reset pop so we can split a second time - currentSpecies.population = oldPop; - } - - // Reproduction and mutation - if(currentSpecies.population >= MAX_POP_SIZE){ - - // To prevent ridiculous population numbers - currentSpecies.population=MAX_POP_SIZE; + ranSpeciesEvent=true; + species.insertLast(newSpecies); + LOG_INFO("Species " + currentSpecies.name + + " split off several species, the first is:" + + newSpecies.name); + // Reset pop so we can split a second time + currentSpecies.population = oldPop; + } - auto newSpecies = Species(currentSpecies, world, - currentSpecies.isBacteria); + // Reproduction and mutation + if(currentSpecies.population >= MAX_POP_SIZE){ + // To prevent ridiculous population numbers + currentSpecies.population=MAX_POP_SIZE; - if (newSpecies.isBacteria) - { - currentBacteriaAmount+=1; - } - else - { - currentEukaryoteAmount+=1; - } - species.insertLast(newSpecies); - LOG_INFO("Species " + currentSpecies.name + " split off a child species:" + - newSpecies.name); + auto newSpecies = Species(currentSpecies, world, + currentSpecies.isBacteria); + if (newSpecies.isBacteria){ + currentBacteriaAmount+=1; } + else{ + currentEukaryoteAmount+=1; + } + species.insertLast(newSpecies); + LOG_INFO("Species " + currentSpecies.name + " split off a child species:" + + newSpecies.name); + } - // Extinction, this is not an event since things with - // low population need to be killed off. - if(currentSpecies.population <= MIN_POP_SIZE){ - LOG_INFO("Species " + currentSpecies.name + " went extinct"); - currentSpecies.extinguish(); - species.removeAt(index); - // Tweak numbers here - if (currentSpecies.isBacteria) - { - currentBacteriaAmount-=1; - } - else - { - currentEukaryoteAmount-=1; - } + // Extinction, this is not an event since things with + // low population need to be killed off. + if(currentSpecies.population <= MIN_POP_SIZE){ + LOG_INFO("Species " + currentSpecies.name + " went extinct"); + currentSpecies.extinguish(); + species.removeAt(index); + // Tweak numbers here + if (currentSpecies.isBacteria){ + currentBacteriaAmount-=1; + } + else{ + currentEukaryoteAmount-=1; } } + } // These are kind of arbitray, we should pronbabbly make it less arbitrary // New species @@ -1137,7 +1129,6 @@ class SpeciesSystem : ScriptSystem{ createBacterium(); currentBacteriaAmount++; } - } } void Clear(){} From 571bdac0b748eb5a32404204b0041c40a23628df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henri=20Hyyryl=C3=A4inen?= Date: Mon, 11 Feb 2019 09:45:51 +0200 Subject: [PATCH 35/42] Removed strange sounding wording from the link to the style guide and added comment about recommended usage of branches --- README.md | 2 +- doc/setup_instructions.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 81f885e8fee..034006d9c93 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ both for guidelines on code formatting and git usage. And [AngelScript primer][asprimer] for scripting help. ### C++ Programmers -To compile Thrive yourself, you will not only need to follow the [setup instructions][setupguide]. +To compile Thrive yourself, you will need to follow the [setup instructions][setupguide]. Be sure to have a look at the [styleguide][styleguide], both for guidelines on code formatting and git usage. diff --git a/doc/setup_instructions.md b/doc/setup_instructions.md index 899e27e7644..53066abe5fa 100644 --- a/doc/setup_instructions.md +++ b/doc/setup_instructions.md @@ -174,7 +174,8 @@ graphical tool for reviewing the exact lines you have changed, but you can also commit on the command line) you can publish them to your fork with (assuming you used the master branch, when working with the main thrive repository you MUST create a different branch but when working -with a fork that isn't required): +with a fork that isn't required, but still strongly recommended as +making multiple pull requests with one branch is messy): ``` git push fork master From ae6bd685e4237bd9706acaf07791b1fbb0e74b27 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Tue, 12 Feb 2019 17:31:50 -0600 Subject: [PATCH 36/42] Large iron chunks now give out more iron ions(compound venter component can be customized now), Player cells now start with 3 iron, its now .175 iron for 10 ATP for chemolithotrophy for balance reasons, disabled log that was happening so often it caused lag Labled parts of name mutator so its easier to understand. --- .../MicrobeStage/BioProcesses.json | 2 +- scripts/microbe_stage/configs.as | 2 +- scripts/microbe_stage/microbe_operations.as | 3 ++- scripts/microbe_stage/setup.as | 5 +++++ scripts/microbe_stage/species_system.as | 9 +++++++++ src/microbe_stage/compound_venter_system.cpp | 18 +++++++++++++++--- src/microbe_stage/compound_venter_system.h | 8 +++++++- src/scripting/script_initializer.cpp | 13 +++++++++++++ 8 files changed, 53 insertions(+), 7 deletions(-) diff --git a/scripts/SimulationParameters/MicrobeStage/BioProcesses.json b/scripts/SimulationParameters/MicrobeStage/BioProcesses.json index f212037ccde..55d6082e212 100644 --- a/scripts/SimulationParameters/MicrobeStage/BioProcesses.json +++ b/scripts/SimulationParameters/MicrobeStage/BioProcesses.json @@ -117,7 +117,7 @@ "inputs": { "carbondioxide": 0.09, - "iron": 0.5 + "iron": 0.175 }, "outputs": { diff --git a/scripts/microbe_stage/configs.as b/scripts/microbe_stage/configs.as index 6035b743d8c..1e2be0268ce 100644 --- a/scripts/microbe_stage/configs.as +++ b/scripts/microbe_stage/configs.as @@ -345,7 +345,7 @@ const dictionary STARTER_MICROBES = { {"phosphates", InitialCompound(0)}, {"hydrogensulfide", InitialCompound(0)}, {"oxytoxy", InitialCompound(0)}, - {"iron", InitialCompound(0)} + {"iron", InitialCompound(3)} }, { OrganelleTemplatePlaced("cytoplasm", 0, 0, 0) diff --git a/scripts/microbe_stage/microbe_operations.as b/scripts/microbe_stage/microbe_operations.as index 12b4c062871..24b3decdc7a 100644 --- a/scripts/microbe_stage/microbe_operations.as +++ b/scripts/microbe_stage/microbe_operations.as @@ -699,7 +699,8 @@ void playSoundWithDistance(CellStageWorld@ world, const string &in soundPath, Ob "sound source"); } } else { - LOG_ERROR("Failed to create sound player"); + //this was happening so often it caused lag + //LOG_ERROR("Failed to create sound player"); } } } diff --git a/scripts/microbe_stage/setup.as b/scripts/microbe_stage/setup.as index 1f0dca2a921..0f2f34e7e17 100644 --- a/scripts/microbe_stage/setup.as +++ b/scripts/microbe_stage/setup.as @@ -632,6 +632,8 @@ ObjectID createIron(CellStageWorld@ world, Float3 pos) renderNode.Node.setPosition(pos); string mesh=""; int ironSize = 1; + // 5 is the default + float ironAmount = 3.0f; // There are four kinds switch (GetEngine().GetRandom().GetNumber(0, 4)) { @@ -650,11 +652,14 @@ ObjectID createIron(CellStageWorld@ world, Float3 pos) case 4: mesh="iron_05.mesh"; ironSize=10; + ironAmount=10.0f; break; } world.Create_CompoundVenterComponent(ironEntity); + // So that larger iron chunks give out more compounds + world.GetComponent_CompoundVenterComponent(ironEntity).setVentAmount(ironAmount); world.Create_CompoundBagComponent(ironEntity); auto model = world.Create_Model(ironEntity, renderNode.Node, mesh); // Need to set the tint diff --git a/scripts/microbe_stage/species_system.as b/scripts/microbe_stage/species_system.as index 05a1a02110c..7ad22f3f436 100644 --- a/scripts/microbe_stage/species_system.as +++ b/scripts/microbe_stage/species_system.as @@ -89,34 +89,40 @@ string mutateWord(string name){ switch (GetEngine().GetRandom().GetNumber(0,5)) { case 0: + //VC newVowel = GetEngine().GetRandom().GetNumber(0,vowels.length()-1); newConsonant = GetEngine().GetRandom().GetNumber(0,consonants.length()-1); newSyllable= ""+vowels.substr(newVowel, 1)+consonants.substr(newConsonant, 1); newName.insert(index, newSyllable); break; case 1: + //CV newVowel = GetEngine().GetRandom().GetNumber(0,vowels.length()-1); newConsonant = GetEngine().GetRandom().GetNumber(0,consonants.length()-1); newSyllable = ""+consonants.substr(newConsonant, 1)+vowels.substr(newVowel, 1); newName.insert(index, newSyllable); break; case 2: + //CC newConsonant = GetEngine().GetRandom().GetNumber(0,consonants.length()-1); newSyllable= ""+original+consonants.substr(newConsonant, 1); newName.insert(index, newSyllable); break; case 3: + //CC newConsonant = GetEngine().GetRandom().GetNumber(0,consonants.length()-1); newSyllable = ""+consonants.substr(newConsonant, 1)+original; newName.insert(index, newSyllable); break; case 4: + //CCV newVowel = GetEngine().GetRandom().GetNumber(0,vowels.length()-1); newConsonant = GetEngine().GetRandom().GetNumber(0,consonants.length()-1); newSyllable = original+consonants.substr(newConsonant, 1)+vowels.substr(newVowel, 1); newName.insert(index, newSyllable); break; case 5: + //VCC newVowel = GetEngine().GetRandom().GetNumber(0,vowels.length()-1); newConsonant = GetEngine().GetRandom().GetNumber(0,consonants.length()-1); newSyllable = vowels.substr(newVowel, 1)+consonants.substr(newConsonant, 1)+original; @@ -124,14 +130,17 @@ string mutateWord(string name){ break; } } + // If is vowel else { if(GetEngine().GetRandom().GetNumber(0,20) <= 10){ + //CVV int newConsonant = GetEngine().GetRandom().GetNumber(0,consonants.length()-1); int newVowel = GetEngine().GetRandom().GetNumber(0,vowels.length()-1); string newSyllable = ""+consonants.substr(newConsonant, 1)+vowels.substr(newVowel, 1)+original; newName.insert(index, newSyllable); } else { + //VVC int newConsonant = GetEngine().GetRandom().GetNumber(0,consonants.length()-1); int newVowel = GetEngine().GetRandom().GetNumber(0,vowels.length()-1); string newSyllable = ""+original+vowels.substr(newVowel, 1)+consonants.substr(newConsonant, 1); diff --git a/src/microbe_stage/compound_venter_system.cpp b/src/microbe_stage/compound_venter_system.cpp index 2c7e4d4baa8..2864bee9495 100644 --- a/src/microbe_stage/compound_venter_system.cpp +++ b/src/microbe_stage/compound_venter_system.cpp @@ -38,8 +38,8 @@ void CompoundVenterComponent& venter = std::get<1>(*value.second); Leviathan::Position& position = std::get<2>(*value.second); venter.ventCompound(position, - SimulationParameters::compoundRegistry.getTypeId("iron"), 5, - world); + SimulationParameters::compoundRegistry.getTypeId("iron"), + venter.ventAmount, world); } } } @@ -51,5 +51,17 @@ void CellStageWorld& world) { world.GetCompoundCloudSystem().addCloud( - compound, amount * 1000, pos.Members._Position); + compound, amount * 1000.0f, pos.Members._Position); +} + +void + CompoundVenterComponent::setVentAmount(float amount) +{ + this->ventAmount = amount; +} + +float + CompoundVenterComponent::getVentAmount() +{ + return this->ventAmount; } \ No newline at end of file diff --git a/src/microbe_stage/compound_venter_system.h b/src/microbe_stage/compound_venter_system.h index 30430a61f61..eecaa20fbea 100644 --- a/src/microbe_stage/compound_venter_system.h +++ b/src/microbe_stage/compound_venter_system.h @@ -21,7 +21,7 @@ class CompoundVenterComponent : public Leviathan::Component { CompoundVenterComponent(); float x, y; - + float ventAmount = 5.0f; REFERENCE_HANDLE_UNCOUNTED_TYPE(CompoundVenterComponent); static constexpr auto TYPE = @@ -32,6 +32,12 @@ class CompoundVenterComponent : public Leviathan::Component { CompoundId ourCompound, double amount, CellStageWorld& world); + + void + setVentAmount(float amount); + + float + getVentAmount(); }; class CompoundVenterSystem diff --git a/src/scripting/script_initializer.cpp b/src/scripting/script_initializer.cpp index 1d18c0db86b..b250a7a5197 100644 --- a/src/scripting/script_initializer.cpp +++ b/src/scripting/script_initializer.cpp @@ -516,6 +516,19 @@ bool engine, "CompoundVenterComponent", &CompoundVenterTYPEProxy)) return false; + if(engine->RegisterObjectMethod("CompoundVenterComponent", + "float getVentAmount()", + asMETHOD(CompoundVenterComponent, getVentAmount), + asCALL_THISCALL) < 0) { + ANGELSCRIPT_REGISTERFAIL; + } + + if(engine->RegisterObjectMethod("CompoundVenterComponent", + "void setVentAmount(float amount)", + asMETHOD(CompoundVenterComponent, setVentAmount), + asCALL_THISCALL) < 0) { + ANGELSCRIPT_REGISTERFAIL; + } // ------------------------------------ // if(engine->RegisterObjectType( "SpawnedComponent", 0, asOBJ_REF | asOBJ_NOCOUNT) < 0) { From 12a98d484917eb791c298e70e3e4d7d23f0f0999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henri=20Hyyryl=C3=A4inen?= Date: Wed, 13 Feb 2019 15:40:56 +0200 Subject: [PATCH 37/42] Made the wording feel less wrong to me --- doc/setup_instructions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/setup_instructions.md b/doc/setup_instructions.md index 53066abe5fa..42791245f51 100644 --- a/doc/setup_instructions.md +++ b/doc/setup_instructions.md @@ -1,7 +1,7 @@ What's this? ============ -This is the setup instructions for compiling Thrive. +These are the setup instructions for compiling Thrive. Important Note: If you run into any trouble with the setup scripts, please bring them up on the development discord or open a github issue. From 997a574636915f292bff81e5f7f310b9b4c43190 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Wed, 13 Feb 2019 12:09:03 -0600 Subject: [PATCH 38/42] Nitrogen fixation now relies on environmental oxygen and at max (if the atmosphere was 100% oxygen) would produce .5 ammonia from 5 atp a second. Fixed typos and made rusticyanin 45 mp cleaned up iron spawn code just a little bit. --- .../MicrobeStage/BioProcesses.json | 5 +- scripts/gui/thrive_gui.html | 46 +++++++++---------- scripts/microbe_stage/organelle_table.as | 2 +- scripts/microbe_stage/setup.as | 4 +- 4 files changed, 29 insertions(+), 28 deletions(-) diff --git a/scripts/SimulationParameters/MicrobeStage/BioProcesses.json b/scripts/SimulationParameters/MicrobeStage/BioProcesses.json index 55d6082e212..e0359718b7f 100644 --- a/scripts/SimulationParameters/MicrobeStage/BioProcesses.json +++ b/scripts/SimulationParameters/MicrobeStage/BioProcesses.json @@ -79,11 +79,12 @@ "name": "Nitrogen Fixing", "inputs": { - "atp": 0.5 + "oxygen": 1.0, + "atp": 5 }, "outputs": { - "ammonia": 0.1 + "ammonia": 0.5 } }, diff --git a/scripts/gui/thrive_gui.html b/scripts/gui/thrive_gui.html index 72bbfc201db..131fb9f3f58 100644 --- a/scripts/gui/thrive_gui.html +++ b/scripts/gui/thrive_gui.html @@ -466,8 +466,8 @@ Nitrogen Fixing Plastid

Cost: 80 mutation points

- Performs Process: Nitrogen Fixation
(0.5 ATP -> 0.1 Ammonia)/Second

- Allows for synthesis of ammonia from atmospheric nitrogen. For easier cell growth. + Performs Process: Nitrogen Fixation
(1 Oxygen + 5 ATP -> 0.5 Ammonia)/Second (Depending On Environmental Oxygen)

+ Allows for synthesis of ammonia from atmospheric nitrogen and oxygen. For easier cell growth.
Nitrogen Fixing Plastid
80 MP @@ -485,36 +485,36 @@ Allows for production and storage of OxytoxyNT which can be shot at enemy cells using E. The more of this organelle you have the faster your toxin fire rate aswell.
Toxin Vacuole
70 MP - -
Bioluminescent Vacuole
N/A MP + +
Bioluminescent Vacuole
N/A MP - Chromatophores

Cost: 25 mutation points

- Performs Process: Chromatophore Photosynthesis
(0.09 CO2 -> 0.33 glucose)/Second (Depending On Environmental C02)
- Performs Process: Glycolysis
(0.125 glucose -> 5 ATP)/Second (Depending On Environmental C02)

- Storage Space: 10

- Coloured, membrane-associated vesicles used by various prokaryotes perform photosynthesis. - Chromatophores contain bacteriochlorophyll pigments and carotenoids.
-
Chromatophores
25 MP - - - ChemosynthisizingProteins

Cost: 20 mutation points

- Performs Process: Bacterial Chemosynthesis
(1 CO2 + 1 Hydrogen Sulfide -> 1 Glucose)/Second (Depending On Environmental C02)
- Performs Process: Glycolysis
(0.125 glucose -> 5 ATP)/Second

- Storage Space: 20

- Small membrane-associated structures that convert the noxious soup containing hydrogen - sulfide from hydrothermal vents into usable energy in the form of glucose.
-
Chemosynthisizing Proteins
20 MP - + Chromatophores

Cost: 25 mutation points

+ Performs Process: Chromatophore Photosynthesis
(0.09 CO2 -> 0.33 glucose)/Second (Depending On Environmental C02)
+ Performs Process: Glycolysis
(0.125 glucose -> 5 ATP)/Second (Depending On Environmental C02)

+ Storage Space: 10

+ Coloured, membrane-associated vesicles used by various prokaryotes perform photosynthesis. + Chromatophores contain bacteriochlorophyll pigments and carotenoids. +
Chromatophores
25 MP + + + ChemosynthisizingProteins

Cost: 20 mutation points

+ Performs Process: Bacterial Chemosynthesis
(1 CO2 + 1 Hydrogen Sulfide -> 1 Glucose)/Second (Depending On Environmental C02)
+ Performs Process: Glycolysis
(0.125 glucose -> 5 ATP)/Second

+ Storage Space: 20

+ Small membrane-associated structures that convert the noxious soup containing hydrogen + sulfide from hydrothermal vents into usable energy in the form of glucose.
+
Chemosynthisizing Proteins
45 MP + - Rusticyanin

Cost: 20 mutation points

+ Rusticyanin

Cost: 45 mutation points

Performs Process: Iron Chemolithotrophy
(0.09 CO2 + 0.5 Iron Ion -> 10 ATP)/Second (Depending On Environmental C02)
Storage Space: 5

Siderophores and Rusticyanin for storing and using iron ions and carbon from atmospheric carbon dioxide to produce ATP. Iron Chemolithotrophy is a process by which organisms obtain their energy from the oxidation of reduced inorganic ions.
-
Rusticyanin
20 MP +
Rusticyanin
45 MP diff --git a/scripts/microbe_stage/organelle_table.as b/scripts/microbe_stage/organelle_table.as index ce6f7476133..f1a2b0bbc2e 100644 --- a/scripts/microbe_stage/organelle_table.as +++ b/scripts/microbe_stage/organelle_table.as @@ -685,7 +685,7 @@ void setupOrganelles(){ rusticyanin.mesh = "chemoproteins.mesh"; rusticyanin.chanceToCreate = 0.5f; rusticyanin.prokaryoteChance = 1; - rusticyanin.mpCost = 20; + rusticyanin.mpCost = 45; rusticyanin.initialComposition = { {"phosphates", 1}, {"ammonia", 1} diff --git a/scripts/microbe_stage/setup.as b/scripts/microbe_stage/setup.as index 0f2f34e7e17..a4f41525385 100644 --- a/scripts/microbe_stage/setup.as +++ b/scripts/microbe_stage/setup.as @@ -657,9 +657,9 @@ ObjectID createIron(CellStageWorld@ world, Float3 pos) } - world.Create_CompoundVenterComponent(ironEntity); + auto venter = world.Create_CompoundVenterComponent(ironEntity); // So that larger iron chunks give out more compounds - world.GetComponent_CompoundVenterComponent(ironEntity).setVentAmount(ironAmount); + venter.setVentAmount(ironAmount); world.Create_CompoundBagComponent(ironEntity); auto model = world.Create_Model(ironEntity, renderNode.Node, mesh); // Need to set the tint From 452be0a6322911da60f4115b353c5da81a4d1246 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Thu, 14 Feb 2019 16:28:57 -0600 Subject: [PATCH 39/42] Venter now only vents compounds the compound bag component has and takes compounds from the bag. If not, it skips them. Iron chunks' compound bag components now have an appropriate amount of iron ions for the venters, that takes about 1000 seconds to run out, and they do. ran formatter script plastid actually only costs 50, so fixed typo in editor. --- scripts/gui/thrive_gui.html | 2 +- scripts/microbe_stage/configs.as | 5 +++++ scripts/microbe_stage/setup.as | 6 +++++- src/microbe_stage/compound_venter_system.cpp | 15 +++++++++++---- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/scripts/gui/thrive_gui.html b/scripts/gui/thrive_gui.html index 131fb9f3f58..f13a47d4351 100644 --- a/scripts/gui/thrive_gui.html +++ b/scripts/gui/thrive_gui.html @@ -465,7 +465,7 @@
Chemoplast
45 MP - Nitrogen Fixing Plastid

Cost: 80 mutation points

+ Nitrogen Fixing Plastid

Cost: 50 mutation points

Performs Process: Nitrogen Fixation
(1 Oxygen + 5 ATP -> 0.5 Ammonia)/Second (Depending On Environmental Oxygen)

Allows for synthesis of ammonia from atmospheric nitrogen and oxygen. For easier cell growth.
diff --git a/scripts/microbe_stage/configs.as b/scripts/microbe_stage/configs.as index 1e2be0268ce..f7779579876 100644 --- a/scripts/microbe_stage/configs.as +++ b/scripts/microbe_stage/configs.as @@ -160,6 +160,11 @@ const float OXY_TOXY_DAMAGE = 10.0f; // Cooldown between agent emissions, in milliseconds. const uint AGENT_EMISSION_COOLDOWN = 2000; +// Iron amounts per chunk. +// big iron ejects ten per 20 clicks , so about 30 per second, so ill give it enough for 1000 seconds) +const double IRON_PER_BIG_CHUNK = 30000.0f; +// small iron ejects 3 per 20 clicks , so about 9 per second, so ill give it enough for 1000 seconds aswell +const double IRON_PER_SMALL_CHUNK = 9000.0f; //Auto Evo Values const int CREATURE_DEATH_POPULATION_LOSS = -60; const int CREATURE_KILL_POPULATION_GAIN = 50; diff --git a/scripts/microbe_stage/setup.as b/scripts/microbe_stage/setup.as index a4f41525385..4993e4b910a 100644 --- a/scripts/microbe_stage/setup.as +++ b/scripts/microbe_stage/setup.as @@ -634,6 +634,7 @@ ObjectID createIron(CellStageWorld@ world, Float3 pos) int ironSize = 1; // 5 is the default float ironAmount = 3.0f; + double ironBagAmount= IRON_PER_SMALL_CHUNK; // There are four kinds switch (GetEngine().GetRandom().GetNumber(0, 4)) { @@ -653,6 +654,7 @@ ObjectID createIron(CellStageWorld@ world, Float3 pos) mesh="iron_05.mesh"; ironSize=10; ironAmount=10.0f; + ironBagAmount=IRON_PER_BIG_CHUNK; break; } @@ -660,7 +662,9 @@ ObjectID createIron(CellStageWorld@ world, Float3 pos) auto venter = world.Create_CompoundVenterComponent(ironEntity); // So that larger iron chunks give out more compounds venter.setVentAmount(ironAmount); - world.Create_CompoundBagComponent(ironEntity); + auto bag = world.Create_CompoundBagComponent(ironEntity); + + bag.setCompound(SimulationParameters::compoundRegistry().getTypeId("iron"),ironBagAmount); auto model = world.Create_Model(ironEntity, renderNode.Node, mesh); // Need to set the tint model.GraphicalObject.setCustomParameter(1, Ogre::Vector4(1, 1, 1, 1)); diff --git a/src/microbe_stage/compound_venter_system.cpp b/src/microbe_stage/compound_venter_system.cpp index 2864bee9495..77bd1e9207a 100644 --- a/src/microbe_stage/compound_venter_system.cpp +++ b/src/microbe_stage/compound_venter_system.cpp @@ -36,10 +36,17 @@ void for(auto& value : CachedComponents.GetIndex()) { CompoundBagComponent& bag = std::get<0>(*value.second); CompoundVenterComponent& venter = std::get<1>(*value.second); - Leviathan::Position& position = std::get<2>(*value.second); - venter.ventCompound(position, - SimulationParameters::compoundRegistry.getTypeId("iron"), - venter.ventAmount, world); + // Loop through all the compounds in the storage bag and eject them + for(const auto& compound : bag.compounds) { + double compoundAmount = compound.second.amount; + CompoundId compoundId = compound.first; + if(venter.ventAmount <= compoundAmount) { + Leviathan::Position& position = std::get<2>(*value.second); + venter.ventCompound( + position, compoundId, venter.ventAmount, world); + bag.takeCompound(compoundId, venter.ventAmount); + } + } } } } From 3f68d820f11160e7cfa95ada36b91c48db970bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henri=20Hyyryl=C3=A4inen?= Date: Fri, 15 Feb 2019 19:33:18 +0200 Subject: [PATCH 40/42] Fixed broken organelle list after merge. Made preview in browser work again --- scripts/gui/microbe_hud.mjs | 3 ++ scripts/gui/thrive_gui.html | 61 +++++++++++++++++++------------------ 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/scripts/gui/microbe_hud.mjs b/scripts/gui/microbe_hud.mjs index 9845d866587..b98d879442e 100644 --- a/scripts/gui/microbe_hud.mjs +++ b/scripts/gui/microbe_hud.mjs @@ -107,6 +107,7 @@ export function runMicrobeHUDSetup(){ const oxytoxy = common.randomBetween(0, 10); const phosphate = common.randomBetween(0, 50); const hydrogenSulfide = common.randomBetween(0, 50); + const iron = common.randomBetween(0, 50); updateMicrobeHUDBars({ hitpoints: common.randomBetween(1, hp), maxHitpoints: hp, @@ -122,6 +123,8 @@ export function runMicrobeHUDSetup(){ PhosphateMax: phosphate, compoundHydrogenSulfide: common.randomBetween(0, hydrogenSulfide), HydrogenSulfideMax: hydrogenSulfide, + compoundIron: common.randomBetween(0, iron), + IronMax: iron, }); // Pseudo population code diff --git a/scripts/gui/thrive_gui.html b/scripts/gui/thrive_gui.html index f13a47d4351..b7e9fe01f41 100644 --- a/scripts/gui/thrive_gui.html +++ b/scripts/gui/thrive_gui.html @@ -405,6 +405,35 @@ sulfide from hydrothermal vents into usable energy in the form of glucose.
Chemosynthisizing Proteins
45 MP + + + + +
+ + Chromatophores

Cost: 25 mutation points

+ Performs Process: Chromatophore Photosynthesis
(0.09 CO2 -> 0.33 glucose)/Second (Depending On Environmental C02)
+ Performs Process: Glycolysis
(0.125 glucose -> 5 ATP)/Second (Depending On Environmental C02)

+ Storage Space: 10

+ Coloured, membrane-associated vesicles used by various prokaryotes perform photosynthesis. + Chromatophores contain bacteriochlorophyll pigments and carotenoids.
+
Chromatophores
25 MP
+ + ChemosynthisizingProteins

Cost: 20 mutation points

+ Performs Process: Bacterial Chemosynthesis
(1 CO2 + 1 Hydrogen Sulfide -> 1 Glucose)/Second (Depending On Environmental C02)
+ Performs Process: Glycolysis
(0.125 glucose -> 5 ATP)/Second

+ Storage Space: 20

+ Small membrane-associated structures that convert the noxious soup containing hydrogen + sulfide from hydrothermal vents into usable energy in the form of glucose.
+
Chemosynthisizing Proteins
45 MP
+ + Rusticyanin

Cost: 45 mutation points

+ Performs Process: Iron Chemolithotrophy
(0.09 CO2 + 0.5 Iron Ion -> 10 ATP)/Second (Depending On Environmental C02)
+ Storage Space: 5

+ Siderophores and Rusticyanin for storing and using iron ions and carbon from atmospheric carbon dioxide to produce ATP. + Iron Chemolithotrophy is a process by which organisms obtain their energy from the oxidation of reduced inorganic ions. +
+
Rusticyanin
45 MP
EXTERNAL ORGANELLES
+
Cilia
40 MP
@@ -416,7 +445,7 @@
Predatory Pilus
30 MP
-
Cilia
40 MP
INTERNAL ORGANELLES
@@ -470,7 +499,7 @@ Allows for synthesis of ammonia from atmospheric nitrogen and oxygen. For easier cell growth.
-
Nitrogen Fixing Plastid
80 MP + Nitrogen Fixing
Plastid
80 MP - - - -
@@ -487,34 +516,6 @@
Toxin Vacuole
70 MP
Bioluminescent Vacuole
N/A MP
- - Chromatophores

Cost: 25 mutation points

- Performs Process: Chromatophore Photosynthesis
(0.09 CO2 -> 0.33 glucose)/Second (Depending On Environmental C02)
- Performs Process: Glycolysis
(0.125 glucose -> 5 ATP)/Second (Depending On Environmental C02)

- Storage Space: 10

- Coloured, membrane-associated vesicles used by various prokaryotes perform photosynthesis. - Chromatophores contain bacteriochlorophyll pigments and carotenoids.
-
Chromatophores
25 MP
- - ChemosynthisizingProteins

Cost: 20 mutation points

- Performs Process: Bacterial Chemosynthesis
(1 CO2 + 1 Hydrogen Sulfide -> 1 Glucose)/Second (Depending On Environmental C02)
- Performs Process: Glycolysis
(0.125 glucose -> 5 ATP)/Second

- Storage Space: 20

- Small membrane-associated structures that convert the noxious soup containing hydrogen - sulfide from hydrothermal vents into usable energy in the form of glucose.
-
Chemosynthisizing Proteins
45 MP
- - Rusticyanin

Cost: 45 mutation points

- Performs Process: Iron Chemolithotrophy
(0.09 CO2 + 0.5 Iron Ion -> 10 ATP)/Second (Depending On Environmental C02)
- Storage Space: 5

- Siderophores and Rusticyanin for storing and using iron ions and carbon from atmospheric carbon dioxide to produce ATP. - Iron Chemolithotrophy is a process by which organisms obtain their energy from the oxidation of reduced inorganic ions. -
-
Rusticyanin
45 MP
From 19524e1ffb777f7c338c90e4bb80271b767a320d Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Fri, 15 Feb 2019 12:57:52 -0600 Subject: [PATCH 41/42] got rid of extra chemosythesizing proteins. --- scripts/gui/thrive_gui.html | 9 --------- 1 file changed, 9 deletions(-) diff --git a/scripts/gui/thrive_gui.html b/scripts/gui/thrive_gui.html index b7e9fe01f41..36815a38fbd 100644 --- a/scripts/gui/thrive_gui.html +++ b/scripts/gui/thrive_gui.html @@ -415,15 +415,6 @@ Coloured, membrane-associated vesicles used by various prokaryotes perform photosynthesis. Chromatophores contain bacteriochlorophyll pigments and carotenoids.
Chromatophores
25 MP - - - ChemosynthisizingProteins

Cost: 20 mutation points

- Performs Process: Bacterial Chemosynthesis
(1 CO2 + 1 Hydrogen Sulfide -> 1 Glucose)/Second (Depending On Environmental C02)
- Performs Process: Glycolysis
(0.125 glucose -> 5 ATP)/Second

- Storage Space: 20

- Small membrane-associated structures that convert the noxious soup containing hydrogen - sulfide from hydrothermal vents into usable energy in the form of glucose.
-
Chemosynthisizing Proteins
45 MP Rusticyanin

Cost: 45 mutation points

From f25224ff1423b80b7bcc61ca332e704df89fcea3 Mon Sep 17 00:00:00 2001 From: Untrustedlife Date: Fri, 15 Feb 2019 13:02:32 -0600 Subject: [PATCH 42/42] plastid now tells you correct MP cost --- scripts/gui/thrive_gui.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gui/thrive_gui.html b/scripts/gui/thrive_gui.html index 36815a38fbd..eb60291125b 100644 --- a/scripts/gui/thrive_gui.html +++ b/scripts/gui/thrive_gui.html @@ -490,7 +490,7 @@ Allows for synthesis of ammonia from atmospheric nitrogen and oxygen. For easier cell growth.
-
Nitrogen Fixing
Plastid
80 MP + Nitrogen Fixing
Plastid
50 MP