Skip to content

Instantly share code, notes, and snippets.

@R4to0
Created April 28, 2019 17:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save R4to0/f6bc00ba3a7e80f4299939fda07b493e to your computer and use it in GitHub Desktop.
Save R4to0/f6bc00ba3a7e80f4299939fda07b493e to your computer and use it in GitHub Desktop.
// PS2HL Eye Scanner
// Based off from https://github.com/supadupaplex/ya-ps2hl-dll
namespace PS2ITEMSCANNER
{
// Scanner model
const string g_model = "models/sc_decay/eye_scanner.mdl";
// Flags
const uint SCN_FLAG_LOCKED = 1; // Locked for player flag
// Sequences
enum ScanSeq
{
SCN_SEQ_CLOSED = 0, // "idle_CLOSED"
SCN_SEQ_OPEN, // "idle_OPEN"
SCN_SEQ_ACTIVATE, // "ACTIVATE"
SCN_SEQ_DEACTIVATE //" DEACTIVATE"
};
//const uint SCN_SEQ_CLOSED = 0; // "idle_CLOSED"
//const uint SCN_SEQ_OPEN = 1; // "idle_OPEN"
//const uint SCN_SEQ_ACTIVATE = 2; // "ACTIVATE"
//const uint SCN_SEQ_DEACTIVATE = 3; //" DEACTIVATE"
// States for scanner
enum ScanState
{
SCN_STATE_IDLE, // Rest
SCN_STATE_OPEN, // Open
SCN_STATE_ACTIVE, // Cycle skins
SCN_STATE_CLOSE // Close
};
// Timings
const float SCN_DELAY_THINK = 0.15f; // Delay before Think() calls. Affects skin cycle speed.
const float SCN_DELAY_START = 0.01f; // Delay before startup
const float SCN_DELAY_ACTIVATE = 2.0f; // 2.4 // Defines time before cycling skins
const float SCN_DELAY_DEACTIVATE = 4.6f; // 5.0 // Defines time when to end cycling skins
const float SCN_USE_RADIUS = 25.0f; // Defines distance at which player can use scanner
// Item class. Using CBaseAnimating because of some model functions
// and there is no CBaseButton exposed in AS -R4to0
class CItemScanner : ScriptBaseAnimating
{
float ResetDelay; // How many seconds to be inactive
string_t LockedTarget; // What to activate on deny
string_t UnlockedTarget; // What to activate on accept
// For Use()
private float LastUseTime; // Time when last used (used to track reset delay for player)
// For Think()
private ScanState CurrentState;
private float StartupTime; // Time when scanner received use request (used to to track states)
// Precache handler
void Precache()
{
BaseClass.Precache();
g_Game.PrecacheModel( g_model );
}
// Object capabilities: Allow usage. -R4to0
int ObjectCaps()
{
return BaseClass.ObjectCaps() | FCAP_IMPULSE_USE;
}
// Spawn handler
void Spawn()
{
// Precache
Precache();
// Set the model
g_EntityFuncs.SetModel( self, g_model );
// Set up BBox
self.pev.solid = SOLID_BBOX; // Changed from SOLID_NOT to SOLID_BBOX -R4to0
SetSequenceBox();
// Check flags
if( ( self.pev.spawnflags & SCN_FLAG_LOCKED ) != 0 )
g_Game.AlertMessage( at_console, "item_eyescanner: got flag 1 >> locked for player...\n" );
// Reset state
ChangeState( SCN_STATE_CLOSE, SCN_SEQ_DEACTIVATE );
LastUseTime = g_Engine.time - ResetDelay;
// Set think
self.pev.nextthink = -1;
//self.pev.nextthink = g_Engine.time + SCN_DELAY_THINK;
}
// Parse keys
bool KeyValue( const string& in szKey, const string& in szValue )
{
if( szKey == "reset_delay" )
{
// Reset delay
ResetDelay = atof( szValue );
return true;
}
else if( szKey == "locked_target" )
{
// Target to fire when deny
LockedTarget = szValue;
return true;
}
else if( szKey == "unlocked_target" )
{
// Target to fire when accept
UnlockedTarget = szValue;
return true;
}
else
return BaseClass.KeyValue( szKey, szValue );
}
// Think handler
void Think()
{
g_Game.AlertMessage( at_console, "item_eyescanner: thinking ...\n" );
// Get current time
float CurrentTime = g_Engine.time;
// Set think delay
self.pev.nextthink = CurrentTime + SCN_DELAY_THINK;
// Call animation handler
self.StudioFrameAdvance( 0 );
// State handler
switch( CurrentState )
{
//case SCHED_SC_IDLE:
// // Do nothing
// break;
case SCN_STATE_OPEN:
// Wait for opening animation
if( self.m_fSequenceFinished )
{
// Go to active state once opening animation is ended
ChangeState( SCN_STATE_ACTIVE, SCN_SEQ_OPEN );
}
if( CurrentTime > ( StartupTime + SCN_DELAY_ACTIVATE ) )
{
// Cycle skins
self.pev.skin++;
if( self.pev.skin > 3 )
self.pev.skin = 1;
}
break;
case SCN_STATE_ACTIVE:
if( CurrentTime > ( StartupTime + SCN_DELAY_ACTIVATE ) )
{
// Continue to cycle skins
self.pev.skin++;
if( self.pev.skin > 3 )
self.pev.skin = 1;
}
if( CurrentTime > ( StartupTime + SCN_DELAY_DEACTIVATE ) )
{
// Start closing once enough time is passed
self.pev.skin = 0;
ChangeState( SCN_STATE_CLOSE, SCN_SEQ_DEACTIVATE );
}
break;
case SCN_STATE_CLOSE:
if( self.m_fSequenceFinished )
{
// Go to idle state once closing animation is ended
ChangeState( SCN_STATE_IDLE, SCN_SEQ_CLOSED );
// Hibernate
self.pev.nextthink = -1;
}
break;
default:
// Do nothing
break;
}
}
// Change sequence
void ChangeSequence( int NewSequence )
{
// Prepare sequence
self.pev.sequence = NewSequence;
self.pev.frame = 0;
self.ResetSequenceInfo();
}
// Change state for Think()
void ChangeState( ScanState NewState, int NewSequence )
{
CurrentState = NewState;
ChangeSequence( NewSequence );
}
// Use handler
void Use( CBaseEntity@ pActivator, CBaseEntity@ pCaller, USE_TYPE useType, float value )
{
// Get current time
float CurrentTime = g_Engine.time;
// Make sure that we have an activator
if( pActivator is null )
@pActivator = self;
// Check activator
if( pActivator !is null && pActivator.IsPlayer() )
{
// Player //
// Hack to prevent false "player" call on c3a2
Vector Dist = self.pev.origin - pActivator.pev.origin;
if( Dist.Length2D() > SCN_USE_RADIUS )
{
g_Game.AlertMessage( at_console, "item_eyescanner: player is too far ...\n" );
return;
}
// Check if busy
if( CurrentState != SCN_STATE_IDLE )
{
// Busy - reject until the state is idle
g_Game.AlertMessage( at_console, "item_eyescanner: busy...\n" );
return;
}
// Check reset delay
if( ( CurrentTime - LastUseTime ) < ResetDelay )
{
// Hibernated - reject until after reset delay
g_Game.AlertMessage( at_console, "item_eyescanner: hibernated...\n" );
return;
}
// Select target
g_Game.AlertMessage( at_console, "item_eyescanner: started by player ...\n" );
if( ( self.pev.spawnflags & SCN_FLAG_LOCKED ) != 0 )
self.pev.target = LockedTarget;
else
self.pev.target = UnlockedTarget;
// Fire target
self.SUB_UseTargets( self, USE_ON, 1 );
//if( self.pev.target )
// g_Game.AlertMessage( at_console, "\n\nitem_eyescanner: fired target \"%s\"\n\n\n", self.pev.target );
// Start scanner
ChangeState( SCN_STATE_OPEN, SCN_SEQ_ACTIVATE );
self.pev.nextthink = StartupTime = CurrentTime + SCN_DELAY_START;
}
else
{
// Script //
// Check if triggered once or in burst
if( ( CurrentTime - LastUseTime ) > ResetDelay )
{
// Once - accept
g_Game.AlertMessage( at_console, "item_eyescanner: started by script ...\n" );
self.pev.target = UnlockedTarget;
// Fire target
ChangeState( SCN_STATE_OPEN, SCN_SEQ_ACTIVATE );
self.pev.nextthink = StartupTime = CurrentTime + SCN_DELAY_START;
}
else
{
// Burst - can't figure out what it does
g_Game.AlertMessage( at_console, "item_eyescanner: burst detected ...\n" );
}
}
// Update last use time
LastUseTime = CurrentTime;
}
// Extract BBox from sequence (ripped from CBaseAnimating with one little change)
void SetSequenceBox()
{
Vector mins, maxs;
// Get sequence bbox
if( self.ExtractBbox( self.pev.sequence, mins, maxs ) )
{
// expand box for rotation
// find min / max for rotations
float yaw = self.pev.angles.y * ( Math.PI / 180.0f );
Vector xvector, yvector;
xvector.x = cos( yaw );
xvector.y = sin( yaw );
yvector.x = -sin( yaw );
yvector.y = cos( yaw );
array<Vector> bounds( 2 );
bounds[0] = mins; // mins self.pev.mins
bounds[1] = maxs; // maxs self.pev.maxs
Vector rmin( 9999, 9999, 9999 );
Vector rmax( -9999, -9999, -9999 );
Vector base, transformed;
for( uint i = 0; i <= 1; i++ )
{
base.x = bounds[i].x;
for( uint j = 0; j <= 1; j++ )
{
base.y = bounds[j].y;
for( uint k = 0; k <= 1; k++ )
{
base.z = bounds[k].z;
// transform the point
transformed.x = ( xvector.x * base.x ) + ( yvector.x * base.y );
transformed.y = ( xvector.y * base.x ) + ( yvector.y * base.y );
transformed.z = base.z;
if( transformed.x < rmin.x )
rmin.x = transformed.x;
if( transformed.x > rmax.x )
rmax.x = transformed.x;
if( transformed.y < rmin.y )
rmin.y = transformed.y;
if( transformed.y > rmax.y )
rmax.y = transformed.y;
if( transformed.z < rmin.z )
rmin.z = transformed.z;
if( transformed.z > rmax.z )
rmax.z = transformed.z;
}
}
}
//rmin.z = 0;
//rmax.z = rmin.z + 1;
g_EntityFuncs.SetSize( self.pev, rmin, rmax );
}
}
}
void Register()
{
g_CustomEntityFuncs.RegisterCustomEntity( "PS2ITEMSCANNER::CItemScanner", "item_eyescanner" );
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment