boiii-scripts/shared/ai/systems/destructible_character.csc
2023-04-13 17:30:38 +02:00

168 lines
13 KiB
Plaintext

#using scripts\codescripts\struct;
#using scripts\shared\ai\systems\gib;
#using scripts\shared\clientfield_shared;
function autoexec main()
{
clientfield::register(
"actor",
"destructible_character_state",
1,
21,
"int",
&DestructClientUtils::_DestructHandler,
!true,
!true);
destructibles = struct::get_script_bundles( "destructiblecharacterdef" );
processedBundles = [];
// Process each destructible bundle to allow quick access to information in the future.
foreach ( destructibleName, destructible in destructibles )
{
destructBundle = SpawnStruct();
destructBundle.pieceCount = destructible.pieceCount;
destructBundle.pieces = [];
destructBundle.name = destructibleName;
for ( index = 1; index <= destructBundle.pieceCount; index++ )
{
pieceStruct = SpawnStruct();
pieceStruct.gibmodel = GetStructField( destructible, "piece" + index + "_gibmodel" );
pieceStruct.gibtag = GetStructField( destructible, "piece" + index + "_gibtag" );
pieceStruct.gibfx = GetStructField( destructible, "piece" + index + "_gibfx" );
pieceStruct.gibfxtag = GetStructField( destructible, "piece" + index + "_gibeffecttag" );
pieceStruct.gibdynentfx = GetStructField( destructible, "piece" + index + "_gibdynentfx" );
pieceStruct.gibsound = GetStructField( destructible, "piece" + index + "_gibsound" );
pieceStruct.hitlocation = GetStructField( destructible, "piece" + index + "_hitlocation" );
pieceStruct.hidetag = GetStructField( destructible, "piece" + index + "_hidetag" );
pieceStruct.detachmodel = GetStructField( destructible, "piece" + index + "_detachmodel" );
destructBundle.pieces[ destructBundle.pieces.size ] = pieceStruct;
}
processedBundles[ destructibleName ] = destructBundle;
}
// Replaces all destructible character define bundles with their processed form to free unncessary script variables.
level.scriptbundles[ "destructiblecharacterdef" ] = processedBundles;
}
#namespace DestructClientUtils;
function private _DestructHandler( localClientNum, oldValue, newValue, bNewEnt, bInitialSnap, fieldName, wasDemoJump )
{
entity = self;
destructFlags = (oldValue ^ newValue);
shouldSpawnGibs = (newValue & 1);
// Don't use the old clientfield value for new entities.
if ( bNewEnt )
{
destructFlags = (0 ^ newValue);
}
if ( !IsDefined(entity.destructibledef) )
{
return;
}
// Only look at destructible pieces, skip toggle bit.
currentDestructFlag = (1 << 1);
pieceNumber = 1;
// Handles any number of simultaneous gibbings.
while ( destructFlags >= currentDestructFlag )
{
if ( destructFlags & currentDestructFlag )
{
_DestructPiece( localClientNum, entity, pieceNumber, shouldSpawnGibs );
}
currentDestructFlag = currentDestructFlag << 1;
pieceNumber++;
}
entity._destruct_state = newValue;
}
function private _DestructPiece( localClientNum, entity, pieceNumber, shouldSpawnGibs )
{
if ( !IsDefined(entity.destructibledef) )
{
return;
}
destructBundle = struct::get_script_bundle( "destructiblecharacterdef", entity.destructibledef );
piece = destructBundle.pieces[ pieceNumber - 1 ];
if ( IsDefined( piece ) )
{
if ( shouldSpawnGibs )
{
GibClientUtils::_PlayGibFX( localClientNum, entity, piece.gibfx, piece.gibfxtag );
entity thread GibClientUtils::_GibPiece( localClientNum, entity, piece.gibmodel, piece.gibtag, piece.gibdynentfx );
GibClientUtils::_PlayGibSound( localClientNum, entity, piece.gibsound );
}
_HandleDestructCallbacks( localClientNum, entity, pieceNumber );
}
}
function private _GetDestructState( localClientNum, entity )
{
if ( IsDefined( entity._destruct_state ) )
{
return entity._destruct_state;
}
return 0;
}
function private _HandleDestructCallbacks( localClientNum, entity, pieceNumber )
{
if ( IsDefined( entity._destructCallbacks ) &&
IsDefined( entity._destructCallbacks[ pieceNumber ] ) )
{
foreach ( callback in entity._destructCallbacks[ pieceNumber ] )
{
if ( IsFunctionPtr( callback ) )
{
[[callback]]( localClientNum, entity, pieceNumber );
}
}
}
}
function AddDestructPieceCallback( localClientNum, entity, pieceNumber, callbackFunction )
{
assert( IsFunctionPtr( callbackFunction ) );
if ( !IsDefined( entity._destructCallbacks ) )
{
entity._destructCallbacks = [];
}
if ( !IsDefined( entity._destructCallbacks[ pieceNumber ] ) )
{
entity._destructCallbacks[ pieceNumber ] = [];
}
destructCallbacks = entity._destructCallbacks[ pieceNumber ];
destructCallbacks[ destructCallbacks.size ] = callbackFunction;
entity._destructCallbacks[ pieceNumber ] = destructCallbacks;
}
function IsPieceDestructed( localClientNum, entity, pieceNumber )
{
return (_GetDestructState( localClientNum, entity ) & (1 << pieceNumber));
}
// end #namespace DestructClientUtils;