summaryrefslogblamecommitdiffstats
path: root/source/Blocks/BlockRail.h
blob: 24947c0bc15c45fcb52cdd1952ab3726e1619a79 (plain) (tree)



























































                                                                                                                                                             

                                                                                                                                 





























































































































































































































































                                                                                                                                                                           

#pragma once

#include "BlockEntity.h"
#include "../World.h"





enum ENUM_RAIL_DIRECTIONS
{
	E_RAIL_NORTH_SOUTH = 0,
	E_RAIL_EAST_WEST = 1,
	E_RAIL_ASCEND_EAST = 2,
	E_RAIL_ASCEND_WEST = 3,
	E_RAIL_ASCEND_NORTH = 4,
	E_RAIL_ASCEND_SOUTH = 5,
	E_RAIL_CURVED_SOUTH_EAST = 6,
	E_RAIL_CURVED_SOUTH_WEST = 7,
	E_RAIL_CURVED_NORTH_WEST = 8,
	E_RAIL_CURVED_NORTH_EAST = 9
};

enum ENUM_PURE
{
	E_PURE_UPDOWN = 0,
	E_PURE_DOWN = 1,
	E_PURE_NONE = 2
};





class cBlockRailHandler :
	public cBlockHandler
{
public:
	cBlockRailHandler(BLOCKTYPE a_BlockType)
		: cBlockHandler(a_BlockType)
	{
	}
	
	virtual void PlaceBlock(cWorld * a_World, cPlayer * a_Player, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override
	{
		a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, m_BlockType, FindMeta(a_World, a_BlockX, a_BlockY, a_BlockZ));
		OnPlacedByPlayer(a_World, a_Player, a_BlockX, a_BlockY, a_BlockZ, a_Dir);
		NeighborChanged(a_World, a_BlockX - 1, a_BlockY + 1, a_BlockZ);
		NeighborChanged(a_World, a_BlockX + 1, a_BlockY + 1, a_BlockZ);
		NeighborChanged(a_World, a_BlockX, a_BlockY + 1, a_BlockZ - 1);
		NeighborChanged(a_World, a_BlockX, a_BlockY + 1, a_BlockZ + 1);
		NeighborChanged(a_World, a_BlockX - 1, a_BlockY - 1, a_BlockZ);
		NeighborChanged(a_World, a_BlockX + 1, a_BlockY - 1, a_BlockZ);
		NeighborChanged(a_World, a_BlockX, a_BlockY - 1, a_BlockZ - 1);
		NeighborChanged(a_World, a_BlockX, a_BlockY - 1, a_BlockZ + 1);
	}

	virtual void OnNeighborChanged(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override
	{
		char Meta = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
		if(IsUnstable(a_World, a_BlockX, a_BlockY, a_BlockZ) && Meta != FindMeta(a_World, a_BlockX, a_BlockY, a_BlockZ))
			a_World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, m_BlockType, FindMeta(a_World, a_BlockX, a_BlockY, a_BlockZ));
	}

	virtual bool CanBeAt(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override
	{
		if(!g_BlockIsSolid[a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)])
			return false;
		char Meta = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
		switch(Meta)
		{
			case E_RAIL_ASCEND_EAST:
			{
				if(!g_BlockIsSolid[a_World->GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ)])
					return false;
				break;
			}
			case E_RAIL_ASCEND_WEST:
			{
				if(!g_BlockIsSolid[a_World->GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ)])
					return false;
				break;
			}
			case E_RAIL_ASCEND_NORTH:
			{
				if(!g_BlockIsSolid[a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1)])
					return false;
				break;
			}
			case E_RAIL_ASCEND_SOUTH:
			{
				if(!g_BlockIsSolid[a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1)])
					return false;
				break;
			}
		}
		return true;
	}

	char FindMeta(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ)
	{
		char Meta = 0;
		char RailsCnt = 0;
		bool Neighbors[8]; // 0 - EAST, 1 - WEST, 2 - NORTH, 3 - SOUTH, 4 - EAST UP, 5 - WEST UP, 6 - NORTH UP, 7 - SOUTH UP
		memset(Neighbors, false, sizeof(Neighbors));
		if(IsUnstable(a_World, a_BlockX + 1, a_BlockY, a_BlockZ) || !IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST, E_PURE_DOWN))
			Neighbors[0] = true;
		if(IsUnstable(a_World, a_BlockX - 1, a_BlockY, a_BlockZ) || !IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_WEST, E_PURE_DOWN))
			Neighbors[1] = true;
		if(IsUnstable(a_World, a_BlockX, a_BlockY, a_BlockZ - 1) || !IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH, E_PURE_DOWN))
			Neighbors[2] = true;
		if(IsUnstable(a_World, a_BlockX, a_BlockY, a_BlockZ + 1) || !IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_SOUTH, E_PURE_DOWN))
			Neighbors[3] = true;
		if(IsUnstable(a_World, a_BlockX + 1, a_BlockY + 1, a_BlockZ) || !IsNotConnected(a_World, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_EAST, E_PURE_NONE))
			Neighbors[4] = true;
		if(IsUnstable(a_World, a_BlockX - 1, a_BlockY + 1, a_BlockZ) || !IsNotConnected(a_World, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_WEST, E_PURE_NONE))
			Neighbors[5] = true;
		if(IsUnstable(a_World, a_BlockX, a_BlockY + 1, a_BlockZ - 1) || !IsNotConnected(a_World, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NORTH, E_PURE_NONE))
			Neighbors[6] = true;
		if(IsUnstable(a_World, a_BlockX, a_BlockY + 1, a_BlockZ + 1) || !IsNotConnected(a_World, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_SOUTH, E_PURE_NONE))
			Neighbors[7] = true;
		if(IsUnstable(a_World, a_BlockX + 1, a_BlockY - 1, a_BlockZ) || !IsNotConnected(a_World, a_BlockX, a_BlockY - 1, a_BlockZ, BLOCK_FACE_EAST))
			Neighbors[0] = true;
		if(IsUnstable(a_World, a_BlockX - 1, a_BlockY - 1, a_BlockZ) || !IsNotConnected(a_World, a_BlockX, a_BlockY - 1, a_BlockZ, BLOCK_FACE_WEST))
			Neighbors[1] = true;
		if(IsUnstable(a_World, a_BlockX, a_BlockY - 1, a_BlockZ - 1) || !IsNotConnected(a_World, a_BlockX, a_BlockY - 1, a_BlockZ, BLOCK_FACE_NORTH))
			Neighbors[2] = true;
		if(IsUnstable(a_World, a_BlockX, a_BlockY - 1, a_BlockZ + 1) || !IsNotConnected(a_World, a_BlockX, a_BlockY - 1, a_BlockZ, BLOCK_FACE_SOUTH))
			Neighbors[3] = true;
		for(int i = 0; i < 8; i++)
		{
			if(Neighbors[i])
			{
				RailsCnt++;
			}
		}
		if(RailsCnt == 1)
		{
			if(Neighbors[7]) Meta = E_RAIL_ASCEND_SOUTH;
			else if(Neighbors[6]) Meta = E_RAIL_ASCEND_NORTH;
			else if(Neighbors[5]) Meta = E_RAIL_ASCEND_WEST;
			else if(Neighbors[4]) Meta = E_RAIL_ASCEND_EAST;
			else if(Neighbors[0] || Neighbors[1]) Meta = E_RAIL_EAST_WEST;
			else if(Neighbors[2] || Neighbors[3]) Meta = E_RAIL_NORTH_SOUTH;
			return Meta;
		}
		for(int i = 0; i < 4; i++)
		{
			if(Neighbors[i+4])
			{
				Neighbors[i] = true;
			}
		}
		if(RailsCnt > 1)
		{
			if(Neighbors[3] && Neighbors[0]) Meta = E_RAIL_CURVED_SOUTH_EAST;
			else if(Neighbors[3] && Neighbors[1]) Meta = E_RAIL_CURVED_SOUTH_WEST;
			else if(Neighbors[2] && Neighbors[0]) Meta = E_RAIL_CURVED_NORTH_EAST;
			else if(Neighbors[2] && Neighbors[1]) Meta = E_RAIL_CURVED_NORTH_WEST;
			else if(Neighbors[7] && Neighbors[2]) Meta = E_RAIL_ASCEND_SOUTH;
			else if(Neighbors[3] && Neighbors[6]) Meta = E_RAIL_ASCEND_NORTH;
			else if(Neighbors[5] && Neighbors[0]) Meta = E_RAIL_ASCEND_WEST;
			else if(Neighbors[4] && Neighbors[1]) Meta = E_RAIL_ASCEND_EAST;
			else if(Neighbors[0] && Neighbors[1]) Meta = E_RAIL_EAST_WEST;
			else if(Neighbors[2] && Neighbors[3]) Meta = E_RAIL_NORTH_SOUTH;
		}
		return Meta;
	}

	bool IsUnstable(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ)
	{
		if(a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) != E_BLOCK_RAIL) return false;
		char Meta = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
		switch(Meta)
		{
			case E_RAIL_NORTH_SOUTH:
			{
				if(IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH, E_PURE_DOWN) || 
				   IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_SOUTH, E_PURE_DOWN)) return true;
				break;
			}
			case E_RAIL_EAST_WEST:
			{
				if(IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST, E_PURE_DOWN) || 
				   IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_WEST, E_PURE_DOWN)) return true;
				break;
			}
			case E_RAIL_ASCEND_EAST:
			{
				if(IsNotConnected(a_World, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_EAST) || 
				   IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_WEST)) return true;
				break;
			}
			case E_RAIL_ASCEND_WEST:
			{
				if(IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST) || 
				   IsNotConnected(a_World, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_WEST)) return true;
				break;
			}
			case E_RAIL_ASCEND_NORTH:
			{
				if(IsNotConnected(a_World, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NORTH) || 
				   IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_SOUTH)) return true;
				break;
			}
			case E_RAIL_ASCEND_SOUTH:
			{
				if(IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH) || 
				   IsNotConnected(a_World, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_SOUTH)) return true;
				break;
			}
			case E_RAIL_CURVED_SOUTH_EAST:
			{
				if(IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_SOUTH) || 
				   IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST)) return true;
				break;
			}
			case E_RAIL_CURVED_SOUTH_WEST:
			{
				if(IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_SOUTH) || 
				   IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_WEST)) return true;
				break;
			}
			case E_RAIL_CURVED_NORTH_WEST:
			{
				if(IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH) || 
				   IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_WEST)) return true;
				break;
			}
			case E_RAIL_CURVED_NORTH_EAST:
			{
				if(IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH) || 
				   IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST)) return true;
				break;
			}
		}
		return false;
	}

	bool IsNotConnected(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, char a_Pure = 0)
	{
		AddDirection(a_BlockX, a_BlockY, a_BlockZ, a_Direction, false);
		char Meta;
		if(a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) != E_BLOCK_RAIL)
		{
			if((a_World->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ) != E_BLOCK_RAIL) || (a_Pure != E_PURE_UPDOWN))
			{
				if((a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ) != E_BLOCK_RAIL) || (a_Pure == E_PURE_NONE))
				{
					return true;
				}
				else
				{
					Meta = a_World->GetBlockMeta(a_BlockX, a_BlockY - 1, a_BlockZ);
				}
			}
			else
			{
				Meta = a_World->GetBlockMeta(a_BlockX, a_BlockY + 1, a_BlockZ);
			}
		}
		else
		{
			Meta = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
		}
		switch(a_Direction)
		{
			case BLOCK_FACE_NORTH:
			{
				if(Meta == E_RAIL_NORTH_SOUTH ||
				   Meta == E_RAIL_ASCEND_NORTH ||
				   Meta == E_RAIL_ASCEND_SOUTH ||
				   Meta == E_RAIL_CURVED_SOUTH_EAST ||
				   Meta == E_RAIL_CURVED_SOUTH_WEST)
				   return false;
				break;
			}
			case BLOCK_FACE_SOUTH:
			{
				if(Meta == E_RAIL_NORTH_SOUTH ||
				   Meta == E_RAIL_ASCEND_NORTH ||
				   Meta == E_RAIL_ASCEND_SOUTH ||
				   Meta == E_RAIL_CURVED_NORTH_EAST ||
				   Meta == E_RAIL_CURVED_NORTH_WEST)
				   return false;
				break;
			}
			case BLOCK_FACE_EAST:
			{
				if(Meta == E_RAIL_EAST_WEST ||
				   Meta == E_RAIL_ASCEND_EAST ||
				   Meta == E_RAIL_ASCEND_WEST ||
				   Meta == E_RAIL_CURVED_SOUTH_WEST ||
				   Meta == E_RAIL_CURVED_NORTH_WEST)
				   return false;
				break;
			}
			case BLOCK_FACE_WEST:
			{
				if(Meta == E_RAIL_EAST_WEST ||
				   Meta == E_RAIL_ASCEND_EAST ||
				   Meta == E_RAIL_ASCEND_WEST ||
				   Meta == E_RAIL_CURVED_SOUTH_EAST ||
				   Meta == E_RAIL_CURVED_NORTH_EAST)
				   return false;
				break;
			}
		}
		return true;
	}
} ;