|
@@ -0,0 +1,249 @@
|
|
|
+#include "FluidBlock.h"
|
|
|
+
|
|
|
+#include "Game.h"
|
|
|
+
|
|
|
+FluidBlock::FluidBlock(int typeId, Framework::Vec3<int> pos)
|
|
|
+ : Block(typeId, 0, pos, 0)
|
|
|
+{
|
|
|
+ transparent = 1;
|
|
|
+ passable = 1;
|
|
|
+ hp = 1;
|
|
|
+ maxHP = 1;
|
|
|
+ hardness = -1.f;
|
|
|
+ speedModifier = 0.5f;
|
|
|
+ tickSource = 1;
|
|
|
+ interactable = 0;
|
|
|
+ fluidAmount = 0;
|
|
|
+}
|
|
|
+
|
|
|
+FluidBlock::~FluidBlock() {}
|
|
|
+
|
|
|
+bool FluidBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
|
|
|
+{
|
|
|
+ nextFlow = 0;
|
|
|
+ int bottom = neighbourTypes[getDirectionIndex(Direction::BOTTOM)];
|
|
|
+ if (bottom != zBlockType()->getId())
|
|
|
+ {
|
|
|
+ if (bottom == BlockTypeEnum::AIR)
|
|
|
+ {
|
|
|
+ nextFlow |= 1 << getDirectionIndex(Direction::BOTTOM);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (zNeighbours[getDirectionIndex(Direction::BOTTOM)]
|
|
|
+ && zNeighbours[getDirectionIndex(Direction::BOTTOM)]
|
|
|
+ ->zBlockType()
|
|
|
+ ->getId()
|
|
|
+ == typeId)
|
|
|
+ {
|
|
|
+ Inventory* array[2]
|
|
|
+ = {zNeighbours[getDirectionIndex(Direction::BOTTOM)], this};
|
|
|
+ MultipleInventoryLock lock(array, 2);
|
|
|
+ FluidBlock* below = dynamic_cast<FluidBlock*>(
|
|
|
+ zNeighbours[getDirectionIndex(Direction::BOTTOM)]);
|
|
|
+ if (below->fluidAmount < 1000)
|
|
|
+ {
|
|
|
+ int transferAmount
|
|
|
+ = MIN(this->fluidAmount, 1000 - below->fluidAmount);
|
|
|
+ below->fluidAmount += transferAmount;
|
|
|
+ this->fluidAmount -= transferAmount;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ int neighborCount = 0;
|
|
|
+ Inventory* others[4];
|
|
|
+ for (int i = 1; i < 5; i++)
|
|
|
+ {
|
|
|
+ if (neighbourTypes[i] == BlockTypeEnum::FLUID && zNeighbours[i]
|
|
|
+ && zNeighbours[i]->zBlockType()->getId() == typeId)
|
|
|
+ {
|
|
|
+ others[neighborCount] = zNeighbours[i];
|
|
|
+ neighborCount++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (neighborCount > 0)
|
|
|
+ {
|
|
|
+ Inventory* array[5]
|
|
|
+ = {this, others[0], others[1], others[2], others[3]};
|
|
|
+ MultipleInventoryLock lock(array, neighborCount + 1);
|
|
|
+ // all neighbot fluid blocks are locked now
|
|
|
+ FluidBlock* otherFluids[4];
|
|
|
+ for (int i = 0; i < neighborCount; i++)
|
|
|
+ {
|
|
|
+ otherFluids[i] = dynamic_cast<FluidBlock*>(others[i]);
|
|
|
+ }
|
|
|
+ // order other fluids increasing by fluid amount
|
|
|
+ sortByAmound(otherFluids, neighborCount);
|
|
|
+ int distCount = 0;
|
|
|
+ int targetAmount = 0;
|
|
|
+ for (int i = 1; i <= neighborCount; i++)
|
|
|
+ {
|
|
|
+ int fluidAmount = this->fluidAmount;
|
|
|
+ for (int j = 0; j < i; j++)
|
|
|
+ {
|
|
|
+ fluidAmount += otherFluids[j]->fluidAmount;
|
|
|
+ }
|
|
|
+ if (fluidAmount / (i + 1) > this->fluidAmount)
|
|
|
+ {
|
|
|
+ targetAmount = fluidAmount / (i + 1);
|
|
|
+ distCount = i;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (int i = 0; i < distCount; i++)
|
|
|
+ {
|
|
|
+ int transferAmount
|
|
|
+ = targetAmount - otherFluids[i]->fluidAmount;
|
|
|
+ otherFluids[i]->fluidAmount += transferAmount;
|
|
|
+ this->fluidAmount -= transferAmount;
|
|
|
+ }
|
|
|
+ // TODO: distribute fluids
|
|
|
+ } // unlock
|
|
|
+ neighborCount = 0;
|
|
|
+ for (int i = 1; i < 5; i++)
|
|
|
+ {
|
|
|
+ int neighbor = neighbourTypes[i];
|
|
|
+ if (neighbor == BlockTypeEnum::AIR
|
|
|
+ && fluidAmount > neighborCount + 1)
|
|
|
+ {
|
|
|
+ nextFlow |= 1 << i;
|
|
|
+ neighborCount++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void FluidBlock::onPostTick()
|
|
|
+{
|
|
|
+ if (nextFlow != 0)
|
|
|
+ {
|
|
|
+ Game::INSTANCE->doLater([this]() {
|
|
|
+ for (int i = 0; i < 6; i++)
|
|
|
+ {
|
|
|
+ if ((nextFlow | (1 << i)) == nextFlow)
|
|
|
+ {
|
|
|
+ Vec3<int> pos
|
|
|
+ = getPos() + getDirection(getDirectionFromIndex(i));
|
|
|
+ if (neighbourTypes[i] == BlockTypeEnum::AIR)
|
|
|
+ {
|
|
|
+ FluidBlock* spawn = new FluidBlock(typeId, pos);
|
|
|
+ spawn->fluidAmount = 1;
|
|
|
+ Game::INSTANCE->zDimension(getDimensionId())
|
|
|
+ ->placeBlock(pos, spawn);
|
|
|
+ fluidAmount--;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (fluidAmount == 0)
|
|
|
+ {
|
|
|
+ Game::INSTANCE->zDimension(getDimensionId())
|
|
|
+ ->placeBlock(getPos(),
|
|
|
+ StaticRegistry<BlockType>::INSTANCE
|
|
|
+ .zElement(BlockTypeEnum::AIR)
|
|
|
+ ->createBlockAt(getPos(), 0));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void FluidBlock::sortByAmound(FluidBlock** array, int count)
|
|
|
+{
|
|
|
+ if (count == 2)
|
|
|
+ {
|
|
|
+ if (array[0]->fluidAmount > array[1]->fluidAmount)
|
|
|
+ {
|
|
|
+ FluidBlock* tmp = array[0];
|
|
|
+ array[0] = array[1];
|
|
|
+ array[1] = tmp;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (count == 3)
|
|
|
+ {
|
|
|
+ if (array[0]->fluidAmount > array[1]->fluidAmount)
|
|
|
+ {
|
|
|
+ FluidBlock* tmp = array[0];
|
|
|
+ array[0] = array[1];
|
|
|
+ array[1] = tmp;
|
|
|
+ }
|
|
|
+ if (array[1]->fluidAmount > array[2]->fluidAmount)
|
|
|
+ {
|
|
|
+ FluidBlock* tmp = array[1];
|
|
|
+ array[1] = array[2];
|
|
|
+ array[2] = tmp;
|
|
|
+ }
|
|
|
+ if (array[0]->fluidAmount > array[1]->fluidAmount)
|
|
|
+ {
|
|
|
+ FluidBlock* tmp = array[0];
|
|
|
+ array[0] = array[1];
|
|
|
+ array[1] = tmp;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (count == 4)
|
|
|
+ {
|
|
|
+ if (array[0]->fluidAmount > array[1]->fluidAmount)
|
|
|
+ {
|
|
|
+ FluidBlock* tmp = array[0];
|
|
|
+ array[0] = array[1];
|
|
|
+ array[1] = tmp;
|
|
|
+ }
|
|
|
+ if (array[2]->fluidAmount > array[3]->fluidAmount)
|
|
|
+ {
|
|
|
+ FluidBlock* tmp = array[2];
|
|
|
+ array[2] = array[3];
|
|
|
+ array[3] = tmp;
|
|
|
+ }
|
|
|
+ if (array[0]->fluidAmount > array[2]->fluidAmount)
|
|
|
+ {
|
|
|
+ FluidBlock* tmp = array[0];
|
|
|
+ array[0] = array[2];
|
|
|
+ array[2] = tmp;
|
|
|
+ }
|
|
|
+ if (array[1]->fluidAmount > array[3]->fluidAmount)
|
|
|
+ {
|
|
|
+ FluidBlock* tmp = array[1];
|
|
|
+ array[1] = array[3];
|
|
|
+ array[3] = tmp;
|
|
|
+ }
|
|
|
+ if (array[1]->fluidAmount > array[2]->fluidAmount)
|
|
|
+ {
|
|
|
+ FluidBlock* tmp = array[1];
|
|
|
+ array[1] = array[2];
|
|
|
+ array[2] = tmp;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+FluidBlockType::FluidBlockType(int id, ModelInfo model, const char* name)
|
|
|
+ : BlockType(id, 0, model, 1, 10, 0, name)
|
|
|
+{}
|
|
|
+
|
|
|
+void FluidBlockType::loadSuperBlock(
|
|
|
+ Block* zBlock, Framework::StreamReader* zReader, int dimensionId) const
|
|
|
+{
|
|
|
+ FluidBlock* block = dynamic_cast<FluidBlock*>(zBlock);
|
|
|
+ zReader->lese((char*)&block->fluidAmount, 2);
|
|
|
+ BlockType::loadSuperBlock(zBlock, zReader, dimensionId);
|
|
|
+}
|
|
|
+
|
|
|
+void FluidBlockType::saveSuperBlock(
|
|
|
+ Block* zBlock, Framework::StreamWriter* zWriter) const
|
|
|
+{
|
|
|
+ FluidBlock* block = dynamic_cast<FluidBlock*>(zBlock);
|
|
|
+ zWriter->schreibe((char*)&block->fluidAmount, 2);
|
|
|
+ BlockType::saveSuperBlock(zBlock, zWriter);
|
|
|
+}
|
|
|
+
|
|
|
+Item* FluidBlockType::createItem() const
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+Block* FluidBlockType::createBlock(Framework::Vec3<int> position) const
|
|
|
+{
|
|
|
+ FluidBlock* result = new FluidBlock(getId(), position);
|
|
|
+ result->fluidAmount = 1000;
|
|
|
+ return result;
|
|
|
+}
|