Beispiel #1
0
void cSquid::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
	m_PathfinderActivated = false;  // Disable Pathfinding until it's fixed. TODO

	// 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 = FloorC(Pos.y);
	if ((RelY < 0) || (RelY >= cChunkDef::Height))
	{
		return;
	}
	int RelX = FloorC(Pos.x) - a_Chunk.GetPosX() * cChunkDef::Width;
	int RelZ = FloorC(Pos.z) - a_Chunk.GetPosZ() * cChunkDef::Width;
	BLOCKTYPE BlockType;
	if (a_Chunk.UnboundedRelGetBlockType(RelX, RelY, RelZ, BlockType) && !IsBlockWater(BlockType) && !IsOnFire())
	{
		// Burn for 10 ticks, then decide again
		StartBurning(10);
	}

	super::Tick(a_Dt, a_Chunk);
}
void cNBTChunkSerializer::AddHangingEntity(cHangingEntity * a_Hanging)
{
	m_Writer.AddInt("TileX", FloorC(a_Hanging->GetPosX()));
	m_Writer.AddInt("TileY", FloorC(a_Hanging->GetPosY()));
	m_Writer.AddInt("TileZ", FloorC(a_Hanging->GetPosZ()));
	m_Writer.AddByte("Facing", a_Hanging->GetProtocolFacing());
}
Beispiel #3
0
	virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override
	{
		int BlockStartX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
		int BlockStartZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
		int BlockEndX = BlockStartX + cChunkDef::Width;
		int BlockEndZ = BlockStartZ + cChunkDef::Width;
		for (sRavineDefPoints::const_iterator itr = m_DefPoints.begin(), end = m_DefPoints.end(); itr != end; ++itr)
		{
			if (
				(ceilf (itr->m_X + itr->m_Radius + 2) < BlockStartX) ||
				(floorf(itr->m_X - itr->m_Radius - 2) > BlockEndX) ||
				(ceilf (itr->m_Z + itr->m_Radius + 2) < BlockStartZ) ||
				(floorf(itr->m_Z - itr->m_Radius - 2) > BlockEndZ)
			)
			{
				// Cannot intersect, bail out early
				continue;
			}

			// Carve out a cylinder around the xz point, up to (m_Radius + 2) in diameter, from Bottom to Top:
			// On each height level, use m_PerHeightRadius[] to modify the actual radius used
			// EnlargedRadiusSq is the square of the radius enlarged by the maximum m_PerHeightRadius offset - anything outside it will never be touched.
			float RadiusSq = (itr->m_Radius + 2) * (itr->m_Radius + 2);
			float DifX = BlockStartX - itr->m_X;  // substitution for faster calc
			float DifZ = BlockStartZ - itr->m_Z;  // substitution for faster calc
			for (int x = 0; x < cChunkDef::Width; x++) for (int z = 0; z < cChunkDef::Width; z++)
			{
				#ifdef _DEBUG
				// DEBUG: Make the roughravine shapepoints visible on a single layer (so that we can see with Minutor what's going on)
				if ((FloorC(DifX + x) == 0) && (FloorC(DifZ + z) == 0))
				{
					a_ChunkDesc.SetBlockType(x, 4, z, E_BLOCK_LAPIS_ORE);
				}
				#endif  // _DEBUG

				// If the column is outside the enlarged radius, bail out completely
				float DistSq = (DifX + x) * (DifX + x) + (DifZ + z) * (DifZ + z);
				if (DistSq > RadiusSq)
				{
					continue;
				}

				int Top = std::min(CeilC(itr->m_Top), +cChunkDef::Height);
				for (int y = std::max(FloorC(itr->m_Bottom), 1); y <= Top; y++)
				{
					if ((itr->m_Radius + m_PerHeightRadius[y]) * (itr->m_Radius + m_PerHeightRadius[y]) < DistSq)
					{
						continue;
					}

					if (cBlockInfo::CanBeTerraformed(a_ChunkDesc.GetBlockType(x, y, z)))
					{
						a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_AIR);
					}
				}  // for y
			}  // for x, z - a_BlockTypes
		}  // for itr - m_Points[]
	}
Beispiel #4
0
void cSplashPotionEntity::Splash(const Vector3d & a_HitPos)
{
	cSplashPotionCallback Callback(a_HitPos, m_EntityEffectType, m_EntityEffect);
	m_World->ForEachEntity(Callback);
	
	m_World->BroadcastSoundParticleEffect(
		EffectID::PARTICLE_SPLASH_POTION,
		FloorC(a_HitPos.x),
		FloorC(a_HitPos.y),
		FloorC(a_HitPos.z),
		m_PotionColor
	);
}
Beispiel #5
0
void cEntityEffectPoison::OnTick(cPawn & a_Target)
{
	super::OnTick(a_Target);

	if (a_Target.IsMob())
	{
		cMonster & Target = reinterpret_cast<cMonster &>(a_Target);

		// Doesn't effect undead mobs, spiders
		if (
			Target.IsUndead() ||
			(Target.GetMobType() == mtSpider) ||
			(Target.GetMobType() == mtCaveSpider)
		)
		{
			return;
		}
	}

	// Poison frequency = 25 ticks, divided by potion level (Poison II = 12 ticks)
	int frequency = FloorC(25.0 / static_cast<double>(m_Intensity + 1));

	if ((m_Ticks % frequency) == 0)
	{
		// Cannot take poison damage when health is at 1
		if (a_Target.GetHealth() > 1)
		{
			a_Target.TakeDamage(dtPoisoning, nullptr, 1, 0);
		}
	}
}
Beispiel #6
0
void GetLargeAppleTreeBranch(int a_BlockX, int a_BlockY, int a_BlockZ, int a_BranchLength, Vector3d a_StartDirection, Vector3d a_Direction, int a_TreeHeight, cNoise & a_Noise, sSetBlockVector & a_LogBlocks)
{
	Vector3d CurrentPos = Vector3d(a_BlockX, a_BlockY, a_BlockZ);
	Vector3d Direction  = a_StartDirection;
	for (int i = 0; i < a_BranchLength; i++)
	{
		CurrentPos += Direction;
		if (CurrentPos.y >= a_TreeHeight)
		{
			return;
		}
		Direction -= a_Direction;
		Direction.clamp(-1.0, 1.0);
		a_LogBlocks.push_back(sSetBlock(FloorC(CurrentPos.x), FloorC(CurrentPos.y), FloorC(CurrentPos.z), E_BLOCK_LOG, GetLogMetaFromDirection(E_META_LOG_APPLE, Direction)));
	}
}
Beispiel #7
0
void cMonster::MoveToWayPoint(cChunk & a_Chunk)
{
	if ((m_NextWayPointPosition - GetPosition()).SqrLength() < WAYPOINT_RADIUS * WAYPOINT_RADIUS)
	{
		return;
	}


	if (m_JumpCoolDown == 0)
	{
		if (DoesPosYRequireJump(FloorC(m_NextWayPointPosition.y)))
		{
			if (((IsOnGround()) && (GetSpeed().SqrLength() == 0.0f)) ||
			(IsSwimming()))
			{
				m_bOnGround = false;
				m_JumpCoolDown = 20;
				// TODO: Change to AddSpeedY once collision detection is fixed - currently, mobs will go into blocks attempting to jump without a teleport
				AddPosY(1.6);  // Jump!!
				SetSpeedX(3.2 * (m_NextWayPointPosition.x - GetPosition().x));  // Move forward in a preset speed.
				SetSpeedZ(3.2 * (m_NextWayPointPosition.z - GetPosition().z));  // The numbers were picked based on trial and error and 1.6 and 3.2 are perfect.
			}
		}
	}
	else
	{
		--m_JumpCoolDown;
	}

	Vector3d Distance = m_NextWayPointPosition - GetPosition();
	if ((Distance.x != 0.0f) || (Distance.z != 0.0f))
	{
		Distance.y = 0;
		Distance.Normalize();

		if (m_bOnGround)
		{
			Distance *= 2.5f;
		}
		else if (IsSwimming())
		{
			Distance *= 1.3f;
		}
		else
		{
			// Don't let the mob move too much if he's falling.
			Distance *= 0.25f;
		}
		// Apply walk speed:
		Distance *= m_RelativeWalkSpeed;
		/* Reduced default speed.
		Close to Vanilla, easier for mobs to follow m_NextWayPointPositions, hence
		better pathfinding. */
		Distance *= 0.5;
		AddSpeedX(Distance.x);
		AddSpeedZ(Distance.z);
	}
}
Beispiel #8
0
int cFurnaceEntity::GetAndResetReward(void)
{
	int Reward = FloorC(m_RewardCounter);
	float Remainder = m_RewardCounter - static_cast<float>(Reward);
	// Remainder is used as the percent chance of getting an extra xp point
	if (GetRandomProvider().RandBool(Remainder))
	{
		Reward++;
	}
	m_RewardCounter = 0.0;
	return Reward;
}
Beispiel #9
0
void cEntityEffectWither::OnTick(cPawn & a_Target)
{
	super::OnTick(a_Target);

	// Damage frequency = 40 ticks, divided by effect level (Wither II = 20 ticks)
	int frequency = FloorC(25.0 / static_cast<double>(m_Intensity + 1));

	if ((m_Ticks % frequency) == 0)
	{
		a_Target.TakeDamage(dtWither, nullptr, 1, 0);
	}
}
Beispiel #10
0
bool cMonster::WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk)
{
	cChunk * Chunk = a_Chunk.GetNeighborChunk(FloorC(a_Location.x), FloorC(a_Location.z));
	if ((Chunk == nullptr) || (!Chunk->IsValid()))
	{
		return false;
	}

	int RelX = FloorC(a_Location.x) - Chunk->GetPosX() * cChunkDef::Width;
	int RelY = FloorC(a_Location.y);
	int RelZ = FloorC(a_Location.z) - Chunk->GetPosZ() * cChunkDef::Width;

	if (
		(Chunk->GetSkyLight(RelX, RelY, RelZ) == 15) &&             // In the daylight
		(Chunk->GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) &&  // Not on soulsand
		(GetWorld()->GetTimeOfDay() < (12000 + 1000)) &&             // It is nighttime
		GetWorld()->IsWeatherSunnyAt(POSX_TOINT, POSZ_TOINT)         // Not raining
	)
	{
		return true;
	}
	return false;
}
cNetherPortalScanner::cNetherPortalScanner(cEntity * a_MovingEntity, cWorld * a_DestinationWorld, Vector3d a_DestPosition, int a_MaxY) :
	m_Entity(a_MovingEntity),
	m_World(a_DestinationWorld),
	m_FoundPortal(false),
	m_BuildPlatform(true),
	m_Dir(Direction::X),
	m_PortalLoc(a_DestPosition.Floor()),
	m_Position(a_DestPosition),
	m_MaxY(a_MaxY)
{
	int MinX = FloorC((m_Position.x - SearchRadius) / cChunkDef::Width);
	int MinZ = FloorC((m_Position.z - SearchRadius) / cChunkDef::Width);
	int MaxX = CeilC((m_Position.x + SearchRadius) / cChunkDef::Width);
	int MaxZ = CeilC((m_Position.z + SearchRadius) / cChunkDef::Width);
	for (int x = MinX; x < MaxX; x++)
	{
		for (int z = MinZ; z < MaxZ; z++)
		{
			Add(x, z);
		}
	}
	Enable(*a_DestinationWorld->GetChunkMap());
}
Beispiel #12
0
int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ)
{
	int PosY = POSY_TOINT;
	PosY = Clamp(PosY, 0, cChunkDef::Height);

	if (!cBlockInfo::IsSolid(m_World->GetBlock(FloorC(a_PosX), PosY, FloorC(a_PosZ))))
	{
		while (!cBlockInfo::IsSolid(m_World->GetBlock(FloorC(a_PosX), PosY, FloorC(a_PosZ))) && (PosY > 0))
		{
			PosY--;
		}

		return PosY + 1;
	}
	else
	{
		while ((PosY < cChunkDef::Height) && cBlockInfo::IsSolid(m_World->GetBlock(static_cast<int>(floor(a_PosX)), PosY, static_cast<int>(floor(a_PosZ)))))
		{
			PosY++;
		}

		return PosY;
	}
}
Beispiel #13
0
void cEntityEffectRegeneration::OnTick(cPawn & a_Target)
{
	super::OnTick(a_Target);

	if (a_Target.IsMob() && reinterpret_cast<cMonster &>(a_Target).IsUndead())
	{
		return;
	}

	// Regen frequency = 50 ticks, divided by potion level (Regen II = 25 ticks)
	int frequency = FloorC(50.0 / static_cast<double>(m_Intensity + 1));

	if ((m_Ticks % frequency) != 0)
	{
		return;
	}

	a_Target.Heal(1);
}
Beispiel #14
0
/* cPath implementation */
cPath::cPath(
	cChunk & a_Chunk,
	const Vector3d & a_StartingPoint, const Vector3d & a_EndingPoint, int a_MaxSteps,
	double a_BoundingBoxWidth, double a_BoundingBoxHeight,
	int a_MaxUp, int a_MaxDown
) :
	m_StepsLeft(a_MaxSteps),
	m_CurrentPoint(0),  // GetNextPoint increments this to 1, but that's fine, since the first cell is always a_StartingPoint
	m_Chunk(&a_Chunk),
	m_BadChunkFound(false)
{
	// TODO: if src not walkable OR dest not walkable, then abort.
	// Borrow a new "isWalkable" from ProcessIfWalkable, make ProcessIfWalkable also call isWalkable

	a_BoundingBoxWidth = 1;  // Until we improve physics, if ever.

	m_BoundingBoxWidth = CeilC(a_BoundingBoxWidth);
	m_BoundingBoxHeight = CeilC(a_BoundingBoxHeight);
	m_HalfWidth = a_BoundingBoxWidth / 2;

	int HalfWidthInt = FloorC(a_BoundingBoxWidth / 2);
	m_Source.x = FloorC(a_StartingPoint.x - HalfWidthInt);
	m_Source.y = FloorC(a_StartingPoint.y);
	m_Source.z = FloorC(a_StartingPoint.z - HalfWidthInt);

	m_Destination.x = FloorC(a_EndingPoint.x - HalfWidthInt);
	m_Destination.y = FloorC(a_EndingPoint.y);
	m_Destination.z = FloorC(a_EndingPoint.z - HalfWidthInt);

	if (GetCell(m_Source)->m_IsSolid || GetCell(m_Destination)->m_IsSolid)
	{
		m_Status = ePathFinderStatus::PATH_NOT_FOUND;
		return;
	}

	m_NearestPointToTarget = GetCell(m_Source);
	m_Status = ePathFinderStatus::CALCULATING;

	ProcessCell(GetCell(m_Source), nullptr, 0);
}
Beispiel #15
0
void cVillager::HandleFarmerPrepareFarmCrops()
{
	if (!m_World->VillagersShouldHarvestCrops())
	{
		return;
	}

	cBlockArea Surrounding;

	// Read a 11x7x11 area:
	Surrounding.Read(
		m_World,
		FloorC(GetPosX()) - 5,
		FloorC(GetPosX()) + 6,
		FloorC(GetPosY()) - 3,
		FloorC(GetPosY()) + 4,
		FloorC(GetPosZ()) - 5,
		FloorC(GetPosZ()) + 6
	);

	for (int I = 0; I < 5; I++)
	{
		for (int Y = 0; Y < 6; Y++)
		{
			// Pick random coordinates and check for crops.
			int X = m_World->GetTickRandomNumber(11);
			int Z = m_World->GetTickRandomNumber(11);

			// A villager can't farm this.
			if (!IsBlockFarmable(Surrounding.GetRelBlockType(X, Y, Z)))
			{
				continue;
			}
			if (Surrounding.GetRelBlockMeta(X, Y, Z) != 0x7)
			{
				continue;
			}

			m_VillagerAction = true;
			m_CropsPos = Vector3i(static_cast<int>(GetPosX()) + X - 5, static_cast<int>(GetPosY()) + Y - 3, static_cast<int>(GetPosZ()) + Z - 5);
			MoveToPosition(Vector3f(static_cast<float>(m_CropsPos.x + 0.5), static_cast<float>(m_CropsPos.y), static_cast<float>(m_CropsPos.z + 0.5)));
			return;
		}  // for Y loop.
	}  // Repeat the procces 5 times.
}
Beispiel #16
0
/* cPath implementation */
cPath::cPath(
	cChunk & a_Chunk,
	const Vector3d & a_StartingPoint, const Vector3d & a_EndingPoint, int a_MaxSteps,
	double a_BoundingBoxWidth, double a_BoundingBoxHeight
) :
	m_StepsLeft(a_MaxSteps),
	m_IsValid(true),
	m_CurrentPoint(0),  // GetNextPoint increments this to 1, but that's fine, since the first cell is always a_StartingPoint
	m_Chunk(&a_Chunk),
	m_BadChunkFound(false)
{

	a_BoundingBoxWidth = 1;  // Treat all mobs width as 1 until physics is improved.

	m_BoundingBoxWidth = CeilC(a_BoundingBoxWidth);
	m_BoundingBoxHeight = CeilC(a_BoundingBoxHeight);
	m_HalfWidth = a_BoundingBoxWidth / 2;

	int HalfWidthInt = FloorC(a_BoundingBoxWidth / 2);
	m_Source.x = FloorC(a_StartingPoint.x - HalfWidthInt);
	m_Source.y = FloorC(a_StartingPoint.y);
	m_Source.z = FloorC(a_StartingPoint.z - HalfWidthInt);

	m_Destination.x = FloorC(a_EndingPoint.x - HalfWidthInt);
	m_Destination.y = FloorC(a_EndingPoint.y);
	m_Destination.z = FloorC(a_EndingPoint.z - HalfWidthInt);

	if (!IsWalkable(m_Source, m_Source))
	{
		m_Status = ePathFinderStatus::PATH_NOT_FOUND;
		return;
	}

	m_NearestPointToTarget = GetCell(m_Source);
	m_Status = ePathFinderStatus::CALCULATING;

	ProcessCell(GetCell(m_Source), nullptr, 0);
}
Beispiel #17
0
bool cMonster::WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk)
{
	// If the Y coord is out of range, return the most logical result without considering anything else:
	int RelY = FloorC(a_Location.y);
	if (RelY < 0)
	{
		// Never burn under the world
		return false;
	}
	if (RelY >= cChunkDef::Height)
	{
		// Always burn above the world
		return true;
	}
	if (RelY <= 0)
	{
		// The mob is about to die, no point in burning
		return false;
	}

	PREPARE_REL_AND_CHUNK(a_Location, a_Chunk);
	if (!RelSuccess)
	{
		return false;
	}

	if (
		(Chunk->GetBlock(Rel.x, Rel.y, Rel.z) != E_BLOCK_SOULSAND) &&  // Not on soulsand
		(GetWorld()->GetTimeOfDay() < 12000 + 1000) &&              // Daytime
		GetWorld()->IsWeatherSunnyAt(POSX_TOINT, POSZ_TOINT)        // Not raining
	)
	{
		int MobHeight = FloorC(a_Location.y + GetHeight()) - 1;  // The block Y coord of the mob's head
		if (MobHeight >= cChunkDef::Height)
		{
			return true;
		}
		// Start with the highest block and scan down to the mob's head.
		// If a non transparent is found, return false (do not burn). Otherwise return true.
		// Note that this loop is not a performance concern as transparent blocks are rare and the loop almost always bailes out
		// instantly.(An exception is e.g. standing under a long column of glass).
		int CurrentBlock = Chunk->GetHeight(Rel.x, Rel.z);
		while (CurrentBlock >= MobHeight)
		{
			BLOCKTYPE Block = Chunk->GetBlock(Rel.x, CurrentBlock, Rel.z);
			if (
				// Do not burn if a block above us meets one of the following conditions:
				(!cBlockInfo::IsTransparent(Block)) ||
				(Block == E_BLOCK_LEAVES) ||
				(Block == E_BLOCK_NEW_LEAVES) ||
				(IsBlockWater(Block))
			)
			{
				return false;
			}
			--CurrentBlock;
		}
		return true;

	}
	return false;
}
Beispiel #18
0
bool cPathFinder::EnsureProperPoint(Vector3d & a_Vector, cChunk & a_Chunk)
{
	cChunk * Chunk = a_Chunk.GetNeighborChunk(FloorC(a_Vector.x), FloorC(a_Vector.z));
	BLOCKTYPE BlockType;
	NIBBLETYPE BlockMeta;

	if ((Chunk == nullptr) || !Chunk->IsValid())
	{
		return false;
	}

	int RelX = FloorC(a_Vector.x) - Chunk->GetPosX() * cChunkDef::Width;
	int RelZ = FloorC(a_Vector.z) - Chunk->GetPosZ() * cChunkDef::Width;

	// If destination in the air, first try to go 1 block north, or east, or west.
	// This fixes the player leaning issue.
	// If that failed, we instead go down to the lowest air block.
	Chunk->GetBlockTypeMeta(RelX, FloorC(a_Vector.y) - 1, RelZ, BlockType, BlockMeta);
	if (!(IsWaterOrSolid(BlockType)))
	{
		bool InTheAir = true;
		int x, z;
		for (z = -1; z <= 1; ++z)
		{
			for (x = -1; x <= 1; ++x)
			{
				if ((x == 0) && (z == 0))
				{
					continue;
				}
				Chunk = a_Chunk.GetNeighborChunk(FloorC(a_Vector.x+x), FloorC(a_Vector.z+z));
				if ((Chunk == nullptr) || !Chunk->IsValid())
				{
					return false;
				}
				RelX = FloorC(a_Vector.x+x) - Chunk->GetPosX() * cChunkDef::Width;
				RelZ = FloorC(a_Vector.z+z) - Chunk->GetPosZ() * cChunkDef::Width;
				Chunk->GetBlockTypeMeta(RelX, FloorC(a_Vector.y) - 1, RelZ, BlockType, BlockMeta);
				if (IsWaterOrSolid((BlockType)))
				{
					a_Vector.x += x;
					a_Vector.z += z;
					InTheAir = false;
					goto breakBothLoops;
				}
			}
		}
		breakBothLoops:

		// Go down to the lowest air block.
		if (InTheAir)
		{
			while (a_Vector.y > 0)
			{
				Chunk->GetBlockTypeMeta(RelX, FloorC(a_Vector.y) - 1, RelZ, BlockType, BlockMeta);
				if (IsWaterOrSolid(BlockType))
				{
					break;
				}
				a_Vector.y -= 1;
			}
		}
	}

	// If destination in water or solid, go up to the first air block.
	while (a_Vector.y < cChunkDef::Height)
	{
		Chunk->GetBlockTypeMeta(RelX, FloorC(a_Vector.y), RelZ, BlockType, BlockMeta);
		if (!IsWaterOrSolid(BlockType))
		{
			break;
		}
		a_Vector.y += 1;
	}

	return true;
}
bool cNetherPortalScanner::OnAllChunksAvailable(void)
{
	if (m_FoundPortal)
	{
		// Find the bottom of this portal
		while (m_World->GetBlock(m_PortalLoc.x, m_PortalLoc.y, m_PortalLoc.z) == E_BLOCK_NETHER_PORTAL)
		{
			m_PortalLoc.y -= 1;
		}
		m_PortalLoc.y += 1;

		// Figure out which way the portal is facing
		int BXP = m_World->GetBlock(m_PortalLoc.x + 1, m_PortalLoc.y, m_PortalLoc.z);
		int BXM = m_World->GetBlock(m_PortalLoc.x - 1, m_PortalLoc.y, m_PortalLoc.z);
		if ((BXP == E_BLOCK_NETHER_PORTAL) || (BXM == E_BLOCK_NETHER_PORTAL))
		{
			// The long axis is along X
			m_Dir = Direction::X;
		}
		else
		{
			// The long axis is along Z
			m_Dir = Direction::Y;
		}
	}
	else
	{
		// Scan the area for a suitable location
		int minx = FloorC(m_Position.x) - BuildSearchRadius;
		int minz = FloorC(m_Position.z) - BuildSearchRadius;
		int maxx = FloorC(m_Position.x) + BuildSearchRadius;
		int maxz = FloorC(m_Position.z) + BuildSearchRadius;
		int maxy = m_MaxY;
		std::vector<Vector3i> Possibilities;
		int x, y, z;
		for (y = 0; y < maxy - PortalHeight; y++)
		{
			for (x = minx; x < maxx - PortalLength; x++)
			{
				for (z = minz; z < maxz - SearchSolidBaseWidth; z++)
				{
					Vector3i Location = Vector3i(x, y, z);
					if (IsValidBuildLocation(Location))
					{
						Possibilities.push_back(Vector3i(x, y, z));
					}
				}
			}
		}

		if (Possibilities.size() > 0)
		{
			m_BuildPlatform = false;

			// Find the nearest
			double DistanceToClosest = (Possibilities[0] - m_Position).SqrLength();
			Vector3i Closest = Possibilities[0];
			for (const auto & itr : Possibilities)
			{
				double Distance = (itr - m_Position).SqrLength();
				if (Distance < DistanceToClosest)
				{
					DistanceToClosest = Distance;
					Closest = itr;
				}
			}

			m_PortalLoc = Closest;
		}
	}
	return true;
}
Beispiel #20
0
void cHorse::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
	super::Tick(a_Dt, a_Chunk);
	if (!IsTicking())
	{
		// The base class tick destroyed us
		return;
	}

	if (!m_bIsMouthOpen)
	{
		if (m_World->GetTickRandomNumber(50) == 25)
		{
			m_bIsMouthOpen = true;
		}
	}
	else
	{
		if (m_World->GetTickRandomNumber(10) == 5)
		{
			m_bIsMouthOpen = false;
		}
	}

	if ((m_Attachee != nullptr) && (!m_bIsTame))
	{
		if (m_TameAttemptTimes < m_TimesToTame)
		{
			if (m_World->GetTickRandomNumber(50) == 25)
			{
				m_World->BroadcastSoundParticleEffect(EffectID::PARTICLE_SMOKE, FloorC(GetPosX()), FloorC(GetPosY()), FloorC(GetPosZ()), int(SmokeDirection::SOUTH_EAST));
				m_World->BroadcastSoundParticleEffect(EffectID::PARTICLE_SMOKE, FloorC(GetPosX()), FloorC(GetPosY()), FloorC(GetPosZ()), int(SmokeDirection::SOUTH_WEST));
				m_World->BroadcastSoundParticleEffect(EffectID::PARTICLE_SMOKE, FloorC(GetPosX()), FloorC(GetPosY()), FloorC(GetPosZ()), int(SmokeDirection::NORTH_EAST));
				m_World->BroadcastSoundParticleEffect(EffectID::PARTICLE_SMOKE, FloorC(GetPosX()), FloorC(GetPosY()), FloorC(GetPosZ()), int(SmokeDirection::NORTH_WEST));

				m_Attachee->Detach();
				m_bIsRearing = true;
			}
		}
		else
		{
			// TODO: emit hearts here
			m_bIsTame = true;
		}
	}

	if (m_bIsRearing)
	{
		if (m_RearTickCount == 20)
		{
			m_bIsRearing = false;
			m_RearTickCount = 0;
		}
		else
		{
			m_RearTickCount++;
		}
	}

	m_World->BroadcastEntityMetadata(*this);
}
Beispiel #21
0
bool cMonster::EnsureProperDestination(cChunk & a_Chunk)
{
	cChunk * Chunk = a_Chunk.GetNeighborChunk(FloorC(m_FinalDestination.x), FloorC(m_FinalDestination.z));
	BLOCKTYPE BlockType;
	NIBBLETYPE BlockMeta;

	if ((Chunk == nullptr) || !Chunk->IsValid())
	{
		return false;
	}

	int RelX = FloorC(m_FinalDestination.x) - Chunk->GetPosX() * cChunkDef::Width;
	int RelZ = FloorC(m_FinalDestination.z) - Chunk->GetPosZ() * cChunkDef::Width;

	// If destination in the air, first try to go 1 block north, or east, or west.
	// This fixes the player leaning issue.
	// If that failed, we instead go down to the lowest air block.
	Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta);
	if (!cBlockInfo::IsSolid(BlockType))
	{
		bool InTheAir = true;
		int x, z;
		for (z = -1; z <= 1; ++z)
		{
			for (x = -1; x <= 1; ++x)
			{
				if ((x==0) && (z==0))
				{
					continue;
				}
				Chunk = a_Chunk.GetNeighborChunk(FloorC(m_FinalDestination.x+x), FloorC(m_FinalDestination.z+z));
				if ((Chunk == nullptr) || !Chunk->IsValid())
				{
					return false;
				}
				RelX = FloorC(m_FinalDestination.x+x) - Chunk->GetPosX() * cChunkDef::Width;
				RelZ = FloorC(m_FinalDestination.z+z) - Chunk->GetPosZ() * cChunkDef::Width;
				Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta);
				if (cBlockInfo::IsSolid(BlockType))
				{
					m_FinalDestination.x += x;
					m_FinalDestination.z += z;
					InTheAir = false;
					goto breakBothLoops;
				}
			}
		}
		breakBothLoops:

		// Go down to the lowest air block.
		if (InTheAir)
		{
			while (m_FinalDestination.y > 0)
			{
				Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta);
				if (cBlockInfo::IsSolid(BlockType))
				{
					break;
				}
				m_FinalDestination.y -= 1;
			}
		}
	}

	// If destination in water, go up to the highest water block.
	// If destination in solid, go up to first air block.
	bool InWater = false;
	while (m_FinalDestination.y < cChunkDef::Height)
	{
		Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y), RelZ, BlockType, BlockMeta);
		if (BlockType == E_BLOCK_STATIONARY_WATER)
		{
			InWater = true;
		}
		else if (cBlockInfo::IsSolid(BlockType))
		{
			InWater = false;
		}
		else
		{
			break;
		}
		m_FinalDestination.y += 1;
	}
	if (InWater)
	{
		m_FinalDestination.y -= 1;
	}


	return true;
}
Beispiel #22
0
void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
{
	HEIGHTTYPE MaxHeight = a_ChunkDesc.GetMaxHeight();

	const int SEGMENT_HEIGHT = 8;
	const int INTERPOL_X = 16;  // Must be a divisor of 16
	const int INTERPOL_Z = 16;  // Must be a divisor of 16
	// Interpolate the chunk in 16 * SEGMENT_HEIGHT * 16 "segments", each SEGMENT_HEIGHT blocks high and each linearly interpolated separately.
	// Have two buffers, one for the lowest floor and one for the highest floor, so that Y-interpolation can be done between them
	// Then swap the buffers and use the previously-top one as the current-bottom, without recalculating it.

	int FloorBuf1[17 * 17];
	int FloorBuf2[17 * 17];
	int * FloorHi = FloorBuf1;
	int * FloorLo = FloorBuf2;
	int BaseX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
	int BaseZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;

	// Interpolate the lowest floor:
	for (int z = 0; z <= 16 / INTERPOL_Z; z++) for (int x = 0; x <= 16 / INTERPOL_X; x++)
	{
		//*
		FloorLo[INTERPOL_X * x + 17 * INTERPOL_Z * z] =
			m_Noise1.IntNoise3DInt(BaseX + INTERPOL_X * x, 0, BaseZ + INTERPOL_Z * z) *
			m_Noise2.IntNoise3DInt(BaseX + INTERPOL_X * x, 0, BaseZ + INTERPOL_Z * z) /
			256;
		//*/
		/*
		FloorLo[INTERPOL_X * x + 17 * INTERPOL_Z * z] =
			m_Noise1.IntNoise3DInt(BaseX + INTERPOL_X * x, 0, BaseZ + INTERPOL_Z * z) / 256;
		//*/
	}  // for x, z - FloorLo[]
	LinearUpscale2DArrayInPlace<17, 17, INTERPOL_X, INTERPOL_Z>(FloorLo);

	// Interpolate segments:
	for (int Segment = 0; Segment < MaxHeight; Segment += SEGMENT_HEIGHT)
	{
		// First update the high floor:
		for (int z = 0; z <= 16 / INTERPOL_Z; z++) for (int x = 0; x <= 16 / INTERPOL_X; x++)
		{
			//*
			FloorHi[INTERPOL_X * x + 17 * INTERPOL_Z * z] =
				m_Noise1.IntNoise3DInt(BaseX + INTERPOL_X * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) *
				m_Noise2.IntNoise3DInt(BaseX + INTERPOL_Z * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) /
				256;
			//*/
			/*
			FloorHi[INTERPOL_X * x + 17 * INTERPOL_Z * z] =
				m_Noise1.IntNoise3DInt(BaseX + INTERPOL_X * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) / 256;
			//*/
		}  // for x, z - FloorLo[]
		LinearUpscale2DArrayInPlace<17, 17, INTERPOL_X, INTERPOL_Z>(FloorHi);

		// Interpolate between FloorLo and FloorHi:
		for (int z = 0; z < 16; z++) for (int x = 0; x < 16; x++)
		{
			int Threshold = static_cast<int>(m_Noise1.CubicNoise2D(static_cast<float>(BaseX + x) / 75, static_cast<float>(BaseZ + z) / 75) * m_MaxThreshold);
			int Lo = FloorLo[x + 17 * z] / 256;
			int Hi = FloorHi[x + 17 * z] / 256;
			for (int y = 0; y < SEGMENT_HEIGHT; y++)
			{
				int Val = Lo + (Hi - Lo) * y / SEGMENT_HEIGHT;
				if (Val < Threshold)  // Don't calculate if the block should be Netherrack when it's already decided that it's air.
				{
					a_ChunkDesc.SetBlockType(x, y + Segment, z, E_BLOCK_NETHERRACK);
				}
			}
		}

		// Swap the floors:
		std::swap(FloorLo, FloorHi);
	}

	// Bedrock at the bottom and at the top:
	for (int z = 0; z < 16; z++) for (int x = 0; x < 16; x++)
	{
		a_ChunkDesc.SetBlockType(x, 0, z, E_BLOCK_BEDROCK);

		int Height = a_ChunkDesc.GetHeight(x, z);
		a_ChunkDesc.SetBlockType(x, Height, z, E_BLOCK_BEDROCK);

		NOISE_DATATYPE CeilingDisguise = (m_Noise1.CubicNoise2D(static_cast<float>(a_ChunkDesc.GetChunkX() * cChunkDef::Width + x) / 10, static_cast<float>(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + z) / 10));
		if (CeilingDisguise < 0)
		{
			CeilingDisguise = -CeilingDisguise;
		}

		int CeilingDisguiseHeight = Height - 2 - FloorC(CeilingDisguise * 3);

		for (int y = Height - 1; y > CeilingDisguiseHeight; y--)
		{
			a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_NETHERRACK);
		}
	}
}