void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) { int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width; int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width; int PosY = POSY_TOINT; if ((PosY < 0) || (PosY >= cChunkDef::Height)) { goto setspeed; } if (m_IsInGround) { if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) == E_BLOCK_AIR) { m_IsInGround = false; } else { return; } } else { if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) != E_BLOCK_AIR) { OnHitSolidBlock(GetPosition(), BLOCK_FACE_YM); return; } } setspeed: AddSpeedY(1); AddPosition(GetSpeed() * (a_Dt / 1000)); }
/// Moves items from the container above it into this hopper. Returns true if the contents have changed. bool cHopperEntity::MoveItemsIn(cChunk & a_Chunk, Int64 a_CurrentTick) { if (m_PosY >= cChunkDef::Height) { // This hopper is at the top of the world, no more blocks above return false; } if (a_CurrentTick - m_LastMoveItemsInTick < TICKS_PER_TRANSFER) { // Too early after the previous transfer return false; } // Try moving an item in: bool res = false; switch (a_Chunk.GetBlock(m_RelX, m_PosY + 1, m_RelZ)) { case E_BLOCK_CHEST: res = MoveItemsFromChest(a_Chunk); break; case E_BLOCK_FURNACE: res = MoveItemsFromFurnace(a_Chunk); break; case E_BLOCK_DISPENSER: case E_BLOCK_DROPPER: res = MoveItemsFromGrid(((cDropSpenserEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ))->GetContents()); break; case E_BLOCK_HOPPER: res = MoveItemsFromGrid(((cHopperEntity *) a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ))->GetContents()); break; case E_BLOCK_LIT_FURNACE: res = MoveItemsFromFurnace(a_Chunk); break; } // If the item has been moved, reset the last tick: if (res) { m_LastMoveItemsInTick = a_CurrentTick; } return res; }
void cMonster::HandleDaylightBurning(cChunk & a_Chunk) { if (!m_BurnsInDaylight) { return; } int RelY = POSY_TOINT; if ((RelY < 0) || (RelY >= cChunkDef::Height)) { // Outside the world return; } int RelX = POSX_TOINT - GetChunkX() * cChunkDef::Width; int RelZ = POSZ_TOINT - GetChunkZ() * cChunkDef::Width; if (!a_Chunk.IsLightValid()) { m_World->QueueLightChunk(GetChunkX(), GetChunkZ()); return; } if ( (a_Chunk.GetSkyLight(RelX, RelY, RelZ) == 15) && // In the daylight (a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand (GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime !IsOnFire() && // Not already burning (GetWorld()->GetWeather() != eWeather_Rain) // Not raining ) { // Burn for 100 ticks, then decide again StartBurning(100); } }
void cMonster::HandleDaylightBurning(cChunk & a_Chunk) { if (!m_BurnsInDaylight) { return; } int RelY = (int)floor(GetPosY()); if ((RelY < 0) || (RelY >= cChunkDef::Height)) { // Outside the world return; } int RelX = (int)floor(GetPosX()) - GetChunkX() * cChunkDef::Width; int RelZ = (int)floor(GetPosZ()) - GetChunkZ() * cChunkDef::Width; if ( (a_Chunk.GetSkyLight(RelX, RelY, RelZ) == 15) && // In the daylight (a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand (GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime !IsOnFire() // Not already burning ) { // Burn for 100 ticks, then decide again StartBurning(100); } }
/// Moves items from the container above it into this hopper. Returns true if the contents have changed. bool cHopperEntity::MoveItemsIn(cChunk & a_Chunk, Int64 a_CurrentTick) { if (m_PosY >= cChunkDef::Height) { // This hopper is at the top of the world, no more blocks above return false; } if (a_CurrentTick - m_LastMoveItemsInTick < TICKS_PER_TRANSFER) { // Too early after the previous transfer return false; } // Try moving an item in: bool res = false; switch (a_Chunk.GetBlock(m_RelX, m_PosY + 1, m_RelZ)) { case E_BLOCK_TRAPPED_CHEST: case E_BLOCK_CHEST: { // Chests have special handling because of double-chests res = MoveItemsFromChest(a_Chunk); break; } case E_BLOCK_LIT_FURNACE: case E_BLOCK_FURNACE: { // Furnaces have special handling because only the output and leftover fuel buckets shall be moved res = MoveItemsFromFurnace(a_Chunk); break; } case E_BLOCK_DISPENSER: case E_BLOCK_DROPPER: case E_BLOCK_HOPPER: { res = MoveItemsFromGrid(*(cBlockEntityWithItems *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ)); break; } } // If the item has been moved, reset the last tick: if (res) { m_LastMoveItemsInTick = a_CurrentTick; } return res; }
void cSquid::Tick(float a_Dt, cChunk & a_Chunk) { // We must first process current location, and only then tick, otherwise we risk processing a location in a chunk // that is not where the entity currently resides (FS #411) Vector3d Pos = GetPosition(); // TODO: Not a real behavior, but cool :D int RelY = (int)floor(Pos.y); if ((RelY < 0) || (RelY >= cChunkDef::Height)) { return; } int RelX = (int)floor(Pos.x) - a_Chunk.GetPosX() * cChunkDef::Width; int RelZ = (int)floor(Pos.z) - a_Chunk.GetPosZ() * cChunkDef::Width; if (!IsBlockWater(a_Chunk.GetBlock(RelX, RelY, RelZ)) && !IsOnFire()) { // Burn for 10 ticks, then decide again StartBurning(10); } super::Tick(a_Dt, a_Chunk); }
void cFallingBlock::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) { // GetWorld()->BroadcastTeleportEntity(*this); // Test position int BlockX = POSX_TOINT; int BlockY = (int)(GetPosY() - 0.5); int BlockZ = POSZ_TOINT; if (BlockY < 0) { // Fallen out of this world, just continue falling until out of sight, then destroy: if (BlockY < VOID_BOUNDARY) { Destroy(true); } return; } if (BlockY >= cChunkDef::Height) { // Above the world, just wait for it to fall back down return; } BLOCKTYPE BlockBelow = a_Chunk.GetBlock(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width); NIBBLETYPE BelowMeta = a_Chunk.GetMeta(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width); if (cSandSimulator::DoesBreakFallingThrough(BlockBelow, BelowMeta)) { // Fallen onto a block that breaks this into pickups (e. g. half-slab) // Must finish the fall with coords one below the block: cSandSimulator::FinishFalling(m_World, BlockX, BlockY, BlockZ, m_BlockType, m_BlockMeta); Destroy(true); return; } else if (!cSandSimulator::CanContinueFallThrough(BlockBelow)) { // Fallen onto a solid block /* LOGD( "Sand: Checked below at {%d, %d, %d} (rel {%d, %d, %d}), it's %s, finishing the fall.", BlockX, BlockY, BlockZ, BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width, ItemTypeToString(BlockBelow).c_str() ); */ if (BlockY < cChunkDef::Height - 1) { cSandSimulator::FinishFalling(m_World, BlockX, BlockY + 1, BlockZ, m_BlockType, m_BlockMeta); } Destroy(true); return; } float MilliDt = a_Dt.count() * 0.001f; AddSpeedY(MilliDt * -9.8f); AddPosition(GetSpeed() * MilliDt); // If not static (one billionth precision) broadcast movement if ((fabs(GetSpeedX()) > std::numeric_limits<double>::epsilon()) || (fabs(GetSpeedZ()) > std::numeric_limits<double>::epsilon())) { BroadcastMovementUpdate(); } }