2023-04-13 17:30:38 +02:00

664 lines
23 KiB
Plaintext

#using scripts\codescripts\struct;
#using scripts\shared\clientfield_shared;
#using scripts\shared\throttle_shared;
#using scripts\shared\ai\systems\destructible_character;
#using scripts\shared\ai\systems\shared;
function private fields_equal( field_a, field_b)
{
if ( !isDefined(field_a) && !isDefined(field_b))
return true;
if ( isDefined(field_a) && isDefined(field_b) && field_a == field_b )
return true;
return false;
}
function private _IsDefaultPlayerGib( gibPieceFlag, gibStruct )
{
if ( !fields_equal( level.playerGibBundle.gibs[gibPieceFlag].gibdynentfx , gibStruct.gibdynentfx ) )
{
return false;
}
if ( !fields_equal( level.playerGibBundle.gibs[gibPieceFlag].gibfxtag, gibStruct.gibfxtag ) )
{
return false;
}
if ( !fields_equal( level.playerGibBundle.gibs[gibPieceFlag].gibfx, gibStruct.gibfx ) )
{
return false;
}
if ( !fields_equal( level.playerGibBundle.gibs[gibPieceFlag].gibtag, gibStruct.gibtag ) )
{
return false;
}
return true;
}
function autoexec main()
{
clientfield::register(
"actor",
"gib_state",
1,
(9),
"int" );
clientfield::register(
"playercorpse",
"gib_state",
1,
(9+3+3),
"int" );
gibDefinitions = struct::get_script_bundles("gibcharacterdef");
gibPieceLookup = [];
gibPieceLookup[2] = "annihilate";
gibPieceLookup[8] = "head";
gibPieceLookup[16] = "rightarm";
gibPieceLookup[32] = "leftarm";
gibPieceLookup[128] = "rightleg";
gibPieceLookup[256] = "leftleg";
processedBundles = [];
if ( SessionModeIsMultiplayerGame() )
{
level.playerGibBundle = SpawnStruct();
level.playerGibBundle.gibs = [];
level.playerGibBundle.name = "default_player";
level.playerGibBundle.gibs[2] = SpawnStruct();
level.playerGibBundle.gibs[8] = SpawnStruct();
level.playerGibBundle.gibs[32] = SpawnStruct();
level.playerGibBundle.gibs[256] = SpawnStruct();
level.playerGibBundle.gibs[16] = SpawnStruct();
level.playerGibBundle.gibs[128] = SpawnStruct();
level.playerGibBundle.gibs[2].gibfxtag = "j_spinelower";
level.playerGibBundle.gibs[2].gibfx = "blood/fx_blood_impact_exp_body_lg";
level.playerGibBundle.gibs[32].gibmodel = "c_t7_mp_battery_mpc_body1_s_larm";
level.playerGibBundle.gibs[32].gibdynentfx = "blood/fx_blood_gib_limb_trail_emitter";
level.playerGibBundle.gibs[32].gibfxtag = "j_elbow_le";
level.playerGibBundle.gibs[32].gibfx = "blood/fx_blood_gib_arm_sever_burst";
level.playerGibBundle.gibs[32].gibtag = "j_elbow_le";
level.playerGibBundle.gibs[256].gibmodel = "c_t7_mp_battery_mpc_body1_s_lleg";
level.playerGibBundle.gibs[256].gibdynentfx = "blood/fx_blood_gib_limb_trail_emitter";
level.playerGibBundle.gibs[256].gibfxtag = "j_knee_le";
level.playerGibBundle.gibs[256].gibfx = "blood/fx_blood_gib_leg_sever_burst";
level.playerGibBundle.gibs[256].gibtag = "j_knee_le";
level.playerGibBundle.gibs[16].gibmodel = "c_t7_mp_battery_mpc_body1_s_rarm";
level.playerGibBundle.gibs[16].gibdynentfx = "blood/fx_blood_gib_limb_trail_emitter";
level.playerGibBundle.gibs[16].gibfxtag = "j_elbow_ri";
level.playerGibBundle.gibs[16].gibfx = "blood/fx_blood_gib_arm_sever_burst_rt";
level.playerGibBundle.gibs[16].gibtag = "j_elbow_ri";
level.playerGibBundle.gibs[128].gibmodel = "c_t7_mp_battery_mpc_body1_s_rleg";
level.playerGibBundle.gibs[128].gibdynentfx = "blood/fx_blood_gib_limb_trail_emitter";
level.playerGibBundle.gibs[128].gibfxtag = "j_knee_ri";
level.playerGibBundle.gibs[128].gibfx = "blood/fx_blood_gib_leg_sever_burst_rt";
level.playerGibBundle.gibs[128].gibtag = "j_knee_ri";
}
// Process each gib bundle to allow quick access to information in the future.
foreach ( definitionName, definition in gibDefinitions )
{
gibBundle = SpawnStruct();
gibBundle.gibs = [];
gibBundle.name = definitionName;
default_player = false;
foreach ( gibPieceFlag, gibPieceName in gibPieceLookup )
{
gibStruct = SpawnStruct();
gibStruct.gibmodel = GetStructField( definition, gibPieceLookup[ gibPieceFlag ] + "_gibmodel" );
gibStruct.gibtag = GetStructField( definition, gibPieceLookup[ gibPieceFlag ] + "_gibtag" );
gibStruct.gibfx = GetStructField( definition, gibPieceLookup[ gibPieceFlag ] + "_gibfx" );
gibStruct.gibfxtag = GetStructField( definition, gibPieceLookup[ gibPieceFlag ] + "_gibeffecttag" );
gibStruct.gibdynentfx = GetStructField( definition, gibPieceLookup[ gibPieceFlag ] + "_gibdynentfx" );
gibStruct.gibsound = GetStructField( definition, gibPieceLookup[ gibPieceFlag ] + "_gibsound" );
gibStruct.gibhidetag = GetStructField( definition, gibPieceLookup[ gibPieceFlag ] + "_gibhidetag" );
if ( SessionModeIsMultiplayerGame() && _IsDefaultPlayerGib( gibPieceFlag, gibStruct ) )
{
default_player = true;
}
gibBundle.gibs[ gibPieceFlag ] = gibStruct;
}
if ( SessionModeIsMultiplayerGame() && default_player )
{
processedBundles[ definitionName ] = level.playerGibBundle;
}
else
{
processedBundles[ definitionName ] = gibBundle;
}
}
// Replaces all gib character define bundles with their processed form to free unncessary script variables.
level.scriptbundles[ "gibcharacterdef" ] = processedBundles;
if ( !IsDefined( level.gib_throttle ) )
{
level.gib_throttle = new Throttle();
// Two gibs every 0.2 seconds.
[[ level.gib_throttle ]]->Initialize( 2, 0.2 );
}
}
#namespace GibServerUtils;
function private _Annihilate( entity )
{
if ( IsDefined( entity ) )
{
entity NotSolid();
}
}
function private _GetGibExtraModel( entity, gibFlag )
{
if ( gibFlag == 4 )
return (isdefined(entity.gib_data)?entity.gib_data.hatmodel:entity.hatmodel);
else if ( gibFlag == 8 )
return (isdefined(entity.gib_data)?entity.gib_data.head:entity.head);
else
AssertMsg( "Unable to find gib model." );
}
// Used to solely gib equipment and the actor's head.
// Does not change the torso or leg models.
function private _GibExtra( entity, gibFlag )
{
if ( IsGibbed( entity, gibFlag ) )
{
return false;
}
if ( !_HasGibDef( entity ) )
{
return false;
}
entity thread _GibExtraInternal( entity, gibFlag );
return true;
}
function private _GibExtraInternal( entity, gibFlag )
{
// Allow simulatenous gibs to happen on the same frame, since the network
// cost is negligible if the gib is for the same entity.
if ( entity.gib_time !== GetTime() )
{
[[ level.gib_throttle ]]->WaitInQueue( entity );
}
if ( !IsDefined( entity ) )
{
return;
}
entity.gib_time = GetTime();
if ( IsGibbed( entity, gibFlag ) )
{
return false;
}
if ( gibFlag == 8 )
{
if ( IsDefined( (isdefined(entity.gib_data)?entity.gib_data.torsoDmg5:entity.torsoDmg5) ) )
{
entity Attach( (isdefined(entity.gib_data)?entity.gib_data.torsoDmg5:entity.torsoDmg5), "", true );
}
}
_SetGibbed( entity, gibFlag, undefined );
DestructServerUtils::ShowDestructedPieces( entity );
ShowHiddenGibPieces( entity );
gibModel = _GetGibExtraModel( entity, gibFlag );
if ( IsDefined( gibModel ) )
{
entity Detach( gibModel, "" );
}
DestructServerUtils::ReapplyDestructedPieces( entity );
ReapplyHiddenGibPieces( entity );
}
// Used to gib torso or leg pieces, not including equipment or the actor's head.
// Changes the torso and leg models.
function private _GibEntity( entity, gibFlag )
{
if ( IsGibbed( entity, gibFlag ) || !_HasGibPieces( entity, gibFlag ) )
{
return false;
}
if ( !_HasGibDef( entity ) )
{
return false;
}
entity thread _GibEntityInternal( entity, gibFlag );
return true;
}
function private _GibEntityInternal( entity, gibFlag )
{
// Allow simulatenous gibs to happen on the same frame, since the network
// cost is negligible if the gib is for the same entity.
if ( entity.gib_time !== GetTime() )
{
[[ level.gib_throttle ]]->WaitInQueue( entity );
}
if ( !IsDefined( entity ) )
{
return;
}
entity.gib_time = GetTime();
if ( IsGibbed( entity, gibFlag ) )
{
return;
}
DestructServerUtils::ShowDestructedPieces( entity );
ShowHiddenGibPieces( entity );
if ( !(_GetGibbedState( entity ) < 16) )
{
legModel = _GetGibbedLegModel( entity );
entity Detach( legModel );
}
_SetGibbed( entity, gibFlag, undefined );
entity SetModel( _GetGibbedTorsoModel( entity ) );
entity Attach( _GetGibbedLegModel( entity ) );
DestructServerUtils::ReapplyDestructedPieces( entity );
ReapplyHiddenGibPieces( entity );
}
function private _GetGibbedLegModel( entity )
{
gibState = _GetGibbedState( entity );
rightLegGibbed = (gibState & 128);
leftLegGibbed = (gibState & 256);
if ( rightLegGibbed && leftLegGibbed)
{
return (isdefined(entity.gib_data)?entity.gib_data.legDmg4:entity.legDmg4);
}
else if ( rightLegGibbed )
{
return (isdefined(entity.gib_data)?entity.gib_data.legDmg2:entity.legDmg2);
}
else if ( leftLegGibbed )
{
return (isdefined(entity.gib_data)?entity.gib_data.legDmg3:entity.legDmg3);
}
return (isdefined(entity.gib_data)?entity.gib_data.legDmg1:entity.legDmg1);
}
function private _GetGibbedState( entity )
{
if ( IsDefined( entity.gib_state ) )
{
return entity.gib_state;
}
return 0;
}
function private _GetGibbedTorsoModel( entity )
{
gibState = _GetGibbedState( entity );
rightArmGibbed = (gibState & 16);
leftArmGibbed = (gibState & 32);
if ( rightArmGibbed && leftArmGibbed )
{
return (isdefined(entity.gib_data)?entity.gib_data.torsoDmg2:entity.torsoDmg2);
// TODO(David Young 5-14-14): Currently AI's don't support both arms getting blown off.
// return GIB_TORSO_NO_ARMS_MODEL( entity );
}
else if ( rightArmGibbed )
{
return (isdefined(entity.gib_data)?entity.gib_data.torsoDmg2:entity.torsoDmg2);
}
else if ( leftArmGibbed )
{
return (isdefined(entity.gib_data)?entity.gib_data.torsoDmg3:entity.torsoDmg3);
}
return (isdefined(entity.gib_data)?entity.gib_data.torsoDmg1:entity.torsoDmg1);
}
function private _HasGibDef( entity )
{
return IsDefined( entity.gibdef );
}
function private _HasGibPieces( entity, gibFlag )
{
hasGibPieces = false;
gibState = _GetGibbedState( entity );
entity.gib_state = (gibState | ( gibFlag & ( ( 1 << 9 ) - 1 ) ));
if ( IsDefined( _GetGibbedTorsoModel( entity ) ) &&
IsDefined( _GetGibbedLegModel( entity ) ) )
{
hasGibPieces = true;
}
entity.gib_state = gibState;
return hasGibPieces;
}
function private _SetGibbed( entity, gibFlag, gibDir )
{
if ( IsDefined( gibDir ) )
{
angles = VectortoAngles( gibDir );
yaw = angles[1];
yaw_bits = getbitsforangle( yaw, 3 );
entity.gib_state = (( _GetGibbedState( entity )|gibFlag & ( ( 1 << 9 ) - 1 ) ) + ( yaw_bits << 9 ) );
}
else
{
entity.gib_state = (_GetGibbedState( entity ) | ( gibFlag & ( ( 1 << 9 ) - 1 ) ));
}
entity.gibbed = true;
entity clientfield::set( "gib_state", entity.gib_state );
}
function Annihilate( entity )
{
if ( !_HasGibDef( entity ) )
{
return false;
}
gibBundle = struct::get_script_bundle("gibcharacterdef",entity.gibdef);
if ( !IsDefined( gibBundle ) || !IsDefined( gibBundle.gibs ) )
{
return false;
}
gibPieceStruct = gibBundle.gibs[ 2 ];
// Make sure there is some sort of FX to play if we're annihilating the AI.
if ( IsDefined( gibPieceStruct ) )
{
if ( IsDefined( gibPieceStruct.gibfx ) )
{
_SetGibbed( entity, 2, undefined );
entity thread _Annihilate( entity );
return true;
}
}
return false;
}
function CopyGibState( originalEntity, newEntity )
{
newEntity.gib_state = _GetGibbedState( originalEntity );
ToggleSpawnGibs( newEntity, false );
ReapplyHiddenGibPieces( newEntity );
}
function IsGibbed( entity, gibFlag )
{
return (_GetGibbedState( entity ) & gibFlag);
}
function GibHat( entity )
{
return _GibExtra( entity, 4 );
}
function GibHead( entity )
{
GibHat( entity );
return _GibExtra( entity, 8 );
}
function GibLeftArm( entity )
{
// TODO(David Young 5-14-14): Currently AI's don't support both arms getting blown off.
if ( IsGibbed( entity, 16 ) )
{
return false;
}
if ( _GibEntity( entity, 32 ) )
{
DestructServerUtils::DestructLeftArmPieces( entity );
return true;
}
return false;
}
function GibRightArm( entity )
{
// TODO(David Young 5-14-14): Currently AI's don't support both arms getting blown off.
if ( IsGibbed( entity, 32 ) )
{
return false;
}
if ( _GibEntity( entity, 16 ) )
{
DestructServerUtils::DestructRightArmPieces( entity );
entity thread shared::DropAIWeapon();
return true;
}
return false;
}
function GibLeftLeg( entity )
{
if ( _GibEntity( entity, 256 ) )
{
DestructServerUtils::DestructLeftLegPieces( entity );
return true;
}
return false;
}
function GibRightLeg( entity )
{
if ( _GibEntity( entity, 128 ) )
{
DestructServerUtils::DestructRightLegPieces( entity );
return true;
}
return false;
}
function GibLegs( entity )
{
if ( _GibEntity( entity, (128+256) ) )
{
DestructServerUtils::DestructRightLegPieces( entity );
DestructServerUtils::DestructLeftLegPieces( entity );
return true;
}
return false;
}
function PlayerGibLeftArm( entity )
{
if ( IsDefined( entity.body ) )
{
dir = (1,0,0);
_SetGibbed( entity.body, 32, dir );
}
}
function PlayerGibRightArm( entity )
{
if ( IsDefined( entity.body ) )
{
dir = (1,0,0);
_SetGibbed( entity.body, 16, dir );
}
}
function PlayerGibLeftLeg( entity )
{
if ( IsDefined( entity.body ) )
{
dir = (1,0,0);
_SetGibbed( entity.body, 256, dir );
}
}
function PlayerGibRightLeg( entity )
{
if ( IsDefined( entity.body ) )
{
dir = (1,0,0);
_SetGibbed( entity.body, 128, dir );
}
}
function PlayerGibLegs( entity )
{
if ( IsDefined( entity.body ) )
{
dir = (1,0,0);
_SetGibbed( entity.body, 128, dir );
_SetGibbed( entity.body, 256, dir );
}
}
function PlayerGibLeftArmVel( entity, dir )
{
if ( IsDefined( entity.body ) )
{
_SetGibbed( entity.body, 32, dir );
}
}
function PlayerGibRightArmVel( entity, dir )
{
if ( IsDefined( entity.body ) )
{
_SetGibbed( entity.body, 16, dir );
}
}
function PlayerGibLeftLegVel( entity, dir )
{
if ( IsDefined( entity.body ) )
{
_SetGibbed( entity.body, 256, dir );
}
}
function PlayerGibRightLegVel( entity, dir )
{
if ( IsDefined( entity.body ) )
{
_SetGibbed( entity.body, 128, dir );
}
}
function PlayerGibLegsVel( entity, dir )
{
if ( IsDefined( entity.body ) )
{
_SetGibbed( entity.body, 128, dir );
_SetGibbed( entity.body, 256, dir );
}
}
function ReapplyHiddenGibPieces( entity )
{
if ( !_HasGibDef( entity ) )
{
return;
}
gibBundle = struct::get_script_bundle("gibcharacterdef",entity.gibdef);
foreach ( gibFlag, gib in gibBundle.gibs )
{
if ( !IsGibbed( entity, gibFlag ) )
{
continue;
}
if ( IsDefined( gib.gibhidetag ) && IsAlive( entity ) && entity HasPart( gib.gibhidetag ) )
{
if ( !( isdefined( entity.skipDeath ) && entity.skipDeath ) )
{
// Gighidetag's are only used for hiding hitlocations. If the entity is already dead or skipping death animations don't apply them.
entity HidePart( gib.gibhidetag, "", true );
}
}
}
}
function ShowHiddenGibPieces( entity )
{
if ( !_HasGibDef( entity ) )
{
return;
}
gibBundle = struct::get_script_bundle("gibcharacterdef",entity.gibdef);
foreach ( gibFlag, gib in gibBundle.gibs )
{
if ( IsDefined( gib.gibhidetag ) && entity HasPart( gib.gibhidetag ) )
{
entity ShowPart( gib.gibhidetag, "", true );
}
}
}
function ToggleSpawnGibs( entity, shouldSpawnGibs )
{
if ( !shouldSpawnGibs )
{
entity.gib_state = _GetGibbedState( entity ) | 1;
}
else
{
entity.gib_state = _GetGibbedState( entity ) & ~1;
}
entity clientfield::set( "gib_state", entity.gib_state );
}