v1.4.4
This commit is contained in:
commit
9c94d113d3
10260 changed files with 1237388 additions and 0 deletions
303
attic/old_source/StarFlowingLiquidAgent.cpp
Normal file
303
attic/old_source/StarFlowingLiquidAgent.cpp
Normal file
|
@ -0,0 +1,303 @@
|
|||
#include "StarFlowingLiquidAgent.hpp"
|
||||
#include "StarRoot.hpp"
|
||||
#include "StarLiquidsDatabase.hpp"
|
||||
#include "StarLivingWorldAgent.hpp"
|
||||
#include "StarLogging.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
FlowingLiquidAgent::FlowingLiquidAgent() {
|
||||
m_livingWorld = {};
|
||||
}
|
||||
|
||||
void FlowingLiquidAgent::bind(LivingWorldFacadePtr world, LivingWorldAgent* livingWorld) {
|
||||
this->m_world = world;
|
||||
m_livingWorld = livingWorld;
|
||||
}
|
||||
|
||||
void FlowingLiquidAgent::processLocation(Vec2I const& c) {
|
||||
auto level = getLiquidLevel(c.x(), c.y());
|
||||
int fountainPressure = 0;
|
||||
|
||||
if (level.liquid != Liquid::SolidTileLiquidPseudoId) {
|
||||
if (!hasBackground(c.x(), c.y()) && isOcean(c.x(), c.y())) {
|
||||
auto liquid = oceanLiquid(c.x(), c.y());
|
||||
auto pressure = oceanLiquidPressure(c.x(), c.y());
|
||||
if ((level.liquid != liquid)||(level.level != pressure)) {
|
||||
setLiquidLevel(c.x(), c.y(), LiquidLevel{liquid, pressure});
|
||||
level = getLiquidLevel(c.x(), c.y());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (level.level >= Liquid::OverflowFullLiquidLevel)
|
||||
if (moveLiquidUpwards(c, level)) {
|
||||
auto l = getLiquidLevel(c.x(), c.y());
|
||||
fountainPressure = (int) level.level - (int) l.level;
|
||||
level = l;
|
||||
}
|
||||
if (level.level > 0)
|
||||
if (moveLiquidDown(c, level, true)) {
|
||||
level = getLiquidLevel(c.x(), c.y());
|
||||
fountainPressure = 0;
|
||||
}
|
||||
if (level.level >= Liquid::TrivialLevelThreshold) {
|
||||
moveLiquidSideWays(c, fountainPressure);
|
||||
}
|
||||
}
|
||||
|
||||
bool FlowingLiquidAgent::moveLiquidDown(Vec2I c, LiquidLevel above, bool attemptMoveOut) {
|
||||
auto liquidsDatabase = Root::singleton().liquidsDatabase();
|
||||
|
||||
if (above.liquid == Liquid::SolidTileLiquidPseudoId)
|
||||
return false;
|
||||
auto below = getLiquidLevel(c.x(), c.y() - 1);
|
||||
if (below.liquid == Liquid::SolidTileLiquidPseudoId) {
|
||||
if (attemptMoveOut)
|
||||
moveLiquidOut(c);
|
||||
return false;
|
||||
}
|
||||
if ((c.y() <= 0) && liquidsDatabase->liquidSettings(above.liquid)->endless)
|
||||
return false;
|
||||
|
||||
int move = std::max(0,
|
||||
std::min(std::min((int) above.level, (Liquid::MaxLiquidLevel - 1) - (int) below.level),
|
||||
std::max((Liquid::OverflowFullLiquidLevel - 1) - (int) below.level,
|
||||
std::min((Liquid::PressurePerLevel - ((int) below.level - (int) above.level)) / 2,
|
||||
(int) above.level - (Liquid::TrivialLevelThreshold - 1)))));
|
||||
|
||||
move *= std::min(liquidsDatabase->liquidSettings(below.liquid)->downwardsSpeedModifier, liquidsDatabase->liquidSettings(above.liquid)->downwardsSpeedModifier);
|
||||
|
||||
above.level -= move;
|
||||
below.level += move;
|
||||
below.liquid = above.liquid;
|
||||
|
||||
if (move > 0) {
|
||||
moveLiquid(c.x(), c.y(), 0, -1, above, below);
|
||||
return true;
|
||||
} else {
|
||||
if (attemptMoveOut)
|
||||
moveLiquidOut(c);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool FlowingLiquidAgent::moveLiquidSideWays(Vec2I c, int fountain) {
|
||||
fountain /= Liquid::PressurePerLevel;
|
||||
auto below = getLiquidLevel(c.x(), c.y() - 1);
|
||||
if ((below.liquid != Liquid::SolidTileLiquidPseudoId) && (below.level < Liquid::FullLiquidLevel))
|
||||
return false;
|
||||
bool result = false;
|
||||
int move = 0;
|
||||
while (true) {
|
||||
move++;
|
||||
int bdx = 0;
|
||||
int bl = 0;
|
||||
int l;
|
||||
auto level = getLiquidLevel(c.x(), c.y());
|
||||
if (level.liquid == Liquid::SolidTileLiquidPseudoId)
|
||||
break;
|
||||
int idx = 0;
|
||||
int preferredDirection = m_random.randInt(1);
|
||||
|
||||
for (int dx = -1; dx <= 1; dx += 2) {
|
||||
l = checkMoveLiquidSideways(c.x() + dx, c.y(), level);
|
||||
if ((l > bl) || ((l == bl) && (idx == preferredDirection))) {
|
||||
bl = l;
|
||||
bdx = dx;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
if (bl == 0)
|
||||
break;
|
||||
|
||||
auto source = getLiquidLevel(c.x(), c.y());
|
||||
auto target = getLiquidLevel(c.x() + bdx, c.y());
|
||||
|
||||
if ((source.level > bl) && ((int) source.level - bl > (int) target.level + bl))
|
||||
bl++;
|
||||
|
||||
if ((fountain > 0) && (m_random.randInt(5 * fountain) != 0))
|
||||
bl /= fountain * 10;
|
||||
|
||||
if ((bl >= Liquid::TrivialSidewaysMoveThreshold)
|
||||
&& (((int) source.level - bl) >= Liquid::TrivialLevelThreshold)
|
||||
&& (((int) target.level + bl) >= Liquid::TrivialLevelThreshold)) {
|
||||
|
||||
source.level -= bl;
|
||||
target.level += bl;
|
||||
target.liquid = source.liquid;
|
||||
moveLiquid(c.x(), c.y(), bdx, 0, source, target);
|
||||
moveLiquidDown(Vec2I(c.x() + bdx, c.y()), getLiquidLevel(c.x() + bdx, c.y()), false);
|
||||
result = true;
|
||||
}
|
||||
else {
|
||||
if (target.level <= Liquid::IdleLevelEvaporateThreshold) {
|
||||
source.level = std::max(0, source.level - Liquid::IdleLevelEvaporateThreshold);
|
||||
setLiquidLevel(c.x(), c.y(), source);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int FlowingLiquidAgent::checkMoveLiquidSideways(int x, int y, LiquidLevel level) {
|
||||
if (level.liquid == Liquid::SolidTileLiquidPseudoId)
|
||||
return 0;
|
||||
auto beside = getLiquidLevel(x, y);
|
||||
if (beside.liquid == Liquid::SolidTileLiquidPseudoId)
|
||||
return 0;
|
||||
int result = (((int) level.level - (int) beside.level) * 1.9) / 2;
|
||||
auto liquidsDatabase = Root::singleton().liquidsDatabase();
|
||||
result *= std::min(liquidsDatabase->liquidSettings(level.liquid)->sidewaysSpeedModifier, liquidsDatabase->liquidSettings(beside.liquid)->sidewaysSpeedModifier);
|
||||
if (result > level.level)
|
||||
result = level.level;
|
||||
if (result <= 0)
|
||||
return 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FlowingLiquidAgent::moveLiquidUpwards(Vec2I c, LiquidLevel level) {
|
||||
if (level.liquid == Liquid::SolidTileLiquidPseudoId)
|
||||
return false;
|
||||
if (level.level < Liquid::OverflowFullLiquidLevel) {
|
||||
return false;
|
||||
}
|
||||
auto above = getLiquidLevel(c.x(), c.y() + 1);
|
||||
if (above.liquid == Liquid::SolidTileLiquidPseudoId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int move = std::max(0,
|
||||
std::min((int) level.level - (Liquid::OverflowFullLiquidLevel -1),
|
||||
(((int) level.level - (int) above.level) - (Liquid::PressurePerLevel)) / 2));
|
||||
|
||||
if (above.liquid == NullLiquidId)
|
||||
above.liquid = level.liquid;
|
||||
|
||||
auto liquidsDatabase = Root::singleton().liquidsDatabase();
|
||||
move *= std::min(liquidsDatabase->liquidSettings(level.liquid)->upwardsSpeedModifier, liquidsDatabase->liquidSettings(above.liquid)->upwardsSpeedModifier);
|
||||
move = std::min(move, std::min((int) level.level, (Liquid::MaxLiquidLevel - 1) - (int) above.level));
|
||||
|
||||
above.level += move;
|
||||
level.level -= move;
|
||||
above.liquid = level.liquid;
|
||||
|
||||
if ((move >= Liquid::TrivialUpwardsMoveThreshold)
|
||||
&& (above.level >= Liquid::TrivialLevelThreshold)) {
|
||||
moveLiquid(c.x(), c.y(), 0, 1, level, above);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FlowingLiquidAgent::moveLiquidOut(Vec2I c) {
|
||||
if (!hasBackground(c.x(), c.y()) && !isOcean(c.x(), c.y())) {
|
||||
auto current = getLiquidLevel(c.x(), c.y());
|
||||
auto liquidsDatabase = Root::singleton().liquidsDatabase();
|
||||
auto setting = liquidsDatabase->liquidSettings(current.liquid);
|
||||
if (setting->endless)
|
||||
return false;
|
||||
// Move Liquid into the background (disappear) at the BackgroundFlowPercentage
|
||||
current.level *= 1.0f - setting->backgroundFlowPercentage;
|
||||
setLiquidLevel(c.x(), c.y(), current);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool FlowingLiquidAgent::sanityCheckLiquid(LiquidLevel const& level) const {
|
||||
if (((level.liquid != Liquid::SolidTileLiquidPseudoId)&&(level.liquid != NullLiquidId)) == (level.level == 0)) {
|
||||
Logger::warn("Inconsistent liquid data. Liquid:%s Level:%s", level.liquid, level.level);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
LiquidLevel FlowingLiquidAgent::getLiquidLevel(int x, int y) {
|
||||
LiquidLevel level = m_world->readTileLiquid(x, y);
|
||||
#ifndef NDEBUG
|
||||
sanityCheckLiquid(level);
|
||||
#endif
|
||||
return level;
|
||||
}
|
||||
|
||||
bool FlowingLiquidAgent::hasBackground(int x, int y) {
|
||||
return m_world->hasBackground(x, y);
|
||||
}
|
||||
|
||||
bool FlowingLiquidAgent::isOcean(int x, int y) {
|
||||
return m_world->isOcean(x, y);
|
||||
}
|
||||
|
||||
LiquidId FlowingLiquidAgent::oceanLiquid(int x, int y) {
|
||||
return m_world->oceanLiquid(x, y);
|
||||
}
|
||||
|
||||
uint16_t FlowingLiquidAgent::oceanLiquidPressure(int x, int y) {
|
||||
return m_world->oceanLiquidPressure(x, y);
|
||||
}
|
||||
|
||||
void FlowingLiquidAgent::moveLiquid(int x, int y, int dx, int dy,
|
||||
LiquidLevel proposedSourceLevel, LiquidLevel proposedTargetLevel) {
|
||||
setLiquidLevel(x, y, proposedSourceLevel);
|
||||
setLiquidLevel(x + dx, y + dy, proposedTargetLevel);
|
||||
}
|
||||
|
||||
void FlowingLiquidAgent::setLiquidLevel(int x, int y, LiquidLevel level) {
|
||||
if (level.level <= Liquid::TrivialLevelThreshold)
|
||||
level.level = 0;
|
||||
if (level.level == 0)
|
||||
level.liquid = NullLiquidId;
|
||||
auto prevLevel = getLiquidLevel(x, y);
|
||||
auto liquidsDatabase = Root::singleton().liquidsDatabase();
|
||||
auto prevLevelSetting = liquidsDatabase->liquidSettings(prevLevel.liquid);
|
||||
if (prevLevelSetting->endless)
|
||||
return; // can never update a endlesswater tile after generation
|
||||
if ((prevLevel.liquid == level.liquid) && (prevLevel.level == level.level))
|
||||
return;
|
||||
starAssert(prevLevel.liquid != Liquid::SolidTileLiquidPseudoId);
|
||||
|
||||
MaterialId blockId = NullMaterialId;
|
||||
MaterialHue blockHueShift = MaterialHue();
|
||||
|
||||
float flow = fabs((float) level.level - (float) prevLevel.level);
|
||||
auto effect = liquidsDatabase->liquidSettings(level.liquid);
|
||||
level.liquid = effect->flowsAs;
|
||||
float chance = effect->blockGenerationChance * fmin((float)flow / (float)Liquid::FullLiquidLevel, 1.0f);
|
||||
if (Random::randf() < chance) {
|
||||
if (!effect->connectedOnly
|
||||
||(getLiquidLevel(x-1, y).liquid == Liquid::SolidTileLiquidPseudoId)
|
||||
||(getLiquidLevel(x+1, y).liquid == Liquid::SolidTileLiquidPseudoId)
|
||||
||(getLiquidLevel(x, y-1).liquid == Liquid::SolidTileLiquidPseudoId)
|
||||
||(getLiquidLevel(x, y+1).liquid == Liquid::SolidTileLiquidPseudoId)) {
|
||||
blockId = Random::randFrom(effect->blockOptions);
|
||||
}
|
||||
}
|
||||
|
||||
if ((level.liquid != NullLiquidId) && (level.liquid != Liquid::SolidTileLiquidPseudoId) && (prevLevel.liquid != NullLiquidId) && (prevLevel.liquid != Liquid::SolidTileLiquidPseudoId)
|
||||
&& (level.liquid != prevLevel.liquid)) {
|
||||
auto& interaction = effect->liquidInteraction[prevLevel.liquid];
|
||||
if (Random::randf() < interaction.blockGenerationChance) {
|
||||
blockId = Random::randFrom(interaction.blockOptions);
|
||||
} else {
|
||||
float chance = flow / (flow + prevLevel.level);
|
||||
if (Random::randf() >= chance)
|
||||
level.liquid = prevLevel.liquid;
|
||||
}
|
||||
}
|
||||
|
||||
if ((blockId != NullMaterialId) && (blockId != EmptyMaterialId)) {
|
||||
m_world->writeTileMaterial(x, y, blockId, blockHueShift, true);
|
||||
} else {
|
||||
if (!sanityCheckLiquid(level))
|
||||
return;
|
||||
m_world->writeTileLiquid(x, y, level);
|
||||
}
|
||||
m_livingWorld->visitRegion(x, y, true);
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue