Created
April 28, 2019 17:33
-
-
Save R4to0/f6bc00ba3a7e80f4299939fda07b493e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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