diff options
Diffstat (limited to 'source/Simulator/FireSimulator.cpp')
-rw-r--r-- | source/Simulator/FireSimulator.cpp | 374 |
1 files changed, 0 insertions, 374 deletions
diff --git a/source/Simulator/FireSimulator.cpp b/source/Simulator/FireSimulator.cpp deleted file mode 100644 index ac3fb9695..000000000 --- a/source/Simulator/FireSimulator.cpp +++ /dev/null @@ -1,374 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "FireSimulator.h" -#include "../World.h" -#include "../BlockID.h" -#include "../Defines.h" -#include "../Chunk.h" - - - - - -// Easy switch for turning on debugging logging: -#if 0 - #define FLOG LOGD -#else - #define FLOG(...) -#endif - - - - - -#define MAX_CHANCE_REPLACE_FUEL 100000 -#define MAX_CHANCE_FLAMMABILITY 100000 - - - - - -static const struct -{ - int x, y, z; -} gCrossCoords[] = -{ - { 1, 0, 0}, - {-1, 0, 0}, - { 0, 0, 1}, - { 0, 0, -1}, -} ; - - - - - -static const struct -{ - int x, y, z; -} gNeighborCoords[] = -{ - { 1, 0, 0}, - {-1, 0, 0}, - { 0, 1, 0}, - { 0, -1, 0}, - { 0, 0, 1}, - { 0, 0, -1}, -} ; - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cFireSimulator: - -cFireSimulator::cFireSimulator(cWorld & a_World, cIniFile & a_IniFile) : - cSimulator(a_World) -{ - // Read params from the ini file: - m_BurnStepTimeFuel = a_IniFile.GetValueSetI("FireSimulator", "BurnStepTimeFuel", 500); - m_BurnStepTimeNonfuel = a_IniFile.GetValueSetI("FireSimulator", "BurnStepTimeNonfuel", 100); - m_Flammability = a_IniFile.GetValueSetI("FireSimulator", "Flammability", 50); - m_ReplaceFuelChance = a_IniFile.GetValueSetI("FireSimulator", "ReplaceFuelChance", 50000); -} - - - - - -cFireSimulator::~cFireSimulator() -{ -} - - - - - -void cFireSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) -{ - cCoordWithIntList & Data = a_Chunk->GetFireSimulatorData(); - - int NumMSecs = (int)a_Dt; - for (cCoordWithIntList::iterator itr = Data.begin(); itr != Data.end();) - { - int idx = cChunkDef::MakeIndexNoCheck(itr->x, itr->y, itr->z); - BLOCKTYPE BlockType = a_Chunk->GetBlock(idx); - - if (!IsAllowedBlock(BlockType)) - { - // The block is no longer eligible (not a fire block anymore; a player probably placed a block over the fire) - FLOG("FS: Removing block {%d, %d, %d}", - itr->x + a_ChunkX * cChunkDef::Width, itr->y, itr->z + a_ChunkZ * cChunkDef::Width - ); - itr = Data.erase(itr); - continue; - } - - // Try to spread the fire: - TrySpreadFire(a_Chunk, itr->x, itr->y, itr->z); - - itr->Data -= NumMSecs; - if (itr->Data >= 0) - { - // Not yet, wait for it longer - ++itr; - continue; - } - - // Burn out the fire one step by increasing the meta: - /* - FLOG("FS: Fire at {%d, %d, %d} is stepping", - itr->x + a_ChunkX * cChunkDef::Width, itr->y, itr->z + a_ChunkZ * cChunkDef::Width - ); - */ - NIBBLETYPE BlockMeta = a_Chunk->GetMeta(idx); - if (BlockMeta == 0x0f) - { - // The fire burnt out completely - FLOG("FS: Fire at {%d, %d, %d} burnt out, removing the fire block", - itr->x + a_ChunkX * cChunkDef::Width, itr->y, itr->z + a_ChunkZ * cChunkDef::Width - ); - a_Chunk->SetBlock(itr->x, itr->y, itr->z, E_BLOCK_AIR, 0); - RemoveFuelNeighbors(a_Chunk, itr->x, itr->y, itr->z); - itr = Data.erase(itr); - continue; - } - a_Chunk->SetMeta(idx, BlockMeta + 1); - itr->Data = GetBurnStepTime(a_Chunk, itr->x, itr->y, itr->z); // TODO: Add some randomness into this - } // for itr - Data[] -} - - - - - -bool cFireSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType) -{ - return (a_BlockType == E_BLOCK_FIRE); -} - - - - - -bool cFireSimulator::IsFuel(BLOCKTYPE a_BlockType) -{ - switch (a_BlockType) - { - case E_BLOCK_PLANKS: - case E_BLOCK_LEAVES: - case E_BLOCK_LOG: - case E_BLOCK_WOOL: - case E_BLOCK_BOOKCASE: - case E_BLOCK_FENCE: - case E_BLOCK_TNT: - case E_BLOCK_VINES: - { - return true; - } - } - return false; -} - - - - - -bool cFireSimulator::IsForever(BLOCKTYPE a_BlockType) -{ - return (a_BlockType == E_BLOCK_NETHERRACK); -} - - - - - -void cFireSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) -{ - if ((a_Chunk == NULL) || !a_Chunk->IsValid()) - { - return; - } - - int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; - int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; - BLOCKTYPE BlockType = a_Chunk->GetBlock(RelX, a_BlockY, RelZ); - if (!IsAllowedBlock(BlockType)) - { - return; - } - - // Check for duplicates: - cFireSimulatorChunkData & ChunkData = a_Chunk->GetFireSimulatorData(); - for (cCoordWithIntList::iterator itr = ChunkData.begin(), end = ChunkData.end(); itr != end; ++itr) - { - if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ)) - { - // Already present, skip adding - return; - } - } // for itr - ChunkData[] - - FLOG("FS: Adding block {%d, %d, %d}", a_BlockX, a_BlockY, a_BlockZ); - ChunkData.push_back(cCoordWithInt(RelX, a_BlockY, RelZ, 100)); -} - - - - - -int cFireSimulator::GetBurnStepTime(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ) -{ - bool IsBlockBelowSolid = false; - if (a_RelY > 0) - { - BLOCKTYPE BlockBelow = a_Chunk->GetBlock(a_RelX, a_RelY - 1, a_RelZ); - if (IsForever(BlockBelow)) - { - // Is burning atop of netherrack, burn forever (re-check in 10 sec) - return 10000; - } - if (IsFuel(BlockBelow)) - { - return m_BurnStepTimeFuel; - } - IsBlockBelowSolid = g_BlockIsSolid[BlockBelow]; - } - - for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) - { - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - if (a_Chunk->UnboundedRelGetBlock(a_RelX + gCrossCoords[i].x, a_RelY, a_RelZ + gCrossCoords[i].z, BlockType, BlockMeta)) - { - if (IsFuel(BlockType)) - { - return m_BurnStepTimeFuel; - } - } - } // for i - gCrossCoords[] - - if (!IsBlockBelowSolid && (a_RelY >= 0)) - { - // Checked through everything, nothing was flammable - // If block below isn't solid, we can't have fire, it would be a non-fueled fire - // SetBlock just to make sure fire doesn't spawn - a_Chunk->SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0); - return 0; - } - return m_BurnStepTimeNonfuel; -} - - - - - -void cFireSimulator::TrySpreadFire(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ) -{ - /* - if (m_World.GetTickRandomNumber(10000) > 100) - { - // Make the chance to spread 100x smaller - return; - } - */ - - for (int x = a_RelX - 1; x <= a_RelX + 1; x++) - { - for (int z = a_RelZ - 1; z <= a_RelZ + 1; z++) - { - for (int y = a_RelY - 1; y <= a_RelY + 2; y++) // flames spread up one more block than around - { - // No need to check the coords for equality with the parent block, - // it cannot catch fire anyway (because it's not an air block) - - if (m_World.GetTickRandomNumber(MAX_CHANCE_FLAMMABILITY) > m_Flammability) - { - continue; - } - - // Start the fire in the neighbor {x, y, z} - /* - FLOG("FS: Trying to start fire at {%d, %d, %d}.", - x + a_Chunk->GetPosX() * cChunkDef::Width, y, z + a_Chunk->GetPosZ() * cChunkDef::Width - ); - */ - if (CanStartFireInBlock(a_Chunk, x, y, z)) - { - FLOG("FS: Starting new fire at {%d, %d, %d}.", - x + a_Chunk->GetPosX() * cChunkDef::Width, y, z + a_Chunk->GetPosZ() * cChunkDef::Width - ); - a_Chunk->UnboundedRelSetBlock(x, y, z, E_BLOCK_FIRE, 0); - } - } // for y - } // for z - } // for x -} - - - - - -void cFireSimulator::RemoveFuelNeighbors(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ) -{ - for (int i = 0; i < ARRAYCOUNT(gNeighborCoords); i++) - { - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - if (!a_Chunk->UnboundedRelGetBlock(a_RelX + gNeighborCoords[i].x, a_RelY + gNeighborCoords[i].y, a_RelZ + gNeighborCoords[i].z, BlockType, BlockMeta)) - { - // Neighbor not accessible, ignore it - continue; - } - if (!IsFuel(BlockType)) - { - continue; - } - bool ShouldReplaceFuel = (m_World.GetTickRandomNumber(MAX_CHANCE_REPLACE_FUEL) < m_ReplaceFuelChance); - a_Chunk->UnboundedRelSetBlock( - a_RelX + gNeighborCoords[i].x, a_RelY + gNeighborCoords[i].y, a_RelZ + gNeighborCoords[i].z, - ShouldReplaceFuel ? E_BLOCK_FIRE : E_BLOCK_AIR, 0 - ); - } // for i - Coords[] -} - - - - - -bool cFireSimulator::CanStartFireInBlock(cChunk * a_NearChunk, int a_RelX, int a_RelY, int a_RelZ) -{ - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - if (!a_NearChunk->UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockType, BlockMeta)) - { - // The chunk is not accessible - return false; - } - - if (BlockType != E_BLOCK_AIR) - { - // Only an air block can be replaced by a fire block - return false; - } - - for (int i = 0; i < ARRAYCOUNT(gNeighborCoords); i++) - { - if (!a_NearChunk->UnboundedRelGetBlock(a_RelX + gNeighborCoords[i].x, a_RelY + gNeighborCoords[i].y, a_RelZ + gNeighborCoords[i].z, BlockType, BlockMeta)) - { - // Neighbor inaccessible, skip it while evaluating - continue; - } - if (IsFuel(BlockType)) - { - return true; - } - } // for i - Coords[] - return false; -} - - - - |