2012-10-06 16:04:58 -04:00
2012-06-14 09:06:06 -04:00
# include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2012-09-23 18:09:57 -04:00
# include "RedstoneSimulator.h"
# include "Piston.h"
# include "World.h"
2012-06-14 09:06:06 -04:00
# include "BlockID.h"
2012-09-23 18:09:57 -04:00
# include "Torch.h"
2012-06-14 09:06:06 -04:00
2012-10-06 16:04:58 -04:00
2012-06-14 09:06:06 -04:00
cRedstoneSimulator : : cRedstoneSimulator ( cWorld * a_World )
: super ( a_World )
{
}
cRedstoneSimulator : : ~ cRedstoneSimulator ( )
{
}
void cRedstoneSimulator : : WakeUp ( int a_X , int a_Y , int a_Z )
{
cCSLock Lock ( m_CS ) ;
m_Blocks . push_back ( Vector3i ( a_X , a_Y , a_Z ) ) ;
}
void cRedstoneSimulator : : Simulate ( float a_Dt )
{
// Toggle torches on/off
while ( ! m_RefreshTorchesAround . empty ( ) )
{
Vector3i pos = m_RefreshTorchesAround . front ( ) ;
m_RefreshTorchesAround . pop_front ( ) ;
RefreshTorchesAround ( pos ) ;
}
// Set repeaters to correct values, and decrement ticks
for ( RepeaterList : : iterator itr = m_SetRepeaters . begin ( ) ; itr ! = m_SetRepeaters . end ( ) ; )
{
( * itr ) . Ticks - - ;
if ( ( * itr ) . Ticks < = 0 )
{
char Block = m_World - > GetBlock ( ( * itr ) . Position ) ;
if ( ( * itr ) . bPowerOn = = true & & Block = = E_BLOCK_REDSTONE_REPEATER_OFF )
{
m_World - > FastSetBlock ( ( * itr ) . Position . x , ( * itr ) . Position . y , ( * itr ) . Position . z , E_BLOCK_REDSTONE_REPEATER_ON , m_World - > GetBlockMeta ( ( * itr ) . Position ) ) ;
m_Blocks . push_back ( ( * itr ) . Position ) ;
}
else if ( ( * itr ) . bPowerOn = = false & & Block = = E_BLOCK_REDSTONE_REPEATER_ON )
{
m_World - > FastSetBlock ( ( * itr ) . Position . x , ( * itr ) . Position . y , ( * itr ) . Position . z , E_BLOCK_REDSTONE_REPEATER_OFF , m_World - > GetBlockMeta ( ( * itr ) . Position ) ) ;
m_Blocks . push_back ( ( * itr ) . Position ) ;
}
if ( ( * itr ) . bPowerOffNextTime )
{
( * itr ) . bPowerOn = false ;
( * itr ) . bPowerOffNextTime = false ;
( * itr ) . Ticks = 10 ; // TODO: Look up actual ticks from block metadata
+ + itr ;
}
else
{
itr = m_SetRepeaters . erase ( itr ) ;
}
}
else
{
+ + itr ;
}
}
// Handle changed blocks
{
cCSLock Lock ( m_CS ) ;
std : : swap ( m_Blocks , m_BlocksBuffer ) ;
}
for ( BlockList : : iterator itr = m_BlocksBuffer . begin ( ) ; itr ! = m_BlocksBuffer . end ( ) ; + + itr )
{
HandleChange ( * itr ) ;
}
m_BlocksBuffer . clear ( ) ;
}
void cRedstoneSimulator : : RefreshTorchesAround ( const Vector3i & a_BlockPos )
{
static Vector3i Surroundings [ ] = {
Vector3i ( - 1 , 0 , 0 ) ,
Vector3i ( 1 , 0 , 0 ) ,
Vector3i ( 0 , 0 , - 1 ) ,
Vector3i ( 0 , 0 , 1 ) ,
Vector3i ( 0 , 1 , 0 ) , // Also toggle torch on top
} ;
char TargetBlockID = E_BLOCK_REDSTONE_TORCH_ON ;
char TargetRepeaterID = E_BLOCK_REDSTONE_REPEATER_OFF ;
if ( IsPowered ( a_BlockPos , true ) )
{
TargetBlockID = E_BLOCK_REDSTONE_TORCH_OFF ;
TargetRepeaterID = E_BLOCK_REDSTONE_REPEATER_ON ;
//if( m_World->GetBlock( a_BlockPos ) == E_BLOCK_DIRT )
//{
// m_World->FastSetBlock( a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_STONE, 0 );
//}
}
else
{
//if( m_World->GetBlock( a_BlockPos ) == E_BLOCK_STONE )
//{
// m_World->FastSetBlock( a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_DIRT, 0 );
//}
}
for ( unsigned int i = 0 ; i < ARRAYCOUNT ( Surroundings ) ; + + i )
{
Vector3i TorchPos = a_BlockPos + Surroundings [ i ] ;
const char Block = m_World - > GetBlock ( TorchPos ) ;
switch ( Block )
{
case E_BLOCK_REDSTONE_TORCH_ON :
case E_BLOCK_REDSTONE_TORCH_OFF :
if ( Block ! = TargetBlockID )
{
char TorchMeta = m_World - > GetBlockMeta ( TorchPos ) ;
if ( cTorch : : IsAttachedTo ( TorchPos , TorchMeta , a_BlockPos ) )
{
m_World - > FastSetBlock ( TorchPos . x , TorchPos . y , TorchPos . z , TargetBlockID , m_World - > GetBlockMeta ( TorchPos ) ) ;
m_Blocks . push_back ( TorchPos ) ;
}
}
break ;
case E_BLOCK_REDSTONE_REPEATER_ON :
case E_BLOCK_REDSTONE_REPEATER_OFF :
2012-10-06 16:04:58 -04:00
if ( ( Block ! = TargetRepeaterID ) & & IsRepeaterPointingAway ( TorchPos , m_World - > GetBlockMeta ( TorchPos ) , a_BlockPos ) )
2012-06-14 09:06:06 -04:00
{
SetRepeater ( TorchPos , 10 , TargetRepeaterID = = E_BLOCK_REDSTONE_REPEATER_ON ) ;
}
break ;
default :
break ;
} ;
}
}
void cRedstoneSimulator : : HandleChange ( const Vector3i & a_BlockPos )
{
std : : deque < Vector3i > SpreadStack ;
Vector3i Surroundings [ ] = {
Vector3i ( 1 , 0 , 0 ) ,
Vector3i ( 1 , 1 , 0 ) ,
Vector3i ( 1 , - 1 , 0 ) ,
Vector3i ( - 1 , 0 , 0 ) ,
Vector3i ( - 1 , 1 , 0 ) ,
Vector3i ( - 1 , - 1 , 0 ) ,
Vector3i ( 0 , 0 , 1 ) ,
Vector3i ( 0 , 1 , 1 ) ,
Vector3i ( 0 , - 1 , 1 ) ,
Vector3i ( 0 , 0 , - 1 ) ,
Vector3i ( 0 , 1 , - 1 ) ,
Vector3i ( 0 , - 1 , - 1 ) ,
Vector3i ( 0 , - 1 , 0 ) ,
} ;
char Block = m_World - > GetBlock ( a_BlockPos ) ;
// First check whether torch should be on or off
if ( Block = = E_BLOCK_REDSTONE_TORCH_ON | | Block = = E_BLOCK_REDSTONE_TORCH_OFF )
{
static Vector3i Surroundings [ ] = {
Vector3i ( - 1 , 0 , 0 ) ,
Vector3i ( 1 , 0 , 0 ) ,
Vector3i ( 0 , 0 , - 1 ) ,
Vector3i ( 0 , 0 , 1 ) ,
Vector3i ( 0 , - 1 , 0 ) ,
} ;
for ( unsigned int i = 0 ; i < ARRAYCOUNT ( Surroundings ) ; + + i )
{
Vector3i pos = a_BlockPos + Surroundings [ i ] ;
char OtherBlock = m_World - > GetBlock ( pos ) ;
if ( ( OtherBlock ! = E_BLOCK_AIR ) & & ( OtherBlock ! = E_BLOCK_REDSTONE_TORCH_ON ) & & ( OtherBlock ! = E_BLOCK_REDSTONE_TORCH_OFF ) )
{
RefreshTorchesAround ( pos ) ;
}
}
Block = m_World - > GetBlock ( a_BlockPos ) ; // Make sure we got the updated block
}
else if ( Block = = E_BLOCK_REDSTONE_REPEATER_ON | | Block = = E_BLOCK_REDSTONE_REPEATER_OFF ) // Check if repeater is powered by a 'powered block' (not wires/torch)
{
2012-10-06 16:04:58 -04:00
Vector3i Direction = GetRepeaterDirection ( m_World - > GetBlockMeta ( a_BlockPos ) ) ;
2012-06-14 09:06:06 -04:00
Vector3i pos = a_BlockPos - Direction ; // NOTE: It's minus Direction
char OtherBlock = m_World - > GetBlock ( pos ) ;
if ( ( OtherBlock ! = E_BLOCK_AIR ) & & ( OtherBlock ! = E_BLOCK_REDSTONE_TORCH_ON ) & & ( OtherBlock ! = E_BLOCK_REDSTONE_TORCH_OFF ) & & ( OtherBlock ! = E_BLOCK_REDSTONE_WIRE ) )
{
RefreshTorchesAround ( pos ) ;
}
else
{
SetRepeater ( a_BlockPos , 10 , IsPowered ( a_BlockPos , false ) ) ;
}
Block = m_World - > GetBlock ( a_BlockPos ) ;
}
BlockList Sources ;
// If torch is still on, use it as a source
if ( Block = = E_BLOCK_REDSTONE_TORCH_ON )
{
Sources . push_back ( a_BlockPos ) ;
}
else if ( Block = = E_BLOCK_REDSTONE_REPEATER_ON )
{
static Vector3i Surroundings [ ] = { // It only spreads right in front, and one block up
Vector3i ( 0 , 0 , 0 ) ,
Vector3i ( 0 , 1 , 0 ) ,
} ;
2012-10-06 16:04:58 -04:00
Vector3i Direction = GetRepeaterDirection ( m_World - > GetBlockMeta ( a_BlockPos ) ) ;
2012-06-14 09:06:06 -04:00
for ( unsigned int i = 0 ; i < ARRAYCOUNT ( Surroundings ) ; + + i )
{
Vector3i pos = a_BlockPos + Direction + Surroundings [ i ] ;
if ( PowerBlock ( pos , a_BlockPos , 0xf ) )
{
SpreadStack . push_back ( pos ) ;
}
}
}
// Power all blocks legally connected to the sources
if ( Block ! = E_BLOCK_REDSTONE_REPEATER_ON )
{
BlockList NewSources = RemoveCurrent ( a_BlockPos ) ;
Sources . insert ( Sources . end ( ) , NewSources . begin ( ) , NewSources . end ( ) ) ;
while ( ! Sources . empty ( ) )
{
Vector3i SourcePos = Sources . back ( ) ;
Sources . pop_back ( ) ;
char Block = m_World - > GetBlock ( SourcePos ) ;
switch ( Block )
{
case E_BLOCK_REDSTONE_TORCH_OFF :
case E_BLOCK_REDSTONE_TORCH_ON :
{
static Vector3i Surroundings [ ] = {
Vector3i ( - 1 , 0 , 0 ) ,
Vector3i ( 1 , 0 , 0 ) ,
Vector3i ( 0 , 0 , - 1 ) ,
Vector3i ( 0 , 0 , 1 ) ,
} ;
for ( unsigned int i = 0 ; i < ARRAYCOUNT ( Surroundings ) ; + + i )
{
Vector3i OtherPos = SourcePos + Surroundings [ i ] ;
if ( PowerBlock ( OtherPos , a_BlockPos , 0xf ) )
{
SpreadStack . push_back ( OtherPos ) ; // Changed, so add to stack
}
}
}
break ;
case E_BLOCK_REDSTONE_REPEATER_OFF :
case E_BLOCK_REDSTONE_REPEATER_ON :
{
static Vector3i Surroundings [ ] = {
Vector3i ( 0 , 0 , 0 ) ,
Vector3i ( 0 , 1 , 0 ) ,
} ;
2012-10-06 16:04:58 -04:00
Vector3i Direction = GetRepeaterDirection ( m_World - > GetBlockMeta ( SourcePos ) ) ;
2012-06-14 09:06:06 -04:00
for ( unsigned int i = 0 ; i < ARRAYCOUNT ( Surroundings ) ; + + i )
{
Vector3i pos = SourcePos + Direction + Surroundings [ i ] ;
if ( PowerBlock ( pos , a_BlockPos , 0xf ) )
{
SpreadStack . push_back ( pos ) ;
}
}
}
break ;
} ;
}
}
// Do a floodfill
while ( ! SpreadStack . empty ( ) )
{
Vector3i pos = SpreadStack . back ( ) ;
SpreadStack . pop_back ( ) ;
char Meta = m_World - > GetBlockMeta ( pos ) ;
for ( unsigned int i = 0 ; i < ARRAYCOUNT ( Surroundings ) ; + + i )
{
Vector3i OtherPos = pos + Surroundings [ i ] ;
if ( PowerBlock ( OtherPos , pos , Meta - 1 ) )
{
SpreadStack . push_back ( OtherPos ) ; // Changed, so add to stack
}
}
}
// Only after a redstone area has been completely simulated the redstone entities can react
while ( ! m_RefreshPistons . empty ( ) )
{
Vector3i pos = m_RefreshPistons . back ( ) ;
m_RefreshPistons . pop_back ( ) ;
char Block = m_World - > GetBlock ( pos ) ;
switch ( Block )
{
case E_BLOCK_PISTON :
case E_BLOCK_STICKY_PISTON :
if ( IsPowered ( pos ) )
{
cPiston Piston ( m_World ) ;
Piston . ExtendPiston ( pos . x , pos . y , pos . z ) ;
}
else
{
cPiston Piston ( m_World ) ;
Piston . RetractPiston ( pos . x , pos . y , pos . z ) ;
}
break ;
default :
break ;
} ;
}
}
bool cRedstoneSimulator : : PowerBlock ( const Vector3i & a_BlockPos , const Vector3i & a_FromBlock , char a_Power )
{
char Block = m_World - > GetBlock ( a_BlockPos ) ;
switch ( Block )
{
case E_BLOCK_REDSTONE_WIRE :
{
if ( m_World - > GetBlockMeta ( a_BlockPos ) < a_Power )
{
m_World - > SetBlockMeta ( a_BlockPos , a_Power ) ;
return true ;
}
}
break ;
case E_BLOCK_PISTON :
case E_BLOCK_STICKY_PISTON :
{
m_RefreshPistons . push_back ( a_BlockPos ) ;
}
break ;
case E_BLOCK_REDSTONE_REPEATER_OFF :
case E_BLOCK_REDSTONE_REPEATER_ON :
{
2012-10-06 16:04:58 -04:00
if ( IsRepeaterPointingAway ( a_BlockPos , m_World - > GetBlockMeta ( a_BlockPos ) , a_FromBlock ) )
2012-06-14 09:06:06 -04:00
{
SetRepeater ( a_BlockPos , 10 , true ) ;
}
}
break ;
default :
{
if ( Block ! = E_BLOCK_AIR & & Block ! = E_BLOCK_REDSTONE_TORCH_ON & & Block ! = E_BLOCK_REDSTONE_TORCH_OFF )
{
if ( IsPowered ( a_BlockPos , true ) )
{
m_RefreshTorchesAround . push_back ( a_BlockPos ) ;
}
}
}
break ;
} ;
return false ;
}
2012-10-06 16:04:58 -04:00
int cRedstoneSimulator : : UnPowerBlock ( const Vector3i & a_BlockPos , const Vector3i & a_FromBlock )
2012-06-14 09:06:06 -04:00
{
2012-10-06 16:04:58 -04:00
BLOCKTYPE BlockType = m_World - > GetBlock ( a_BlockPos ) ;
switch ( BlockType )
2012-06-14 09:06:06 -04:00
{
2012-10-06 16:04:58 -04:00
case E_BLOCK_REDSTONE_WIRE :
2012-06-14 09:06:06 -04:00
{
if ( m_World - > GetBlockMeta ( a_BlockPos ) > 0 )
{
m_World - > SetBlockMeta ( a_BlockPos , 0 ) ;
return 1 ;
}
2012-10-06 16:04:58 -04:00
break ;
2012-06-14 09:06:06 -04:00
}
2012-10-06 16:04:58 -04:00
case E_BLOCK_PISTON :
case E_BLOCK_STICKY_PISTON :
2012-06-14 09:06:06 -04:00
{
m_RefreshPistons . push_back ( a_BlockPos ) ;
2012-10-06 16:04:58 -04:00
break ;
2012-06-14 09:06:06 -04:00
}
2012-10-06 16:04:58 -04:00
case E_BLOCK_REDSTONE_TORCH_ON :
2012-06-14 09:06:06 -04:00
{
return 2 ;
2012-10-06 16:04:58 -04:00
break ;
2012-06-14 09:06:06 -04:00
}
2012-10-06 16:04:58 -04:00
case E_BLOCK_REDSTONE_REPEATER_ON :
2012-06-14 09:06:06 -04:00
{
2012-10-06 16:04:58 -04:00
if (
IsRepeaterPointingTo ( a_BlockPos , m_World - > GetBlockMeta ( a_BlockPos ) , a_FromBlock ) | | // Repeater is next to wire
IsRepeaterPointingTo ( a_BlockPos , m_World - > GetBlockMeta ( a_BlockPos ) , a_FromBlock - Vector3i ( 0 , 1 , 0 ) ) // Repeater is below wire
)
2012-06-14 09:06:06 -04:00
{
return 2 ;
}
2012-10-06 16:04:58 -04:00
else if ( IsRepeaterPointingAway ( a_BlockPos , m_World - > GetBlockMeta ( a_BlockPos ) , a_FromBlock ) )
2012-06-14 09:06:06 -04:00
{
SetRepeater ( a_BlockPos , 10 , false ) ;
}
2012-10-06 16:04:58 -04:00
// fall-through:
2012-06-14 09:06:06 -04:00
}
2012-10-06 16:04:58 -04:00
case E_BLOCK_REDSTONE_REPEATER_OFF :
2012-06-14 09:06:06 -04:00
{
2012-10-06 16:04:58 -04:00
if ( IsRepeaterPointingAway ( a_BlockPos , m_World - > GetBlockMeta ( a_BlockPos ) , a_FromBlock ) )
{
SetRepeater ( a_BlockPos , 10 , false ) ;
}
break ;
2012-06-14 09:06:06 -04:00
}
2012-10-06 16:04:58 -04:00
default :
2012-06-14 09:06:06 -04:00
{
2012-10-06 16:04:58 -04:00
if ( ( BlockType ! = E_BLOCK_AIR ) & & ( BlockType ! = E_BLOCK_REDSTONE_TORCH_ON ) & & ( BlockType ! = E_BLOCK_REDSTONE_TORCH_OFF ) )
2012-06-14 09:06:06 -04:00
{
2012-10-06 16:04:58 -04:00
if ( ! IsPowered ( a_BlockPos , true ) )
{
m_RefreshTorchesAround . push_back ( a_BlockPos ) ;
}
2012-06-14 09:06:06 -04:00
}
2012-10-06 16:04:58 -04:00
break ;
2012-06-14 09:06:06 -04:00
}
2012-10-06 16:04:58 -04:00
} // switch (BlockType)
2012-06-14 09:06:06 -04:00
return 0 ;
}
// Removes current from all powered redstone wires until it reaches an energy source.
// Also returns all energy sources it encountered
cRedstoneSimulator : : BlockList cRedstoneSimulator : : RemoveCurrent ( const Vector3i & a_BlockPos )
{
std : : deque < Vector3i > SpreadStack ;
std : : deque < Vector3i > FoundSources ;
Vector3i Surroundings [ ] = {
Vector3i ( 1 , 0 , 0 ) ,
Vector3i ( 1 , 1 , 0 ) ,
Vector3i ( 1 , - 1 , 0 ) ,
Vector3i ( - 1 , 0 , 0 ) ,
Vector3i ( - 1 , 1 , 0 ) ,
Vector3i ( - 1 , - 1 , 0 ) ,
Vector3i ( 0 , 0 , 1 ) ,
Vector3i ( 0 , 1 , 1 ) ,
Vector3i ( 0 , - 1 , 1 ) ,
Vector3i ( 0 , 0 , - 1 ) ,
Vector3i ( 0 , 1 , - 1 ) ,
Vector3i ( 0 , - 1 , - 1 ) ,
Vector3i ( 0 , - 1 , 0 ) ,
} ;
char Block = m_World - > GetBlock ( a_BlockPos ) ;
if ( Block = = E_BLOCK_REDSTONE_REPEATER_ON | | Block = = E_BLOCK_REDSTONE_REPEATER_OFF )
{
static Vector3i Surroundings [ ] = { // Repeaters only spread right in front and 1 block up
Vector3i ( 0 , 0 , 0 ) ,
Vector3i ( 0 , 1 , 0 ) ,
} ;
2012-10-06 16:04:58 -04:00
Vector3i Direction = GetRepeaterDirection ( m_World - > GetBlockMeta ( a_BlockPos ) ) ;
2012-06-14 09:06:06 -04:00
for ( unsigned int i = 0 ; i < ARRAYCOUNT ( Surroundings ) ; + + i )
{
Vector3i pos = a_BlockPos + Direction + Surroundings [ i ] ;
int RetVal = UnPowerBlock ( pos , a_BlockPos ) ;
if ( RetVal = = 1 )
{
SpreadStack . push_back ( pos ) ; // Changed, so add to stack
}
else if ( RetVal = = 2 )
{
FoundSources . push_back ( pos ) ;
}
}
}
else if ( Block = = E_BLOCK_REDSTONE_TORCH_OFF | | Block = = E_BLOCK_REDSTONE_TORCH_ON )
{
static Vector3i Surroundings [ ] = { // Torches only spread on the same level
Vector3i ( - 1 , 0 , 0 ) ,
Vector3i ( 1 , 0 , 0 ) ,
Vector3i ( 0 , 0 , - 1 ) ,
Vector3i ( 0 , 0 , 1 ) ,
} ;
for ( unsigned int i = 0 ; i < ARRAYCOUNT ( Surroundings ) ; + + i )
{
Vector3i pos = Vector3i ( a_BlockPos ) + Surroundings [ i ] ;
int RetVal = UnPowerBlock ( pos , a_BlockPos ) ;
if ( RetVal = = 1 )
{
SpreadStack . push_back ( pos ) ; // Changed, so add to stack
}
else if ( RetVal = = 2 )
{
FoundSources . push_back ( pos ) ;
}
}
}
else
{
SpreadStack . push_back ( a_BlockPos ) ;
}
while ( ! SpreadStack . empty ( ) )
{
Vector3i pos = SpreadStack . back ( ) ;
SpreadStack . pop_back ( ) ;
for ( unsigned int i = 0 ; i < ARRAYCOUNT ( Surroundings ) ; + + i )
{
Vector3i OtherPos = pos + Surroundings [ i ] ;
int RetVal = UnPowerBlock ( OtherPos , pos ) ;
if ( RetVal = = 1 )
{
SpreadStack . push_back ( OtherPos ) ; // Changed, so add to stack
}
else if ( RetVal = = 2 )
{
FoundSources . push_back ( OtherPos ) ;
}
}
}
return FoundSources ;
}
bool cRedstoneSimulator : : IsPowering ( const Vector3i & a_PowerPos , const Vector3i & a_BlockPos , eRedstoneDirection a_WireDirection , bool a_bOnlyByWire )
{
2012-10-06 16:04:58 -04:00
BLOCKTYPE PowerBlock = m_World - > GetBlock ( a_PowerPos ) ;
if ( ! a_bOnlyByWire & & ( PowerBlock = = E_BLOCK_REDSTONE_TORCH_ON ) ) return true ;
if ( PowerBlock = = E_BLOCK_REDSTONE_REPEATER_ON ) // A repeater pointing towards block is regarded as wire
2012-06-14 09:06:06 -04:00
{
2012-10-06 16:04:58 -04:00
if ( IsRepeaterPointingTo ( a_PowerPos , m_World - > GetBlockMeta ( a_PowerPos ) , a_BlockPos ) )
2012-06-14 09:06:06 -04:00
{
return true ;
}
}
2012-10-06 16:04:58 -04:00
if ( PowerBlock = = E_BLOCK_REDSTONE_WIRE )
2012-06-14 09:06:06 -04:00
{
2012-10-06 16:04:58 -04:00
if ( m_World - > GetBlockMeta ( a_PowerPos ) > 0 )
2012-06-14 09:06:06 -04:00
{
2012-10-06 16:04:58 -04:00
if ( GetDirection ( a_PowerPos ) = = a_WireDirection )
2012-06-14 09:06:06 -04:00
{
return true ;
}
}
}
return false ;
}
bool cRedstoneSimulator : : IsPowered ( const Vector3i & a_BlockPos , bool a_bOnlyByWire /* = false */ )
{
2012-10-06 16:04:58 -04:00
BLOCKTYPE Block = m_World - > GetBlock ( a_BlockPos ) ;
if ( ( Block = = E_BLOCK_REDSTONE_REPEATER_OFF ) | | ( Block = = E_BLOCK_REDSTONE_REPEATER_ON ) )
2012-06-14 09:06:06 -04:00
{
2012-10-06 16:04:58 -04:00
Vector3i Behind = a_BlockPos - GetRepeaterDirection ( m_World - > GetBlockMeta ( a_BlockPos ) ) ;
BLOCKTYPE BehindBlock = m_World - > GetBlock ( Behind ) ;
if ( BehindBlock = = E_BLOCK_REDSTONE_TORCH_ON )
2012-06-14 09:06:06 -04:00
{
return true ;
}
2012-10-06 16:04:58 -04:00
if ( BehindBlock = = E_BLOCK_REDSTONE_WIRE )
2012-06-14 09:06:06 -04:00
{
if ( m_World - > GetBlockMeta ( Behind ) > 0 )
{
return true ;
}
}
2012-10-06 16:04:58 -04:00
if ( BehindBlock = = E_BLOCK_REDSTONE_REPEATER_ON )
2012-06-14 09:06:06 -04:00
{
2012-10-06 16:04:58 -04:00
if ( IsRepeaterPointingTo ( Behind , m_World - > GetBlockMeta ( Behind ) , a_BlockPos ) )
2012-06-14 09:06:06 -04:00
{
return true ;
}
}
return false ;
}
if ( IsPowering ( Vector3i ( a_BlockPos . x - 1 , a_BlockPos . y , a_BlockPos . z ) , a_BlockPos , REDSTONE_X_POS , a_bOnlyByWire ) )
return true ;
if ( IsPowering ( Vector3i ( a_BlockPos . x + 1 , a_BlockPos . y , a_BlockPos . z ) , a_BlockPos , REDSTONE_X_NEG , a_bOnlyByWire ) )
return true ;
if ( IsPowering ( Vector3i ( a_BlockPos . x , a_BlockPos . y , a_BlockPos . z - 1 ) , a_BlockPos , REDSTONE_Z_POS , a_bOnlyByWire ) )
return true ;
if ( IsPowering ( Vector3i ( a_BlockPos . x , a_BlockPos . y , a_BlockPos . z + 1 ) , a_BlockPos , REDSTONE_Z_NEG , a_bOnlyByWire ) )
return true ;
// Only wires can power the bottom block
char PosY = m_World - > GetBlock ( a_BlockPos . x , a_BlockPos . y + 1 , a_BlockPos . z ) ;
if ( PosY = = E_BLOCK_REDSTONE_WIRE )
{
if ( m_World - > GetBlockMeta ( a_BlockPos . x , a_BlockPos . y + 1 , a_BlockPos . z ) > 0 )
{
return true ;
}
}
return false ;
}
// Believe me, it works!! TODO: Add repeaters and low/high wires
cRedstoneSimulator : : eRedstoneDirection cRedstoneSimulator : : GetDirection ( int a_X , int a_Y , int a_Z )
{
int Dir = REDSTONE_NONE ;
char NegX = m_World - > GetBlock ( a_X - 1 , a_Y , a_Z ) ;
if ( NegX = = E_BLOCK_REDSTONE_WIRE | | NegX = = E_BLOCK_REDSTONE_TORCH_ON )
{
Dir | = ( REDSTONE_X_POS ) ;
}
char PosX = m_World - > GetBlock ( a_X + 1 , a_Y , a_Z ) ;
if ( PosX = = E_BLOCK_REDSTONE_WIRE | | PosX = = E_BLOCK_REDSTONE_TORCH_ON )
{
Dir | = ( REDSTONE_X_NEG ) ;
}
char NegZ = m_World - > GetBlock ( a_X , a_Y , a_Z - 1 ) ;
if ( NegZ = = E_BLOCK_REDSTONE_WIRE | | NegZ = = E_BLOCK_REDSTONE_TORCH_ON )
{
if ( ( Dir & REDSTONE_X_POS ) & & ! ( Dir & REDSTONE_X_NEG ) ) //corner
{
Dir ^ = REDSTONE_X_POS ;
Dir | = REDSTONE_X_NEG ;
}
if ( ( Dir & REDSTONE_X_NEG ) & & ! ( Dir & REDSTONE_X_POS ) ) //corner
{
Dir ^ = REDSTONE_X_NEG ;
Dir | = REDSTONE_X_POS ;
}
Dir | = REDSTONE_Z_POS ;
}
char PosZ = m_World - > GetBlock ( a_X , a_Y , a_Z + 1 ) ;
if ( PosZ = = E_BLOCK_REDSTONE_WIRE | | PosZ = = E_BLOCK_REDSTONE_TORCH_ON )
{
if ( ( Dir & REDSTONE_X_POS ) & & ! ( Dir & REDSTONE_X_NEG ) ) //corner
{
Dir ^ = REDSTONE_X_POS ;
Dir | = REDSTONE_X_NEG ;
}
if ( ( Dir & REDSTONE_X_NEG ) & & ! ( Dir & REDSTONE_X_POS ) ) //corner
{
Dir ^ = REDSTONE_X_NEG ;
Dir | = REDSTONE_X_POS ;
}
Dir | = REDSTONE_Z_NEG ;
}
return ( eRedstoneDirection ) Dir ;
2012-10-06 16:04:58 -04:00
}
bool cRedstoneSimulator : : IsRepeaterPointingTo ( const Vector3i & a_RepeaterPos , char a_MetaData , const Vector3i & a_BlockPos )
{
switch ( a_MetaData & 0x3 )
{
case 0x0 :
{
if ( ( a_RepeaterPos - a_BlockPos ) . Equals ( Vector3i ( 0 , 0 , 1 ) ) )
{
return true ;
}
break ;
}
case 0x1 :
{
if ( ( a_RepeaterPos - a_BlockPos ) . Equals ( Vector3i ( - 1 , 0 , 0 ) ) )
{
return true ;
}
break ;
}
case 0x2 :
{
if ( ( a_RepeaterPos - a_BlockPos ) . Equals ( Vector3i ( 0 , 0 , - 1 ) ) )
{
return true ;
}
break ;
}
case 0x3 :
{
if ( ( a_RepeaterPos - a_BlockPos ) . Equals ( Vector3i ( 1 , 0 , 0 ) ) )
{
return true ;
}
break ;
}
}
return false ;
}
bool cRedstoneSimulator : : IsRepeaterPointingAway ( const Vector3i & a_RepeaterPos , char a_MetaData , const Vector3i & a_BlockPos )
{
switch ( a_MetaData & 0x3 )
{
case 0x0 :
{
if ( ( a_RepeaterPos - a_BlockPos ) . Equals ( Vector3i ( 0 , 0 , - 1 ) ) )
{
return true ;
}
break ;
}
case 0x1 :
{
if ( ( a_RepeaterPos - a_BlockPos ) . Equals ( Vector3i ( 1 , 0 , 0 ) ) )
{
return true ;
}
break ;
}
case 0x2 :
{
if ( ( a_RepeaterPos - a_BlockPos ) . Equals ( Vector3i ( 0 , 0 , 1 ) ) )
{
return true ;
}
break ;
}
case 0x3 :
{
if ( ( a_RepeaterPos - a_BlockPos ) . Equals ( Vector3i ( - 1 , 0 , 0 ) ) )
{
return true ;
}
break ;
}
}
return false ;
}
NIBBLETYPE cRedstoneSimulator : : RepeaterRotationToMetaData ( float a_Rotation )
{
a_Rotation + = 90 + 45 ; // So its not aligned with axis
if ( a_Rotation > 360.f )
{
a_Rotation - = 360.f ;
}
if ( ( a_Rotation > = 0.f ) & & ( a_Rotation < 90.f ) )
{
return 0x1 ;
}
else if ( ( a_Rotation > = 180 ) & & ( a_Rotation < 270 ) )
{
return 0x3 ;
}
else if ( ( a_Rotation > = 90 ) & & ( a_Rotation < 180 ) )
{
return 0x2 ;
}
else
{
return 0x0 ;
}
}
Vector3i cRedstoneSimulator : : GetRepeaterDirection ( NIBBLETYPE a_MetaData )
{
switch ( a_MetaData & 0x3 )
{
case 0x0 : return Vector3i ( 0 , 0 , - 1 ) ;
case 0x1 : return Vector3i ( 1 , 0 , 0 ) ;
case 0x2 : return Vector3i ( 0 , 0 , 1 ) ;
case 0x3 : return Vector3i ( - 1 , 0 , 0 ) ;
}
return Vector3i ( ) ;
}
void cRedstoneSimulator : : SetRepeater ( const Vector3i & a_Position , int a_Ticks , bool a_bPowerOn )
{
for ( RepeaterList : : iterator itr = m_SetRepeaters . begin ( ) ; itr ! = m_SetRepeaters . end ( ) ; + + itr )
{
sRepeaterChange & Change = * itr ;
if ( Change . Position . Equals ( a_Position ) )
{
if ( Change . bPowerOn & & a_bPowerOn = = false )
{
Change . bPowerOffNextTime = true ;
}
if ( a_bPowerOn = = true )
{
Change . bPowerOffNextTime = false ;
}
Change . bPowerOn | = a_bPowerOn ;
return ;
}
}
sRepeaterChange RC ;
RC . Position = a_Position ;
RC . Ticks = a_Ticks ;
RC . bPowerOn = a_bPowerOn ;
RC . bPowerOffNextTime = false ;
m_SetRepeaters . push_back ( RC ) ;
}