Exemplo n.º 1
0
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);
}
Exemplo n.º 2
0
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);
}
Exemplo n.º 3
0
/// 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;
}
Exemplo n.º 4
0
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();
	}
}	
Exemplo n.º 5
0
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);
}
Exemplo n.º 6
0
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)
}
Exemplo n.º 7
0
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();
	}
}
Exemplo n.º 8
0
/// 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;
}
Exemplo n.º 9
0
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();
}
Exemplo n.º 10
0
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)
}