2013-07-29 07:13:03 -04:00
# pragma once
# include "BlockHandler.h"
class cBlockFireHandler :
public cBlockHandler
{
public :
cBlockFireHandler ( BLOCKTYPE a_BlockType )
2015-01-23 10:30:38 -05:00
: cBlockHandler ( a_BlockType ) ,
XZP ( 0 ) , XZM ( 0 ) , Dir ( 0 )
2013-07-29 07:13:03 -04:00
{
}
2015-06-30 10:50:15 -04:00
/** Portal boundary and direction variables */
2014-03-30 17:13:13 -04:00
// 2014_03_30 _X: What are these used for? Why do we need extra variables?
int XZP , XZM ;
NIBBLETYPE Dir ;
2013-11-01 20:44:09 -04:00
2014-02-01 08:06:32 -05:00
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
2013-11-01 20:44:09 -04:00
{
/*
PORTAL FINDING ALGORITH
= = = = = = = = = = = = = = = = = = = = = = =
2014-03-30 17:13:13 -04:00
- 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
2013-11-01 20:44:09 -04:00
*/
2014-05-28 10:59:51 -04:00
// a_BlockY - 1: Because we want the block below the fire
FindAndSetPortalFrame ( a_BlockX , a_BlockY - 1 , a_BlockZ , a_ChunkInterface , a_WorldInterface ) ;
2013-11-01 20:44:09 -04:00
}
2013-07-29 07:13:03 -04:00
virtual void ConvertToPickups ( cItems & a_Pickups , NIBBLETYPE a_BlockMeta ) override
{
// No pickups from this block
}
virtual bool IsClickedThrough ( void ) override
{
return true ;
}
2013-11-01 20:44:09 -04:00
2014-08-19 16:14:37 -04:00
/** 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 */
2014-02-01 08:06:32 -05:00
int FindObsidianCeiling ( int X , int Y , int Z , cChunkInterface & a_ChunkInterface , int MaxY = 0 )
2013-11-01 20:44:09 -04:00
{
2014-02-01 08:06:32 -05:00
if ( a_ChunkInterface . GetBlock ( X , Y , Z ) ! = E_BLOCK_OBSIDIAN )
2013-11-01 20:44:09 -04:00
{
return 0 ;
}
2016-02-05 16:45:45 -05:00
2013-12-10 14:35:05 -05:00
for ( int newY = Y + 1 ; newY < cChunkDef : : Height ; newY + + )
2013-11-01 20:44:09 -04:00
{
2014-02-01 08:06:32 -05:00
BLOCKTYPE Block = a_ChunkInterface . GetBlock ( X , newY , Z ) ;
2013-11-01 20:44:09 -04:00
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 ) )
{
2014-05-03 19:38:06 -04:00
return EvaluatePortalBorder ( X , newY , Z , MaxY , a_ChunkInterface ) ? - 1 /* -1 = found a frame */ : 0 ;
2013-11-01 20:44:09 -04:00
}
else
{
// Return ceiling Y, whoever called this function will decide if it's part of a portal or not
return newY ;
}
}
}
return 0 ;
}
2014-08-19 16:14:37 -04:00
/** Evaluates if coords have a valid border on top, based on MaxY */
2014-05-03 19:38:06 -04:00
bool EvaluatePortalBorder ( int X , int FoundObsidianY , int Z , int MaxY , cChunkInterface & a_ChunkInterface )
2013-11-02 09:50:30 -04:00
{
2014-07-17 16:15:34 -04:00
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
2013-11-02 09:50:30 -04:00
{
2014-02-01 08:06:32 -05:00
if ( a_ChunkInterface . GetBlock ( X , checkBorder , Z ) ! = E_BLOCK_OBSIDIAN )
2013-11-02 09:50:30 -04:00
{
// Base obsidian, base + 1 obsidian, base + x NOT obsidian -> not complete portal
2014-05-03 19:38:06 -04:00
return false ;
2013-11-02 09:50:30 -04:00
}
}
// Everything was obsidian, found a border!
2014-05-03 19:38:06 -04:00
return true ;
2013-11-02 09:50:30 -04:00
}
2015-06-30 10:50:15 -04:00
/** Finds entire frame in any direction with the coordinates of a base block and fills hole with nether portal (START HERE) */
2014-02-01 08:06:32 -05:00
void FindAndSetPortalFrame ( int X , int Y , int Z , cChunkInterface & a_ChunkInterface , cWorldInterface & a_WorldInterface )
2013-11-01 20:44:09 -04:00
{
2014-07-17 16:15:34 -04:00
int MaxY = FindObsidianCeiling ( X , Y , Z , a_ChunkInterface ) ; // Get topmost obsidian block as reference for all other checks
2015-05-09 03:25:09 -04:00
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
2013-11-01 20:44:09 -04:00
2014-07-17 16:15:34 -04:00
if ( MaxY = = 0 ) // Oh noes! Not a portal coordinate :(
2013-11-01 20:44:09 -04:00
{
return ;
}
2014-01-31 18:17:41 -05:00
if ( ! FindPortalSliceX ( X1 , X2 , Y , Z , MaxY , a_ChunkInterface ) )
2013-11-01 20:44:09 -04:00
{
2014-01-31 18:17:41 -05:00
if ( ! FindPortalSliceZ ( X , Y , Z1 , Z2 , MaxY , a_ChunkInterface ) )
2013-11-01 20:44:09 -04:00
{
2014-07-17 16:15:34 -04:00
return ; // No eligible portal construct, abort abort abort!!
2013-11-01 20:44:09 -04:00
}
}
2015-06-13 08:57:51 -04:00
int PortalHeight = MaxY - Y - 1 ;
int PortalWidth = XZP - XZM + 1 ;
if ( ( PortalHeight < a_WorldInterface . GetMinNetherPortalHeight ( ) ) | | ( PortalHeight > a_WorldInterface . GetMaxNetherPortalHeight ( ) ) )
{
// The portal isn't high enough, or is too high
return ;
}
if ( ( PortalWidth < a_WorldInterface . GetMinNetherPortalWidth ( ) ) | | ( PortalWidth > a_WorldInterface . GetMaxNetherPortalWidth ( ) ) )
{
// The portal isn't wide enough, or is too wide
return ;
}
2014-07-17 16:15:34 -04:00
for ( int Height = Y + 1 ; Height < = MaxY - 1 ; Height + + ) // Loop through boundary to set portal blocks
2013-11-01 20:44:09 -04:00
{
for ( int Width = XZM ; Width < = XZP ; Width + + )
{
if ( Dir = = 1 )
{
2014-09-12 13:07:20 -04:00
a_ChunkInterface . SetBlock ( Width , Height , Z , E_BLOCK_NETHER_PORTAL , Dir ) ;
2013-11-01 20:44:09 -04:00
}
else
{
2014-09-12 13:07:20 -04:00
a_ChunkInterface . SetBlock ( X , Height , Width , E_BLOCK_NETHER_PORTAL , Dir ) ;
2013-11-01 20:44:09 -04:00
}
}
}
return ;
}
2015-05-09 03:25:09 -04:00
/** Evaluates if coordinates are a portal going XP / XM; returns true if so, and writes boundaries to variable
2014-08-19 16:14:37 -04:00
Takes coordinates of base block and Y coord of target obsidian ceiling */
2014-02-01 08:06:32 -05:00
bool FindPortalSliceX ( int X1 , int X2 , int Y , int Z , int MaxY , cChunkInterface & a_ChunkInterface )
2013-11-01 20:44:09 -04:00
{
2014-07-17 16:15:34 -04:00
Dir = 1 ; // Set assumed direction (will change if portal turns out to be facing the other direction)
2013-11-01 20:44:09 -04:00
bool FoundFrameXP = false , FoundFrameXM = false ;
2014-07-17 16:15:34 -04:00
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
2013-11-01 20:44:09 -04:00
{
2014-01-31 18:17:41 -05:00
int Value = FindObsidianCeiling ( X1 , Y , Z , a_ChunkInterface , MaxY ) ;
2014-07-17 16:15:34 -04:00
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
2013-11-01 20:44:09 -04:00
{
2014-07-17 16:15:34 -04:00
FoundFrameXP = true ; // Found a frame border in this direction, proceed in other direction (don't go further)
2013-11-01 20:44:09 -04:00
break ;
}
2014-07-17 16:15:34 -04:00
else if ( ( Value ! = MaxY ) & & ( ValueTwo ! = MaxY ) ) // Make sure that there is a valid portal 'slice'
2013-11-01 20:44:09 -04:00
{
2014-07-17 16:15:34 -04:00
return false ; // Not valid slice, no portal can be formed
2013-11-01 20:44:09 -04:00
}
2014-08-19 16:14:37 -04:00
}
XZP = X1 - 1 ; // Set boundary of frame interior
2014-07-17 16:15:34 -04:00
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)
2013-11-01 20:44:09 -04:00
{
2014-01-31 18:17:41 -05:00
int Value = FindObsidianCeiling ( X2 , Y , Z , a_ChunkInterface , MaxY ) ;
int ValueTwo = FindObsidianCeiling ( X2 , Y + 1 , Z , a_ChunkInterface , MaxY ) ;
2013-11-02 08:29:26 -04:00
if ( ( Value = = - 1 ) | | ( ValueTwo = = - 1 ) )
2013-11-01 20:44:09 -04:00
{
FoundFrameXM = true ;
break ;
}
else if ( ( Value ! = MaxY ) & & ( ValueTwo ! = MaxY ) )
{
return false ;
}
2014-08-19 16:14:37 -04:00
}
XZM = X2 + 1 ; // Set boundary, see previous
2013-11-01 20:44:09 -04:00
return ( FoundFrameXP & & FoundFrameXM ) ;
}
2015-06-30 10:50:15 -04:00
/** Evaluates if coords are a portal going ZP / ZM; returns true if so, and writes boundaries to variable */
2014-02-01 08:06:32 -05:00
bool FindPortalSliceZ ( int X , int Y , int Z1 , int Z2 , int MaxY , cChunkInterface & a_ChunkInterface )
2013-11-01 20:44:09 -04:00
{
Dir = 2 ;
bool FoundFrameZP = false , FoundFrameZM = false ;
2014-02-01 08:06:32 -05:00
for ( ; ( ( a_ChunkInterface . GetBlock ( X , Y , Z1 ) = = E_BLOCK_OBSIDIAN ) | | ( a_ChunkInterface . GetBlock ( X , Y + 1 , Z1 ) = = E_BLOCK_OBSIDIAN ) ) ; Z1 + + )
2013-11-01 20:44:09 -04:00
{
2014-01-31 18:17:41 -05:00
int Value = FindObsidianCeiling ( X , Y , Z1 , a_ChunkInterface , MaxY ) ;
int ValueTwo = FindObsidianCeiling ( X , Y + 1 , Z1 , a_ChunkInterface , MaxY ) ;
2013-11-02 08:29:26 -04:00
if ( ( Value = = - 1 ) | | ( ValueTwo = = - 1 ) )
2013-11-01 20:44:09 -04:00
{
FoundFrameZP = true ;
2014-05-03 19:38:06 -04:00
break ;
2013-11-01 20:44:09 -04:00
}
else if ( ( Value ! = MaxY ) & & ( ValueTwo ! = MaxY ) )
{
return false ;
}
2014-08-19 16:14:37 -04:00
}
XZP = Z1 - 1 ;
2014-02-01 08:06:32 -05:00
for ( ; ( ( a_ChunkInterface . GetBlock ( X , Y , Z2 ) = = E_BLOCK_OBSIDIAN ) | | ( a_ChunkInterface . GetBlock ( X , Y + 1 , Z2 ) = = E_BLOCK_OBSIDIAN ) ) ; Z2 - - )
2013-11-01 20:44:09 -04:00
{
2014-01-31 18:17:41 -05:00
int Value = FindObsidianCeiling ( X , Y , Z2 , a_ChunkInterface , MaxY ) ;
int ValueTwo = FindObsidianCeiling ( X , Y + 1 , Z2 , a_ChunkInterface , MaxY ) ;
2013-11-02 08:29:26 -04:00
if ( ( Value = = - 1 ) | | ( ValueTwo = = - 1 ) )
2013-11-01 20:44:09 -04:00
{
FoundFrameZM = true ;
2014-05-03 19:38:06 -04:00
break ;
2013-11-01 20:44:09 -04:00
}
else if ( ( Value ! = MaxY ) & & ( ValueTwo ! = MaxY ) )
{
return false ;
}
2014-08-19 16:14:37 -04:00
}
XZM = Z2 + 1 ;
2013-11-01 20:44:09 -04:00
return ( FoundFrameZP & & FoundFrameZM ) ;
}
2015-06-14 07:53:09 -04:00
2017-07-07 10:37:53 -04:00
virtual bool DoesIgnoreBuildCollision ( cChunkInterface & a_ChunkInterface , Vector3i a_Pos , cPlayer & a_Player , NIBBLETYPE a_Meta ) override
2015-06-14 07:53:09 -04:00
{
return true ;
}
2015-06-30 10:50:15 -04:00
virtual ColourID GetMapBaseColourID ( NIBBLETYPE a_Meta ) override
{
UNUSED ( a_Meta ) ;
return 15 ;
}
2013-11-01 20:44:09 -04:00
} ;
2013-07-29 07:13:03 -04:00