diff --git a/src/BlockID.h b/src/BlockID.h index 2fec512e2..a227245aa 100644 --- a/src/BlockID.h +++ b/src/BlockID.h @@ -503,6 +503,10 @@ enum E_META_PLANKS_CONIFER = 1, E_META_PLANKS_BIRCH = 2, E_META_PLANKS_JUNGLE = 3, + + // E_BLOCK_(XXX_WEIGHTED)_PRESSURE_PLATE metas: + E_META_PRESSURE_PLATE_RAISED = 0, + E_META_PRESSURE_PLATE_DEPRESSED = 1, // E_BLOCK_QUARTZ_BLOCK metas: E_META_QUARTZ_NORMAL = 0, diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index e0640a409..1bedf7e5e 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -537,13 +537,14 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_Block unsigned char MyPower; if (!IsWirePowered(a_BlockX, a_BlockY, a_BlockZ, MyPower)) { - m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, 0); + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0); + m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); return; } - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MyPower); // Maximum power + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MyPower); - if (MyPower < 2) + if (MyPower < 1) { return; } @@ -1015,16 +1016,13 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc break; } case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: - case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: - case E_BLOCK_WOODEN_PRESSURE_PLATE: { class cPressurePlateCallback : public cEntityCallback { public: - cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : - m_Entity(NULL), - m_World(a_World), + cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) : + m_NumberOfEntities(0), m_X(a_BlockX), m_Y(a_BlockY), m_Z(a_BlockZ) @@ -1039,7 +1037,140 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc if (Distance <= 0.7) { - m_Entity = a_Entity; + m_NumberOfEntities++; + } + return false; + } + + bool GetPowerLevel(unsigned char & a_PowerLevel) const + { + a_PowerLevel = std::min(m_NumberOfEntities, MAX_POWER_LEVEL); + return (a_PowerLevel > 0); + } + + protected: + int m_NumberOfEntities; + + int m_X; + int m_Y; + int m_Z; + }; + + cPressurePlateCallback PressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ); + m_World.ForEachEntity(PressurePlateCallback); + + unsigned char Power; + NIBBLETYPE Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + if (PressurePlateCallback.GetPowerLevel(Power)) + { + if (Meta == E_META_PRESSURE_PLATE_RAISED) + { + m_World.BroadcastSoundEffect("random.click", (int)((a_BlockX + 0.5) * 8.0), (int)((a_BlockY + 0.1) * 8.0), (int)((a_BlockZ + 0.5) * 8.0), 0.3F, 0.5F); + } + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_DEPRESSED); + SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType, Power); + } + else + { + if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) + { + m_World.BroadcastSoundEffect("random.click", (int)((a_BlockX + 0.5) * 8.0), (int)((a_BlockY + 0.1) * 8.0), (int)((a_BlockZ + 0.5) * 8.0), 0.3F, 0.6F); + } + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_RAISED); + m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + } + + break; + } + case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: + {class cPressurePlateCallback : + public cEntityCallback + { + public: + cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) : + m_NumberOfEntities(0), + m_X(a_BlockX), + m_Y(a_BlockY), + m_Z(a_BlockZ) + { + } + + virtual bool Item(cEntity * a_Entity) override + { + Vector3f EntityPos = a_Entity->GetPosition(); + Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f); + double Distance = (EntityPos - BlockPos).Length(); + + if (Distance <= 0.7) + { + m_NumberOfEntities++; + } + return false; + } + + bool GetPowerLevel(unsigned char & a_PowerLevel) const + { + a_PowerLevel = std::min((int)ceil(m_NumberOfEntities / (float)10), MAX_POWER_LEVEL); + return (a_PowerLevel > 0); + } + + protected: + int m_NumberOfEntities; + + int m_X; + int m_Y; + int m_Z; + }; + + cPressurePlateCallback PressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ); + m_World.ForEachEntity(PressurePlateCallback); + + unsigned char Power; + NIBBLETYPE Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + if (PressurePlateCallback.GetPowerLevel(Power)) + { + if (Meta == E_META_PRESSURE_PLATE_RAISED) + { + m_World.BroadcastSoundEffect("random.click", (int)((a_BlockX + 0.5) * 8.0), (int)((a_BlockY + 0.1) * 8.0), (int)((a_BlockZ + 0.5) * 8.0), 0.3F, 0.5F); + } + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_DEPRESSED); + SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType, Power); + } + else + { + if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) + { + m_World.BroadcastSoundEffect("random.click", (int)((a_BlockX + 0.5) * 8.0), (int)((a_BlockY + 0.1) * 8.0), (int)((a_BlockZ + 0.5) * 8.0), 0.3F, 0.6F); + } + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_RAISED); + m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + } + + break; + } + case E_BLOCK_WOODEN_PRESSURE_PLATE: + { + class cPressurePlateCallback : + public cEntityCallback + { + public: + cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) : + m_FoundEntity(false), + m_X(a_BlockX), + m_Y(a_BlockY), + m_Z(a_BlockZ) + { + } + + virtual bool Item(cEntity * a_Entity) override + { + Vector3f EntityPos = a_Entity->GetPosition(); + Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f); + double Distance = (EntityPos - BlockPos).Length(); + + if (Distance <= 0.7) + { + m_FoundEntity = true; return true; // Break out, we only need to know for plates that at least one entity is on top } return false; @@ -1047,45 +1178,46 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc bool FoundEntity(void) const { - return m_Entity != NULL; + return m_FoundEntity; } protected: - cEntity * m_Entity; - cWorld * m_World; + bool m_FoundEntity; int m_X; int m_Y; int m_Z; } ; - cPressurePlateCallback PressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ, &m_World); + cPressurePlateCallback PressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ); m_World.ForEachEntity(PressurePlateCallback); NIBBLETYPE Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); if (PressurePlateCallback.FoundEntity()) { - if (Meta == 0x0) + if (Meta == E_META_PRESSURE_PLATE_RAISED) { m_World.BroadcastSoundEffect("random.click", (int) ((a_BlockX + 0.5) * 8.0), (int) ((a_BlockY + 0.1) * 8.0), (int) ((a_BlockZ + 0.5) * 8.0), 0.3F, 0.5F); } - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1); + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_DEPRESSED); SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType); } else { - if (Meta == 0x1) + if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) { m_World.BroadcastSoundEffect("random.click", (int) ((a_BlockX + 0.5) * 8.0), (int) ((a_BlockY + 0.1) * 8.0), (int) ((a_BlockZ + 0.5) * 8.0), 0.3F, 0.6F); } - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0); + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_RAISED); m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); } break; } default: + { LOGD("Unimplemented pressure plate type %s in cRedstoneSimulator", ItemToFullString(a_MyType).c_str()); break; + } } } @@ -1426,7 +1558,7 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int -void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock) +void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock, unsigned char a_PowerLevel) { static const struct { @@ -1443,7 +1575,7 @@ void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_Bloc for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through struct to power all directions { - SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, a_SourceBlock); + SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, a_SourceBlock, a_PowerLevel); } } @@ -1460,21 +1592,25 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, return; } - PoweredBlocksList * Powered = m_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ)->GetRedstoneSimulatorPoweredBlocksList(); - for (PoweredBlocksList::const_iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list + auto Powered = m_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ)->GetRedstoneSimulatorPoweredBlocksList(); + for (auto itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list { if ( itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) && itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)) ) { - // Check for duplicates + // Check for duplicates, update power level if everything else the same but either way, don't add a new listing + if (itr->a_PowerLevel != a_PowerLevel) + { + itr->a_PowerLevel = a_PowerLevel; + } return; } } - PoweredBlocksList * OtherPowered = m_Chunk->GetNeighborChunk(a_SourceX, a_SourceZ)->GetRedstoneSimulatorPoweredBlocksList(); - for (PoweredBlocksList::const_iterator itr = OtherPowered->begin(); itr != OtherPowered->end(); ++itr) // Check powered list + auto OtherPowered = m_Chunk->GetNeighborChunk(a_SourceX, a_SourceZ)->GetRedstoneSimulatorPoweredBlocksList(); + for (auto itr = OtherPowered->cbegin(); itr != OtherPowered->cend(); ++itr) // Check powered list { if ( itr->a_BlockPos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)) && @@ -1515,8 +1651,8 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( return; } - LinkedBlocksList * Linked = m_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ)->GetRedstoneSimulatorLinkedBlocksList(); - for (LinkedBlocksList::const_iterator itr = Linked->begin(); itr != Linked->end(); ++itr) // Check linked powered list + auto Linked = m_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ)->GetRedstoneSimulatorLinkedBlocksList(); + for (auto itr = Linked->begin(); itr != Linked->end(); ++itr) // Check linked powered list { if ( itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) && @@ -1524,7 +1660,11 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)) ) { - // Check for duplicates + // Check for duplicates, update power level if everything else the same but either way, don't add a new listing + if (itr->a_PowerLevel != a_PowerLevel) + { + itr->a_PowerLevel = a_PowerLevel; + } return; } } diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h index 21bf11887..f52c50f9c 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator.h @@ -36,6 +36,8 @@ public: private: + #define MAX_POWER_LEVEL 15 + struct sPoweredBlocks // Define structure of the directly powered blocks list { Vector3i a_BlockPos; // Position of powered block @@ -134,15 +136,15 @@ private: /* ====== Helper functions ====== */ /** Marks a block as powered */ - void SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, unsigned char a_PowerLevel = 15); + void SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL); /** Marks a block as being powered through another block */ - void SetBlockLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MiddleX, int a_MiddleY, int a_MiddleZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddeBlock, unsigned char a_PowerLevel = 15); + void SetBlockLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MiddleX, int a_MiddleY, int a_MiddleZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddeBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL); /** Marks a block as simulated, who should not be simulated further unless their power state changes, to accomodate a player manually toggling the block without triggering the simulator toggling it back */ void SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool WasLastStatePowered); /** Marks the second block in a direction as linked powered */ - void SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceBlock, unsigned char a_PowerLevel = 15); + void SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL); /** Marks all blocks immediately surrounding a coordinate as powered */ - void SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock); + void SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL); /** Queues a repeater to be powered or unpowered */ void QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn);