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

314 lines
16 KiB
Plaintext

#using scripts\codescripts\struct;
#using scripts\shared\clientfield_shared;
#using scripts\shared\math_shared;
#using scripts\shared\array_shared;
function autoexec main()
{
clientfield::register(
"actor",
"destructible_character_state",
1,
21,
"int" );
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 DestructServerUtils;
function private _GetDestructState( entity )
{
if ( IsDefined( entity._destruct_state ) )
{
return entity._destruct_state;
}
return 0;
}
function private _SetDestructed( entity, destructFlag )
{
entity._destruct_state = (_GetDestructState( entity ) | destructFlag);
entity clientfield::set( "destructible_character_state", entity._destruct_state );
}
function CopyDestructState( originalEntity, newEntity )
{
newEntity._destruct_state = _GetDestructState( originalEntity );
ToggleSpawnGibs( newEntity, false );
ReapplyDestructedPieces( newEntity );
}
function DestructHitLocPieces( entity, hitLoc )
{
if ( IsDefined(entity.destructibledef) )
{
destructBundle = struct::get_script_bundle( "destructiblecharacterdef", entity.destructibledef );
for ( index = 1; index <= destructBundle.pieces.size; index++ )
{
piece = destructBundle.pieces[ index - 1 ];
if ( IsDefined( piece.hitlocation ) && piece.hitlocation == hitLoc )
{
DestructPiece( entity, index );
}
}
}
}
function DestructLeftArmPieces( entity )
{
DestructHitLocPieces( entity, "left_arm_upper" );
DestructHitLocPieces( entity, "left_arm_lower" );
DestructHitLocPieces( entity, "left_hand" );
}
function DestructLeftLegPieces( entity )
{
DestructHitLocPieces( entity, "left_leg_upper" );
DestructHitLocPieces( entity, "left_leg_lower" );
DestructHitLocPieces( entity, "left_foot" );
}
function DestructPiece( entity, pieceNumber )
{
/# assert( (1 <= pieceNumber && pieceNumber <= 20) ); #/
if ( IsDestructed( entity, pieceNumber ) )
{
return;
}
_SetDestructed( entity, (1 << pieceNumber) );
if ( !IsDefined(entity.destructibledef) )
{
return;
}
destructBundle = struct::get_script_bundle( "destructiblecharacterdef", entity.destructibledef );
piece = destructBundle.pieces[ pieceNumber - 1 ];
if ( IsDefined( piece.hidetag ) && entity HasPart( piece.hidetag ) )
{
entity HidePart( piece.hidetag );
}
if ( IsDefined( piece.detachmodel ) )
{
entity Detach( piece.detachmodel, "" );
}
}
// Destruct a specified number of pieces
// Use 0 to destruct all pieces
function DestructNumberRandomPieces( entity, num_pieces_to_destruct=0 )
{
// Array containing our desctructible pieces.
destructible_pieces_list = [];
// Get the total number of breakable pieces we have
destructablePieces = GetPieceCount( entity );
if (num_pieces_to_destruct == 0)
{
num_pieces_to_destruct = destructablePieces;
}
// Build the list of pieces
for ( i = 0; i < destructablePieces; i++ )
{
destructible_pieces_list[i] = i + 1;
}
// Shuffle the list of pieces so we break off pieces at random
destructible_pieces_list = array::randomize(destructible_pieces_list);
// Go through the randomized list breaking off pieces until we either run out of pieces or broke off all the pieces we needed to.
foreach(piece in destructible_pieces_list)
{
if(!IsDestructed(entity,piece))
{
DestructPiece(entity,piece);
num_pieces_to_destruct--;
if(num_pieces_to_destruct == 0 )
break;
}
}
}
function DestructRandomPieces( entity)
{
destructPieces = GetPieceCount( entity );
for ( index = 0; index < destructPieces; index++ )
{
if ( math::cointoss() )
{
DestructPiece( entity, index + 1 );
}
}
}
function DestructRightArmPieces( entity )
{
DestructHitLocPieces( entity, "right_arm_upper" );
DestructHitLocPieces( entity, "right_arm_lower" );
DestructHitLocPieces( entity, "right_hand" );
}
function DestructRightLegPieces( entity )
{
DestructHitLocPieces( entity, "right_leg_upper" );
DestructHitLocPieces( entity, "right_leg_lower" );
DestructHitLocPieces( entity, "right_foot" );
}
function GetPieceCount( entity )
{
if ( IsDefined(entity.destructibledef) )
{
destructBundle = struct::get_script_bundle( "destructiblecharacterdef", entity.destructibledef );
if ( IsDefined( destructBundle ) )
{
return destructBundle.piececount;
}
}
return 0;
}
function HandleDamage(
eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex, modelIndex )
{
entity = self;
if ( ( isdefined( entity.skipDeath ) && entity.skipDeath ) )
{
return iDamage;
}
if ( ( isdefined( entity.skipGibs ) && entity.skipGibs ) )
{
return iDamage;
}
ToggleSpawnGibs( entity, true );
DestructHitLocPieces( entity, sHitLoc );
return iDamage;
}
function IsDestructed( entity, pieceNumber )
{
/# assert( (1 <= pieceNumber && pieceNumber <= 20) ); #/
return (_GetDestructState( entity ) & (1 << pieceNumber));
}
function ReapplyDestructedPieces( entity )
{
if ( !IsDefined(entity.destructibledef) )
{
return;
}
destructBundle = struct::get_script_bundle( "destructiblecharacterdef", entity.destructibledef );
for ( index = 1; index <= destructBundle.pieces.size; index++ )
{
if ( !IsDestructed( entity, index ) )
{
continue;
}
piece = destructBundle.pieces[ index - 1];
if ( IsDefined( piece.hidetag ) && entity HasPart( piece.hidetag ) )
{
entity HidePart( piece.hidetag );
}
}
}
function ShowDestructedPieces( entity )
{
if ( !IsDefined(entity.destructibledef) )
{
return;
}
destructBundle = struct::get_script_bundle( "destructiblecharacterdef", entity.destructibledef );
for ( index = 1; index <= destructBundle.pieces.size; index++ )
{
piece = destructBundle.pieces[ index - 1];
if ( IsDefined( piece.hidetag ) && entity HasPart( piece.hidetag ) )
{
entity ShowPart( piece.hidetag );
}
}
}
function ToggleSpawnGibs( entity, shouldSpawnGibs )
{
if ( shouldSpawnGibs )
{
entity._destruct_state = _GetDestructState( entity ) | 1;
}
else
{
entity._destruct_state = _GetDestructState( entity ) & ~1;
}
entity clientfield::set( "destructible_character_state", entity._destruct_state );
}
// end #namespace DestructServerUtils;