2013-07-29 12:13:03 +01:00
#pragma once
#include "BlockHandler.h"
class cBlockFireHandler :
public cBlockHandler
{
public :
cBlockFireHandler ( BLOCKTYPE a_BlockType )
: cBlockHandler ( a_BlockType )
{
}
2013-11-02 00:44:09 +00:00
/// Portal boundary and direction variables
int XZP , XZM , Dir ; // For wont of a better name...
virtual void OnPlaced ( cWorld * a_World , 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 -- ; // Because we want the block below the fire
FindAndSetPortalFrame ( a_BlockX , a_BlockY , a_BlockZ , a_World ); // Brought to you by Aperture Science
}
2013-07-29 12:13:03 +01:00
virtual void OnDigging ( cWorld * a_World , cPlayer * a_Player , int a_BlockX , int a_BlockY , int a_BlockZ ) override
{
a_World -> DigBlock ( a_BlockX , a_BlockY , a_BlockZ );
}
virtual void ConvertToPickups ( cItems & a_Pickups , NIBBLETYPE a_BlockMeta ) override
{
// No pickups from this block
}
virtual bool IsClickedThrough ( void ) override
{
return true ;
}
2013-11-02 00:44:09 +00:00
2013-07-29 12:13:03 +01:00
virtual const char * GetStepSound ( void ) override
{
return "step.wood" ;
}
2013-11-02 00:44:09 +00: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
2013-11-02 12:29:26 +00:00
int FindObsidianCeiling ( int X , int Y , int Z , cWorld * a_World , int MaxY = 0 )
2013-11-02 00:44:09 +00:00
{
if ( a_World -> GetBlock ( X , Y , Z ) != E_BLOCK_OBSIDIAN )
{
return 0 ;
}
int newY = Y + 1 ;
for ( newY ; newY < cChunkDef :: Height ; newY ++ )
{
BLOCKTYPE Block = a_World -> 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 ))
{
2013-11-02 13:50:30 +00:00
return EvaluatePortalBorder ( X , newY , Z , MaxY , a_World );
2013-11-02 00:44:09 +00:00
}
else
{
// Return ceiling Y, whoever called this function will decide if it's part of a portal or not
return newY ;
}
}
else { return 0 ; }
}
return 0 ;
}
2013-11-02 13:50:30 +00:00
/// Evaluates if coords have a valid border on top, based on MaxY
int EvaluatePortalBorder ( int X , int FoundObsidianY , int Z , int MaxY , cWorld * a_World )
{
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_World -> GetBlock ( X , checkBorder , Z ) != E_BLOCK_OBSIDIAN )
{
// Base obsidian, base + 1 obsidian, base + x NOT obsidian -> not complete portal
return 0 ;
}
}
// Everything was obsidian, found a border!
return - 1 ; // Return -1 for a frame border
}
2013-11-02 00:44:09 +00:00
/// 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 , cWorld * a_World )
{
2013-11-02 12:29:26 +00:00
int MaxY = FindObsidianCeiling ( X , Y , Z , a_World ); // Get topmost obsidian block as reference for all other checks
2013-11-02 00:44:09 +00: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
if ( MaxY == 0 ) // Oh noes! Not a portal coordinate :(
{
return ;
}
if ( ! FindPortalSliceX ( X1 , X2 , Y , Z , MaxY , a_World ))
{
if ( ! FindPortalSliceZ ( X , Y , Z1 , Z2 , MaxY , a_World ))
{
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_World -> SetBlock ( Width , Height , Z , E_BLOCK_NETHER_PORTAL , Dir );
}
else
{
a_World -> SetBlock ( 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 , cWorld * a_World )
{
Dir = 1 ; // Set assumed direction (will change if portal turns out to be facing the other direction)
bool FoundFrameXP = false , FoundFrameXM = false ;
for ( X1 ; (( a_World -> GetBlock ( X1 , Y , Z ) == E_BLOCK_OBSIDIAN ) || ( a_World -> GetBlock ( X1 , Y + 1 , Z ) == E_BLOCK_OBSIDIAN )); X1 ++ ) // Check XP for obsidian blocks, exempting corners
{
2013-11-02 12:29:26 +00:00
int Value = FindObsidianCeiling ( X1 , Y , Z , a_World , MaxY );
int ValueTwo = FindObsidianCeiling ( X1 , Y + 1 , Z , a_World , MaxY ); // For corners without obsidian
if (( Value == - 1 ) || ( ValueTwo == - 1 )) // FindObsidianCeiling returns -1 upon frame-find
2013-11-02 00:44:09 +00:00
{
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
}
2013-11-02 19:04:38 +00:00
} XZP = X1 - 1 ; // Set boundary of frame interior, note that for some reason, the loop of X and the loop of Z go to different numbers, hence -1 here and -2 there
2013-11-02 00:44:09 +00:00
for ( X2 ; (( a_World -> GetBlock ( X2 , Y , Z ) == E_BLOCK_OBSIDIAN ) || ( a_World -> GetBlock ( X2 , Y + 1 , Z ) == E_BLOCK_OBSIDIAN )); X2 -- ) // Go the other direction (XM)
{
2013-11-02 12:29:26 +00:00
int Value = FindObsidianCeiling ( X2 , Y , Z , a_World , MaxY );
int ValueTwo = FindObsidianCeiling ( X2 , Y + 1 , Z , a_World , MaxY );
if (( Value == - 1 ) || ( ValueTwo == - 1 ))
2013-11-02 00:44:09 +00:00
{
FoundFrameXM = true ;
break ;
}
else if (( Value != MaxY ) && ( ValueTwo != MaxY ))
{
return false ;
}
2013-11-02 19:04:38 +00:00
} XZM = X2 + 1 ; // Set boundary, see previous
2013-11-02 00:44:09 +00:00
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 , cWorld * a_World )
{
Dir = 2 ;
bool FoundFrameZP = false , FoundFrameZM = false ;
for ( Z1 ; (( a_World -> GetBlock ( X , Y , Z1 ) == E_BLOCK_OBSIDIAN ) || ( a_World -> GetBlock ( X , Y + 1 , Z1 ) == E_BLOCK_OBSIDIAN )); Z1 ++ )
{
2013-11-02 12:29:26 +00:00
int Value = FindObsidianCeiling ( X , Y , Z1 , a_World , MaxY );
int ValueTwo = FindObsidianCeiling ( X , Y + 1 , Z1 , a_World , MaxY );
if (( Value == - 1 ) || ( ValueTwo == - 1 ))
2013-11-02 00:44:09 +00:00
{
FoundFrameZP = true ;
continue ;
}
else if (( Value != MaxY ) && ( ValueTwo != MaxY ))
{
return false ;
}
} XZP = Z1 - 2 ;
for ( Z2 ; (( a_World -> GetBlock ( X , Y , Z2 ) == E_BLOCK_OBSIDIAN ) || ( a_World -> GetBlock ( X , Y + 1 , Z2 ) == E_BLOCK_OBSIDIAN )); Z2 -- )
{
2013-11-02 12:29:26 +00:00
int Value = FindObsidianCeiling ( X , Y , Z2 , a_World , MaxY );
int ValueTwo = FindObsidianCeiling ( X , Y + 1 , Z2 , a_World , MaxY );
if (( Value == - 1 ) || ( ValueTwo == - 1 ))
2013-11-02 00:44:09 +00:00
{
FoundFrameZM = true ;
continue ;
}
else if (( Value != MaxY ) && ( ValueTwo != MaxY ))
{
return false ;
}
} XZM = Z2 + 2 ;
return ( FoundFrameZP && FoundFrameZM );
}
};
2013-07-29 12:13:03 +01:00