summaryrefslogblamecommitdiffstats
path: root/src/Blocks/BlockFire.h
blob: b6d1d95f28802153d0f626b5a3f2e2ef6ba095dd (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

















                                                
                                                   


                                                                                  
 
                                                                                                                                                                                                       



                                       







                                                                                                                                                                          

                  

                                                                                                            

         








                                                                                          
 

                                                                                                                       
                                                                                                      
         
                                                                           


                                 

                                                                        
                 
                                                                                










                                                                                                                          
                                                                                                                                          






                                                                                                                                     




                         
                                                                            
                                                                                                                 
         
                                                                                                                                                                                                                                
                 
                                                                                             

                                                                                                                 
                                             


                                                           
                            

         
                                                                                                                                   
                                                                                                                               
         

                                                                                                                                                                  
 
                                                                      



                               
                                                                            
                 
                                                                                    
                         
                                                                                             


                         
                                                                                                                     




                                                                    
                                                                                                                                  


                                    
                                                                                                                                  






                                 

                                                                                                                    
                                                                                                         
         
                                                                                                                     
                                                                
                                                                                                                                                                                                              
                 
                                                                                          

                                                                                                                                  
                         
                                                                                                                                              

                                      
                                                                                                                          
                         
                                                                                          
                         

                                                                
                                                                                                                                                                                          
                 

                                                                                                 
                                                              







                                                                       


                                                            



                                                                                                               
                                                                                                         


                                                                
                                                                                                                                                          
                 

                                                                                                 
                                                              

                                                    
                                      




                                                                       

                             
                                                                                                                                                          
                 

                                                                                                 
                                                              

                                                    
                                      




                                                                       


                             


                                                      



 

#pragma once

#include "BlockHandler.h"





class cBlockFireHandler :
	public cBlockHandler
{
public:
	cBlockFireHandler(BLOCKTYPE a_BlockType)
		: cBlockHandler(a_BlockType)
	{
	}

	/// Portal boundary and direction variables
	// 2014_03_30 _X: What are these used for? Why do we need extra variables?
	int XZP, XZM;
	NIBBLETYPE Dir;

	virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
	{
		/*
		PORTAL FINDING ALGORITH
		=======================
		- Get clicked base block
		- Trace upwards to find first obsidian block; aborts if anything other than obsidian or air is encountered.
			Uses this value as a reference (the 'ceiling')
		- For both directions (if one fails, try the other), BASE (clicked) block:
			- Go in one direction, only stop if a non obsidian block is encountered (abort) OR a portal border is encountered (FindObsidianCeiling returns -1)
			- If a border was encountered, go the other direction and repeat above
			- Write borders to XZP and XZM, write direction portal faces to Dir
		- Loop through boundary variables, and fill with portal blocks based on Dir with meta from Dir
		*/

		// a_BlockY - 1: Because we want the block below the fire
		FindAndSetPortalFrame(a_BlockX, a_BlockY - 1, a_BlockZ, a_ChunkInterface, a_WorldInterface);
	}

	virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
	{
		// No pickups from this block
	}

	virtual bool IsClickedThrough(void) override
	{
		return true;
	}

	/** Traces along YP until it finds an obsidian block, returns Y difference or 0 if no portal, and -1 for border
	Takes the X, Y, and Z of the base block; with an optional MaxY for portal border finding */
	int FindObsidianCeiling(int X, int Y, int Z, cChunkInterface & a_ChunkInterface, int MaxY = 0)
	{
		if (a_ChunkInterface.GetBlock(X, Y, Z) != E_BLOCK_OBSIDIAN)
		{
			return 0;
		}
		
		for (int newY = Y + 1; newY < cChunkDef::Height; newY++)
		{
			BLOCKTYPE Block = a_ChunkInterface.GetBlock(X, newY, Z);
			if ((Block == E_BLOCK_AIR) || (Block == E_BLOCK_FIRE))
			{
				continue;
			}
			else if (Block == E_BLOCK_OBSIDIAN)
			{
				// We found an obsidian ceiling
				// Make sure MaxY has a value and newY ('ceiling' location) is at one above the base block
				// This is because the frame is a solid obsidian pillar
				if ((MaxY != 0) && (newY == Y + 1))
				{
					return EvaluatePortalBorder(X, newY, Z, MaxY, a_ChunkInterface) ? -1 /* -1 = found a frame */ : 0;
				}
				else
				{
					// Return ceiling Y, whoever called this function will decide if it's part of a portal or not
					return newY;
				}
			}
		}

		return 0;
	}

	/** Evaluates if coords have a valid border on top, based on MaxY */
	bool EvaluatePortalBorder(int X, int FoundObsidianY, int Z, int MaxY, cChunkInterface & a_ChunkInterface)
	{
		for (int checkBorder = FoundObsidianY + 1; checkBorder <= MaxY - 1; checkBorder++)  // FoundObsidianY + 1: FoundObsidianY has already been checked in FindObsidianCeiling; MaxY - 1: portal doesn't need corners
		{
			if (a_ChunkInterface.GetBlock(X, checkBorder, Z) != E_BLOCK_OBSIDIAN)
			{
				// Base obsidian, base + 1 obsidian, base + x NOT obsidian -> not complete portal
				return false;
			}
		}
		// Everything was obsidian, found a border!
		return true;
	}

	/// Finds entire frame in any direction with the coordinates of a base block and fills hole with nether portal (START HERE)
	void FindAndSetPortalFrame(int X, int Y, int Z, cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface)
	{
		int MaxY = FindObsidianCeiling(X, Y, Z, a_ChunkInterface);  // Get topmost obsidian block as reference for all other checks
		int X1 = X + 1, Z1 = Z + 1, X2 = X - 1, Z2 = Z - 1;  // Duplicate XZ values, add/subtract one as we've checked the original already the line above

		if (MaxY == 0)  // Oh noes! Not a portal coordinate :(
		{
			return;
		}

		if (!FindPortalSliceX(X1, X2, Y, Z, MaxY, a_ChunkInterface))
		{
			if (!FindPortalSliceZ(X, Y, Z1, Z2, MaxY, a_ChunkInterface))
			{
				return;  // No eligible portal construct, abort abort abort!!
			}
		}

		for (int Height = Y + 1; Height <= MaxY - 1; Height++)  // Loop through boundary to set portal blocks
		{
			for (int Width = XZM; Width <= XZP; Width++)
			{
				if (Dir == 1)
				{
					a_ChunkInterface.SetBlock(a_WorldInterface, Width, Height, Z, E_BLOCK_NETHER_PORTAL, Dir);
				}
				else
				{
					a_ChunkInterface.SetBlock(a_WorldInterface, X, Height, Width, E_BLOCK_NETHER_PORTAL, Dir);
				}
			}
		}

		return;
	}

	/** Evaluates if coordinates are a portal going XP/XM; returns true if so, and writes boundaries to variable
	Takes coordinates of base block and Y coord of target obsidian ceiling */
	bool FindPortalSliceX(int X1, int X2, int Y, int Z, int MaxY, cChunkInterface & a_ChunkInterface)
	{
		Dir = 1;  // Set assumed direction (will change if portal turns out to be facing the other direction)
		bool FoundFrameXP = false, FoundFrameXM = false;
		for (; ((a_ChunkInterface.GetBlock(X1, Y, Z) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock(X1, Y + 1, Z) == E_BLOCK_OBSIDIAN)); X1++)  // Check XP for obsidian blocks, exempting corners
		{
			int Value = FindObsidianCeiling(X1, Y, Z, a_ChunkInterface, MaxY);
			int ValueTwo = FindObsidianCeiling(X1, Y + 1, Z, a_ChunkInterface, MaxY);  // For corners without obsidian
			if ((Value == -1) || (ValueTwo == -1))  // FindObsidianCeiling returns -1 upon frame-find
			{
				FoundFrameXP = true;  // Found a frame border in this direction, proceed in other direction (don't go further)
				break;
			}
			else if ((Value != MaxY) && (ValueTwo != MaxY))  // Make sure that there is a valid portal 'slice'
			{
				return false;  // Not valid slice, no portal can be formed
			}
		}
		XZP = X1 - 1;  // Set boundary of frame interior
		for (; ((a_ChunkInterface.GetBlock(X2, Y, Z) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock(X2, Y + 1, Z) == E_BLOCK_OBSIDIAN)); X2--)  // Go the other direction (XM)
		{
			int Value = FindObsidianCeiling(X2, Y, Z, a_ChunkInterface, MaxY);
			int ValueTwo = FindObsidianCeiling(X2, Y + 1, Z, a_ChunkInterface, MaxY);
			if ((Value == -1) || (ValueTwo == -1))
			{
				FoundFrameXM = true;
				break;
			}
			else if ((Value != MaxY) && (ValueTwo != MaxY))
			{
				return false;
			}
		}
		XZM = X2 + 1;  // Set boundary, see previous

		return (FoundFrameXP && FoundFrameXM);
	}

	/// Evaluates if coords are a portal going ZP/ZM; returns true if so, and writes boundaries to variable
	bool FindPortalSliceZ(int X, int Y, int Z1, int Z2, int MaxY, cChunkInterface & a_ChunkInterface)
	{
		Dir = 2;
		bool FoundFrameZP = false, FoundFrameZM = false;
		for (; ((a_ChunkInterface.GetBlock(X, Y, Z1) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock(X, Y + 1, Z1) == E_BLOCK_OBSIDIAN)); Z1++)
		{
			int Value = FindObsidianCeiling(X, Y, Z1, a_ChunkInterface, MaxY);
			int ValueTwo = FindObsidianCeiling(X, Y + 1, Z1, a_ChunkInterface, MaxY);
			if ((Value == -1) || (ValueTwo == -1))
			{
				FoundFrameZP = true;
				break;
			}
			else if ((Value != MaxY) && (ValueTwo != MaxY))
			{
				return false;
			}
		}
		XZP = Z1 - 1;
		for (; ((a_ChunkInterface.GetBlock(X, Y, Z2) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock(X, Y + 1, Z2) == E_BLOCK_OBSIDIAN)); Z2--)
		{
			int Value = FindObsidianCeiling(X, Y, Z2, a_ChunkInterface, MaxY);
			int ValueTwo = FindObsidianCeiling(X, Y + 1, Z2, a_ChunkInterface, MaxY);
			if ((Value == -1) || (ValueTwo == -1))
			{
				FoundFrameZM = true;
				break;
			}
			else if ((Value != MaxY) && (ValueTwo != MaxY))
			{
				return false;
			}
		}
		XZM = Z2 + 1;

		return (FoundFrameZP && FoundFrameZM);
	}
};