void cDropSpenserEntity::DropFromSlot(cChunk & a_Chunk, int a_SlotNum) { int DispX = m_PosX; int DispY = m_PosY; int DispZ = m_PosZ; NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ); AddDropSpenserDir(DispX, DispY, DispZ, Meta); cItems Pickups; Pickups.push_back(m_Contents.RemoveOneItem(a_SlotNum)); const int PickupSpeed = m_World->GetTickRandomNumber(4) + 2; // At least 2, at most 6 int PickupSpeedX = 0, PickupSpeedY = 0, PickupSpeedZ = 0; switch (Meta) { case E_META_DROPSPENSER_FACING_YP: PickupSpeedY = PickupSpeed; break; case E_META_DROPSPENSER_FACING_YM: PickupSpeedY = -PickupSpeed; break; case E_META_DROPSPENSER_FACING_XM: PickupSpeedX = -PickupSpeed; break; case E_META_DROPSPENSER_FACING_XP: PickupSpeedX = PickupSpeed; break; case E_META_DROPSPENSER_FACING_ZM: PickupSpeedZ = -PickupSpeed; break; case E_META_DROPSPENSER_FACING_ZP: PickupSpeedZ = PickupSpeed; break; } double MicroX, MicroY, MicroZ; MicroX = DispX + 0.5; MicroY = DispY + 0.4; // Slightly less than half, to accomodate actual texture hole on DropSpenser MicroZ = DispZ + 0.5; m_World->SpawnItemPickups(Pickups, MicroX, MicroY, MicroZ, PickupSpeedX, PickupSpeedY, PickupSpeedZ); }
void cDropSpenserEntity::DropFromSlot(cChunk & a_Chunk, int a_SlotNum) { int DispX = m_PosX; int DispY = m_PosY; int DispZ = m_PosZ; NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ); AddDropSpenserDir(DispX, DispY, DispZ, Meta); cItems Pickups; Pickups.push_back(m_Contents.RemoveOneItem(a_SlotNum)); m_World->SpawnItemPickups(Pickups, DispX, DispY, DispZ); }
/// Moves items out from this hopper into the destination. Returns true if the contents have changed. bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick) { if (a_CurrentTick - m_LastMoveItemsOutTick < TICKS_PER_TRANSFER) { // Too early after the previous transfer return false; } int bx, by, bz; NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ); if (!GetOutputBlockPos(Meta, bx, by, bz)) { // Not attached to another container return false; } if (by < 0) { // Cannot output below the zero-th block level return false; } // Convert coords to relative: int rx = bx - a_Chunk.GetPosX() * cChunkDef::Width; int rz = bz - a_Chunk.GetPosZ() * cChunkDef::Width; cChunk * DestChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(rx, rz); if (DestChunk == NULL) { // The destination chunk has been unloaded, don't tick return false; } // Call proper moving function, based on the blocktype present at the coords: bool res = false; switch (DestChunk->GetBlock(rx, by, rz)) { case E_BLOCK_CHEST: res = MoveItemsToChest(*DestChunk, bx, by, bz); break; case E_BLOCK_FURNACE: res = MoveItemsToFurnace(*DestChunk, bx, by, bz, Meta); break; case E_BLOCK_DISPENSER: case E_BLOCK_DROPPER: res = MoveItemsToGrid(((cDropSpenserEntity *)DestChunk->GetBlockEntity(bx, by, bz))->GetContents()); break; case E_BLOCK_HOPPER: res = MoveItemsToGrid(((cHopperEntity *) DestChunk->GetBlockEntity(bx, by, bz))->GetContents()); break; case E_BLOCK_LIT_FURNACE: res = MoveItemsToFurnace(*DestChunk, bx, by, bz, Meta); break; } // If the item has been moved, reset the last tick: if (res) { m_LastMoveItemsOutTick = a_CurrentTick; } return res; }
void cDropSpenserEntity::DropSpense(cChunk & a_Chunk) { // Pick one of the occupied slots: int OccupiedSlots[9]; int SlotsCnt = 0; for (int i = m_Contents.GetNumSlots() - 1; i >= 0; i--) { if (!m_Contents.GetSlot(i).IsEmpty()) { OccupiedSlots[SlotsCnt] = i; SlotsCnt++; } } // for i - m_Contents[] if (SlotsCnt == 0) { // Nothing in the dropspenser, play the click sound m_World->BroadcastSoundEffect("random.click", m_PosX * 8, m_PosY * 8, m_PosZ * 8, 1.0f, 1.2f); return; } int RandomSlot = m_World->GetTickRandomNumber(SlotsCnt - 1); // DropSpense the item, using the specialized behavior in the subclasses: DropSpenseFromSlot(a_Chunk, OccupiedSlots[RandomSlot]); // Broadcast a smoke and click effects: NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ); int SmokeDir = 0; switch (Meta) { case E_META_DROPSPENSER_FACING_XM: SmokeDir = 3; break; case E_META_DROPSPENSER_FACING_XP: SmokeDir = 5; break; case E_META_DROPSPENSER_FACING_ZM: SmokeDir = 1; break; case E_META_DROPSPENSER_FACING_ZP: SmokeDir = 7; break; } m_World->BroadcastSoundParticleEffect(2000, m_PosX * 8, m_PosY * 8, m_PosZ * 8, SmokeDir); m_World->BroadcastSoundEffect("random.click", m_PosX * 8, m_PosY * 8, m_PosZ * 8, 1.0f, 1.0f); // Update the UI window, if open: cWindow * Window = GetWindow(); if (Window != NULL) { Window->BroadcastWholeWindow(); } }
void cDropSpenserEntity::DropSpense(cChunk & a_Chunk) { // Pick one of the occupied slots: int OccupiedSlots[9]; int SlotsCnt = 0; for (int i = m_Contents.GetNumSlots() - 1; i >= 0; i--) { if (!m_Contents.GetSlot(i).IsEmpty()) { OccupiedSlots[SlotsCnt] = i; SlotsCnt++; } } // for i - m_Contents[] if (SlotsCnt == 0) { // Nothing in the dropspenser, play the click sound m_World->BroadcastSoundEffect("random.click", static_cast<double>(m_PosX), static_cast<double>(m_PosY), static_cast<double>(m_PosZ), 1.0f, 1.2f); return; } int RandomSlot = m_World->GetTickRandomNumber(SlotsCnt - 1); // DropSpense the item, using the specialized behavior in the subclasses: DropSpenseFromSlot(a_Chunk, OccupiedSlots[RandomSlot]); // Broadcast a smoke and click effects: NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ); int SmokeDir = 0; switch (Meta) { case E_META_DROPSPENSER_FACING_YP: SmokeDir = 4; break; // YP & YM don't have associated smoke dirs, just do 4 (centre of block) case E_META_DROPSPENSER_FACING_YM: SmokeDir = 4; break; case E_META_DROPSPENSER_FACING_XM: SmokeDir = 3; break; case E_META_DROPSPENSER_FACING_XP: SmokeDir = 5; break; case E_META_DROPSPENSER_FACING_ZM: SmokeDir = 1; break; case E_META_DROPSPENSER_FACING_ZP: SmokeDir = 7; break; } m_World->BroadcastSoundParticleEffect(2000, m_PosX, m_PosY, m_PosZ, SmokeDir); m_World->BroadcastSoundEffect("random.click", static_cast<double>(m_PosX), static_cast<double>(m_PosY), static_cast<double>(m_PosZ), 1.0f, 1.0f); }
void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) { int DispX = m_RelX; int DispY = m_PosY; int DispZ = m_RelZ; NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ); AddDropSpenserDir(DispX, DispY, DispZ, Meta); cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(DispX, DispZ); if (DispChunk == NULL) { // Would dispense into / interact with a non-loaded chunk, ignore the tick return; } BLOCKTYPE DispBlock = DispChunk->GetBlock(DispX, DispY, DispZ); int BlockX = (DispX + DispChunk->GetPosX() * cChunkDef::Width); int BlockZ = (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); // Dispense the item: switch (m_Contents.GetSlot(a_SlotNum).m_ItemType) { case E_ITEM_BUCKET: { LOGD("Dispensing empty bucket in slot %d; DispBlock is \"%s\" (%d).", a_SlotNum, ItemTypeToString(DispBlock).c_str(), DispBlock); switch (DispBlock) { case E_BLOCK_STATIONARY_WATER: case E_BLOCK_WATER: { if (ScoopUpLiquid(a_SlotNum, E_ITEM_WATER_BUCKET)) { DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_AIR, 0); } break; } case E_BLOCK_STATIONARY_LAVA: case E_BLOCK_LAVA: { if (ScoopUpLiquid(a_SlotNum, E_ITEM_LAVA_BUCKET)) { DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_AIR, 0); } break; } default: { DropFromSlot(a_Chunk, a_SlotNum); break; } } break; } // E_ITEM_BUCKET case E_ITEM_WATER_BUCKET: { LOGD("Dispensing water bucket in slot %d; DispBlock is \"%s\" (%d).", a_SlotNum, ItemTypeToString(DispBlock).c_str(), DispBlock); if (EmptyLiquidBucket(DispBlock, a_SlotNum)) { DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_WATER, 0); } else { DropFromSlot(a_Chunk, a_SlotNum); } break; } case E_ITEM_LAVA_BUCKET: { LOGD("Dispensing lava bucket in slot %d; DispBlock is \"%s\" (%d).", a_SlotNum, ItemTypeToString(DispBlock).c_str(), DispBlock); if (EmptyLiquidBucket(DispBlock, a_SlotNum)) { DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_LAVA, 0); } else { DropFromSlot(a_Chunk, a_SlotNum); } break; } case E_ITEM_SPAWN_EGG: { double MobX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width); double MobZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); if (m_World->SpawnMob(MobX, DispY, MobZ, (cMonster::eType)m_Contents.GetSlot(a_SlotNum).m_ItemDamage) >= 0) { m_Contents.ChangeSlotCount(a_SlotNum, -1); } break; } case E_BLOCK_TNT: { // Spawn a primed TNT entity, if space allows: if (DispChunk->GetBlock(DispX, DispY, DispZ) == E_BLOCK_AIR) { double TNTX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width); double TNTZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); m_World->SpawnPrimedTNT(TNTX, DispY + 0.5, TNTZ, 80, 0); // 80 ticks fuse, no initial velocity m_Contents.ChangeSlotCount(a_SlotNum, -1); } break; } case E_ITEM_FLINT_AND_STEEL: { // Spawn fire if the block in front is air. if (DispChunk->GetBlock(DispX, DispY, DispZ) == E_BLOCK_AIR) { DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_FIRE, 0); bool ItemBroke = m_Contents.DamageItem(a_SlotNum, 1); if (ItemBroke) { m_Contents.ChangeSlotCount(a_SlotNum, -1); } } break; } case E_ITEM_FIRE_CHARGE: { SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkFireCharge, GetShootVector(Meta) * 20); m_Contents.ChangeSlotCount(a_SlotNum, -1); break; } case E_ITEM_ARROW: { SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkArrow, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)); m_Contents.ChangeSlotCount(a_SlotNum, -1); break; } case E_ITEM_SNOWBALL: { SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkSnowball, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)); m_Contents.ChangeSlotCount(a_SlotNum, -1); break; } case E_ITEM_EGG: { SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkEgg, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)); m_Contents.ChangeSlotCount(a_SlotNum, -1); break; } case E_ITEM_FIREWORK_ROCKET: { // TODO: Add the fireworks entity break; } default: { DropFromSlot(a_Chunk, a_SlotNum); break; } } // switch (ItemType) }
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(); } }
/// Moves items out from this hopper into the destination. Returns true if the contents have changed. bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick) { if (a_CurrentTick - m_LastMoveItemsOutTick < TICKS_PER_TRANSFER) { // Too early after the previous transfer return false; } // Get the coords of the block where to output items: int OutX, OutY, OutZ; NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ); if (!GetOutputBlockPos(Meta, OutX, OutY, OutZ)) { // Not attached to another container return false; } if (OutY < 0) { // Cannot output below the zero-th block level return false; } // Convert coords to relative: int OutRelX = OutX - a_Chunk.GetPosX() * cChunkDef::Width; int OutRelZ = OutZ - a_Chunk.GetPosZ() * cChunkDef::Width; cChunk * DestChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(OutRelX, OutRelZ); if (DestChunk == NULL) { // The destination chunk has been unloaded, don't tick return false; } // Call proper moving function, based on the blocktype present at the coords: bool res = false; switch (DestChunk->GetBlock(OutRelX, OutY, OutRelZ)) { case E_BLOCK_TRAPPED_CHEST: case E_BLOCK_CHEST: { // Chests have special handling because of double-chests res = MoveItemsToChest(*DestChunk, OutX, OutY, OutZ); break; } case E_BLOCK_LIT_FURNACE: case E_BLOCK_FURNACE: { // Furnaces have special handling because of the direction-to-slot relation res = MoveItemsToFurnace(*DestChunk, OutX, OutY, OutZ, Meta); break; } case E_BLOCK_DISPENSER: case E_BLOCK_DROPPER: case E_BLOCK_HOPPER: { cBlockEntityWithItems * BlockEntity = (cBlockEntityWithItems *)DestChunk->GetBlockEntity(OutX, OutY, OutZ); if (BlockEntity == NULL) { LOGWARNING("%s: A block entity was not found where expected at {%d, %d, %d}", __FUNCTION__, OutX, OutY, OutZ); return false; } res = MoveItemsToGrid(*BlockEntity); break; } } // If the item has been moved, reset the last tick: if (res) { m_LastMoveItemsOutTick = a_CurrentTick; } return res; }
void cMinecart::HandleRailPhysics(float a_Dt, cChunk & a_Chunk) { super::HandlePhysics(a_Dt, a_Chunk); // Main physics handling /* NOTE: Please bear in mind that taking away from negatives make them even more negative, adding to negatives make them positive, etc. */ // Get block meta below the cart int RelPosX = (int)floor(GetPosX()) - a_Chunk.GetPosX() * cChunkDef::Width; int RelPosZ = (int)floor(GetPosZ()) - a_Chunk.GetPosZ() * cChunkDef::Width; NIBBLETYPE BelowMeta = a_Chunk.GetMeta(RelPosX, (int)floor(GetPosY() - 1), RelPosZ); double SpeedX = GetSpeedX(), SpeedY = GetSpeedY(), SpeedZ = GetSpeedZ(); // Get current speed switch (BelowMeta) { case E_META_RAIL_ZM_ZP: // NORTHSOUTH { SetRotation(270); SpeedY = 0; // Don't move vertically as on ground SpeedX = 0; // Correct diagonal movement from curved rails if (SpeedZ != 0) // Don't do anything if cart is stationary { if (SpeedZ > 0) { // Going SOUTH, slow down SpeedZ = SpeedZ - 0.1; } else { // Going NORTH, slow down SpeedZ = SpeedZ + 0.1; } } break; } case E_META_RAIL_XM_XP: // EASTWEST { SetRotation(180); SpeedY = 0; SpeedZ = 0; if (SpeedX != 0) { if (SpeedX > 0) { SpeedX = SpeedX - 0.1; } else { SpeedX = SpeedX + 0.1; } } break; } case E_META_RAIL_ASCEND_ZM: // ASCEND NORTH { SetRotation(270); SetPosY(floor(GetPosY()) + 0.2); // It seems it doesn't work without levitation :/ SpeedX = 0; if (SpeedZ >= 0) { // SpeedZ POSITIVE, going SOUTH if (SpeedZ <= MAX_SPEED) // Speed limit { SpeedZ = SpeedZ + 0.5; // Speed up SpeedY = (0 - SpeedZ); // Downward movement is negative (0 minus positive numbers is negative) } else { SpeedZ = MAX_SPEED; // Enforce speed limit SpeedY = (0 - SpeedZ); } } else { // SpeedZ NEGATIVE, going NORTH SpeedZ = SpeedZ + 0.4; // Slow down SpeedY = (0 - SpeedZ); // Upward movement is positive (0 minus negative number is positive number) } break; } case E_META_RAIL_ASCEND_ZP: // ASCEND SOUTH { SetRotation(270); SetPosY(floor(GetPosY()) + 0.2); SpeedX = 0; if (SpeedZ > 0) { // SpeedZ POSITIVE, going SOUTH SpeedZ = SpeedZ - 0.4; // Slow down SpeedY = SpeedZ; // Upward movement positive } else { if (SpeedZ >= MAX_SPEED_NEGATIVE) // Speed limit { // SpeedZ NEGATIVE, going NORTH SpeedZ = SpeedZ - 0.5; // Speed up SpeedY = SpeedZ; // Downward movement negative } else { SpeedZ = MAX_SPEED_NEGATIVE; // Enforce speed limit SpeedY = SpeedZ; } } break; } case E_META_RAIL_ASCEND_XM: // ASCEND EAST { SetRotation(180); SetPosY(floor(GetPosY()) + 0.2); SpeedZ = 0; if (SpeedX >= 0) { if (SpeedX <= MAX_SPEED) { SpeedX = SpeedX + 0.5; SpeedY = (0 - SpeedX); } else { SpeedX = MAX_SPEED; SpeedY = (0 - SpeedX); } } else { SpeedX = SpeedX + 0.4; SpeedY = (0 - SpeedX); } break; } case E_META_RAIL_ASCEND_XP: // ASCEND WEST { SetRotation(180); SetPosY(floor(GetPosY()) + 0.2); SpeedZ = 0; if (SpeedX > 0) { SpeedX = SpeedX - 0.4; SpeedY = SpeedX; } else { if (SpeedX >= MAX_SPEED_NEGATIVE) { SpeedX = SpeedX - 0.5; SpeedY = SpeedX; } else { SpeedX = MAX_SPEED_NEGATIVE; SpeedY = SpeedX; } } break; } case E_META_RAIL_CURVED_ZM_XM: // Ends pointing NORTH and WEST { SetRotation(315); // Set correct rotation server side SetPosY(floor(GetPosY()) + 0.2); // Levitate dat cart if (SpeedZ > 0) // Cart moving south { SpeedX = (0 - SpeedZ); // Diagonally move southwest (which will make cart hit a southwest rail) } else if (SpeedX > 0) // Cart moving east { SpeedZ = (0 - SpeedX); // Diagonally move northeast } break; } case E_META_RAIL_CURVED_ZM_XP: // Curved NORTH EAST { SetRotation(225); SetPosY(floor(GetPosY()) + 0.2); if (SpeedZ > 0) { SpeedX = SpeedZ; } else if (SpeedX < 0) { SpeedZ = SpeedX; } break; } case E_META_RAIL_CURVED_ZP_XM: // Curved SOUTH WEST { SetRotation(135); SetPosY(floor(GetPosY()) + 0.2); if (SpeedZ < 0) { SpeedX = SpeedZ; } else if (SpeedX > 0) { SpeedZ = SpeedX; } break; } case E_META_RAIL_CURVED_ZP_XP: // Curved SOUTH EAST { SetRotation(45); SetPosY(floor(GetPosY()) + 0.2); if (SpeedZ < 0) { SpeedX = (0 - SpeedZ); } else if (SpeedX < 0) { SpeedZ = (0 - SpeedX); } break; } default: { ASSERT(!"Unhandled rail meta!"); // Dun dun DUN! break; } } // Set speed to speed variables SetSpeedX(SpeedX); SetSpeedY(SpeedY); SetSpeedZ(SpeedZ); // Broadcast position to client BroadcastMovementUpdate(); }
void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) { int DispX = m_RelX; int DispY = m_PosY; int DispZ = m_RelZ; NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ); AddDropSpenserDir(DispX, DispY, DispZ, Meta); cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(DispX, DispZ); if (DispChunk == NULL) { // Would dispense into / interact with a non-loaded chunk, ignore the tick return; } BLOCKTYPE DispBlock = DispChunk->GetBlock(DispX, DispY, DispZ); // Dispense the item: switch (m_Contents.GetSlot(a_SlotNum).m_ItemType) { case E_ITEM_BUCKET: { LOGD("Dispensing empty bucket in slot %d; DispBlock is \"%s\" (%d).", a_SlotNum, ItemTypeToString(DispBlock).c_str(), DispBlock); switch (DispBlock) { case E_BLOCK_STATIONARY_WATER: case E_BLOCK_WATER: { if (ScoopUpLiquid(a_SlotNum, E_ITEM_WATER_BUCKET)) { DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_AIR, 0); } break; } case E_BLOCK_STATIONARY_LAVA: case E_BLOCK_LAVA: { if (ScoopUpLiquid(a_SlotNum, E_ITEM_LAVA_BUCKET)) { DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_AIR, 0); } break; } default: { DropFromSlot(a_Chunk, a_SlotNum); break; } } break; } // E_ITEM_BUCKET case E_ITEM_WATER_BUCKET: { LOGD("Dispensing water bucket in slot %d; DispBlock is \"%s\" (%d).", a_SlotNum, ItemTypeToString(DispBlock).c_str(), DispBlock); if (EmptyLiquidBucket(DispBlock, a_SlotNum)) { DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_WATER, 0); } else { DropFromSlot(a_Chunk, a_SlotNum); } break; } case E_ITEM_LAVA_BUCKET: { LOGD("Dispensing lava bucket in slot %d; DispBlock is \"%s\" (%d).", a_SlotNum, ItemTypeToString(DispBlock).c_str(), DispBlock); if (EmptyLiquidBucket(DispBlock, a_SlotNum)) { DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_LAVA, 0); } else { DropFromSlot(a_Chunk, a_SlotNum); } break; } case E_ITEM_SPAWN_EGG: { double MobX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width); double MobZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); if (m_World->SpawnMob(MobX, DispY, MobZ, m_Contents.GetSlot(a_SlotNum).m_ItemDamage) >= 0) { m_Contents.ChangeSlotCount(a_SlotNum, -1); } break; } case E_BLOCK_TNT: { // Spawn a primed TNT entity, if space allows: if (DispChunk->GetBlock(DispX, DispY, DispZ) == E_BLOCK_AIR) { double TNTX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width); double TNTZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); m_World->SpawnPrimedTNT(TNTX, DispY + 0.5, TNTZ, 4, 0); // 4 seconds fuse, no initial velocity m_Contents.ChangeSlotCount(a_SlotNum, -1); } break; } case E_ITEM_FLINT_AND_STEEL: { // Spawn fire if the block in front is air. if (DispChunk->GetBlock(DispX, DispY, DispZ) == E_BLOCK_AIR) { DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_FIRE, 0); m_Contents.SetSlot(a_SlotNum, m_Contents.GetSlot(a_SlotNum).m_ItemType, m_Contents.GetSlot(a_SlotNum).m_ItemCount, m_Contents.GetSlot(a_SlotNum).m_ItemDamage + 1); // If the durability has run out destroy the item. if (m_Contents.GetSlot(a_SlotNum).m_ItemDamage > 64) { m_Contents.ChangeSlotCount(a_SlotNum, -1); } } break; } default: { DropFromSlot(a_Chunk, a_SlotNum); break; } } // switch (ItemType) }