📄 sentient.cpp
字号:
this->client->pers.netname, armor_damage, damage, location );
}
else
{
gi.cprintf ( attacker->edict, PRINT_HIGH, "TARG:%s ARMOR_DAM:%0.2f TOT_DAM:%0.2f LOC:%s\n",
getClassname(), armor_damage, damage, location );
}
}
// Send message to victim
if ( this->isClient() && attacker != this )
{
gi.cprintf ( this->edict, PRINT_HIGH, "TARG:%s ARMOR_DAM:%0.2f TOT_DAM:%0.2f LOC:%s\n",
this->client->pers.netname, armor_damage, damage, location );
}
}
// Blood and sparks effects
if (
( damage > 0 ) &&
( meansofdeath != MOD_DROWN ) &&
( meansofdeath != MOD_MUTANT_DRAIN )
)
{
// Blood particles
if ( flags & FL_BLOOD )
{
Particles( position, normal, __min( 150,damage ), 127, PARTICLE_RANDOM );
// Blood splat
if ( dflags & DAMAGE_BULLET )
SprayBlood( position, direction, damage );
}
// Sparks from metal
else if ( flags & FL_SPARKS )
{
SpawnSparks (position, normal, __min(damage, 75) );
}
}
else if ( armor_damage > 0 )
{
// Sparks off armor
Particles( position, normal, __min(armor_damage, 75), 122, 0 );
}
// Gib if we are dead and get hit by a rocket or shotgun
if ( deadflag == DEAD_DEAD )
{
health -= damage;
if ( DoGib( meansofdeath, inflictor ) )
{
Event *gibEv;
gibEv = new Event( EV_Gib );
gibEv->AddInteger( 0 );
ProcessEvent( gibEv );
}
return;
}
else if ( deadflag )
{
health -= damage;
return;
}
// Do the kick
if (!(dflags & DAMAGE_NO_KNOCKBACK))
{
if ((knockback) &&
(movetype != MOVETYPE_NONE) &&
(movetype != MOVETYPE_BOUNCE) &&
(movetype != MOVETYPE_PUSH) &&
(movetype != MOVETYPE_STOP))
{
float m;
if (mass < 50)
m = 50;
else
m = mass;
direction.normalize();
if ( isClient() && ( attacker == this ) && deathmatch->value )
momentum = direction * ( 1700.0f * ( float )knockback / m ); // the rocket jump hack...
else
momentum = direction * ( 500.0f * ( float )knockback / m );
if ( dflags & DAMAGE_BULLET )
{
// Clip the z velocity for bullet weapons
if ( momentum.z > 75)
momentum.z = 75;
}
velocity += momentum;
}
}
// check for godmode or invincibility
if ( flags & FL_GODMODE )
{
return;
}
// do the damage
health -= damage;
// He's dead jim, send out a bunch of events
if ( health <= 0 )
{
if ( ( meansofdeath == MOD_ION ) && !( flags & FL_NOION ) )
{
flags |= FL_DIE_TESSELATE;
RandomGlobalSound( "snd_tesselate" );
}
event = new Event( EV_Killed );
event->AddEntity( attacker );
event->AddInteger( damage );
event->AddEntity( inflictor );
event->AddString( location );
event->AddInteger( meansofdeath );
ProcessEvent( event );
return;
}
if ( ( damage > 0 ) && ( meansofdeath == MOD_ION ) && !( flags & FL_NOION ) )
{
// Do the ion particlizer effect
TesselateModel
(
this,
1,
1000,
direction,
damage,
1.0f,
0,
vec3_origin,
TESSELATE_EXPANDANDSHRINK,
126
);
}
// Tesselate from damage
if (flags & FL_TESSELATE)
{
TesselateModel
(
this,
tess_min_size,
tess_max_size,
direction,
damage,
1.0f,
tess_thickness,
vec3_origin
);
}
// Darken if we are hurt
if (flags & FL_DARKEN)
{
edict->s.renderfx |= RF_LIGHTOFFSET;
if ( max_health )
{
edict->s.lightofs = - ( 40.0f * ( (float)(max_health - health) / (float)max_health ) );
}
else
{
edict->s.lightofs -= damage;
}
if ( edict->s.lightofs < -127 )
edict->s.lightofs = -127;
if ( edict->s.lightofs > 127 )
edict->s.lightofs = 127;
}
// Drop your weapon if you get hit in the hands
if ( location == gun_bone_group_name && ( ( damage > 50 ) || ( G_Random( 1 ) > 0.97f ) ) )
{
// don't drop weapons when in deathmatch and DF_NO_DROP_WEAPONS is set
if ( currentWeapon && currentWeapon->IsDroppable() && ( !deathmatch->value || !DM_FLAG( DF_NO_DROP_WEAPONS ) ) )
{
DropCurrentWeapon();
WeaponKnockedFromHands();
}
}
if ( meansofdeath == MOD_MUTANT_DRAIN )
return;
// Send pain event
event = new Event( EV_Pain );
event->AddFloat( damage );
event->AddEntity( attacker );
event->AddString( location );
event->AddInteger( meansofdeath );
ProcessEvent( event );
}
void Sentient::UpdateSilencedWeapons
(
void
)
{
// If the current weapon is silencable, then change it.
if ( currentWeapon && currentWeapon->IsSilenced() )
{
currentWeapon->ProcessEvent(EV_Weapon_PutAwayAndRaise);
}
}
int Sentient::NumInventoryItems
(
void
)
{
return inventory.NumObjects();
}
Item *Sentient::NextItem
(
Item *item
)
{
Item *next_item;
int i;
int n;
qboolean item_found = false;
if ( !item )
{
item_found = true;
}
else if ( !inventory.ObjectInList( item->entnum ) )
{
error( "NextItem", "Item not in list" );
}
n = inventory.NumObjects();
for( i = 1; i <= n; i++ )
{
next_item = ( Item * )G_GetEntity( inventory.ObjectAt( i ) );
assert( next_item );
if ( next_item->isSubclassOf( InventoryItem ) && item_found )
return next_item;
if ( next_item == item )
item_found = true;
}
return NULL;
}
Item *Sentient::PrevItem
(
Item *item
)
{
Item *prev_item;
int i;
int n;
qboolean item_found = false;
if ( !item )
{
item_found = true;
}
else if ( !inventory.ObjectInList( item->entnum ) )
{
error( "NextItem", "Item not in list" );
}
n = inventory.NumObjects();
for( i = n; i >= 1; i-- )
{
prev_item = ( Item * )G_GetEntity( inventory.ObjectAt( i ) );
assert( prev_item );
if ( prev_item->isSubclassOf( InventoryItem ) && item_found)
return prev_item;
if ( prev_item == item )
item_found = true;
}
return NULL;
}
// This will search a dead body and create a floating inventory for that player
// which will be displayed on the client as a list of icons. If the user presses
// use, then he will pick up the items in that floating inventory, and the body
// will be faded out.
void Sentient::SearchBody
(
Event *ev
)
{
int i,n;
Item *item;
Entity *other;
Player *player;
Event *event;
qboolean inventory_created = false;
other = ev->GetEntity( 1 );
assert( other );
// Only players can touch this
if ( !other->isSubclassOf( Player ) )
return;
// Can't touch yourself
if ( other == this )
return;
// Make sure the body is dead
if ( !deadflag )
return;
n = inventory.NumObjects();
// No items, get out of here
if ( n == 0 )
{
return;
}
player = ( Player * )other;
// Check to see if this inventory is already being displayed for
// this body.
if ( player->GetFloatingOwner() == this )
{
// Still touching the body, so extend the clear time
player->CancelEventsOfType( EV_Player_ClearFloatingInventory );
event = new Event( EV_Player_ClearFloatingInventory );
player->PostEvent( event, 0.4f );
return;
}
else if ( player->GetFloatingOwner() )
{
// Currently looking at an inventory, so don't bother with this one.
return;
}
else
{
// Make sure the inventory is cleared out before making a new one.
// Could have some left over items in there from other bodies
player->ProcessEvent( EV_Player_ClearFloatingInventory );
}
// Create the inventory
for( i = 1; i <= n; i++ )
{
item = ( Item * )G_GetEntity( inventory.ObjectAt( i ) );
assert( item );
if ( item->Amount() )
{
player->AddItemToFloatingInventory( item );
inventory_created = true;
}
}
if (!inventory_created)
return;
// Set the current owner of the inventory
player->SetFloatingOwner( this );
// Send the inventory to the client
player->SendFloatingInventory();
// Clear the inventory in the future
event = new Event( EV_Player_ClearFloatingInventory );
player->PostEvent( event, 0.3f );
}
void Sentient::UselessCheck( Event *ev )
{
Item *item;
int n;
int i;
Event *event;
// Check to see if we have any inventory and
// remove if we don't
n = inventory.NumObjects();
for ( i = 1; i <= n; i++ )
{
item = ( Item * )G_GetEntity( inventory.ObjectAt( i ) );
assert( item );
if ( item->Amount() )
{
PostEvent ( EV_Sentient_UselessCheck, 1.0f + G_Random() );
return;
}
}
event = new Event( "remove_useless" );
ProcessEvent( event );
}
qboolean Sentient::HasInventoryOfType
(
const char *type
)
{
int num;
int i;
Item *item;
num = inventory.NumObjects();
for( i = num; i > 0; i-- )
{
item = ( Item * )G_GetEntity( inventory.ObjectAt( i ) );
if ( checkInheritance( type, item->getClassname() ) )
{
return true;
}
}
return false;
}
void Sentient::DropInventoryItems
(
void
)
{
int num;
int i;
Item *item;
// Drop any inventory items
num = inventory.NumObjects();
for( i = num; i >= 1; i-- )
{
item = ( Item * )G_GetEntity( inventory.ObjectAt( i ) );
if ( item->isSubclassOf( InventoryItem ) )
{
item->Drop();
}
}
}
qboolean Sentient::PowerupActive
(
void
)
{
if ( poweruptype && this->client )
{
gi.cprintf( edict, PRINT_HIGH, "You are already using a powerup\n" );
}
return poweruptype;
}
void Sentient::SprayBlood
(
Vector src,
Vector dir,
float damage
)
{
trace_t trace;
Vector norm;
Vector end;
Vector ang;
float dist;
float scale;
BloodSplat *splat;
dir.normalize();
end = src + dir * 2048;
trace = G_Trace( src, vec_zero, vec_zero, end, this, MASK_SOLIDNONFENCE, "Sentient::SprayBlood" );
if ( HitSky( &trace ) || ( trace.ent->solid != SOLID_BSP ) || ( trace.ent->s.number != 0 ) )
{
return;
}
dist = ( Vector( trace.endpos ) - src ).length();
scale = damage / ( dist * 0.3 );
if ( scale > 0.6 )
{
scale = 0.6;
}
if ( scale < 0.02 )
{
return;
}
norm = trace.plane.normal;
norm.x = -norm.x;
norm.y = -norm.y;
ang = norm.toAngles();
ang.z = G_Random( 360 );
end = trace.endpos + Vector( trace.plane.normal ) * 0.2;
splat = new BloodSplat( end, ang, scale );
}
EXPORT_FROM_DLL void Sentient::setModel
(
const char *mdl
)
{
if ( currentWeapon )
{
// rebind the current gun
currentWeapon->DetachFromOwner();
Entity::setModel( mdl );
currentWeapon->AttachToOwner();
}
else
{
Entity::setModel( mdl );
}
}
void Sentient::TurnOffShadow
(
Event *ev
)
{
// HACK FIXME
//
// temporary shadow flag
//
edict->s.renderfx &= ~RF_XFLIP;
}
EXPORT_FROM_DLL void Sentient::Archive
(
Archiver &arc
)
{
int i;
int num;
Entity::Archive( arc );
num = inventory.NumObjects();
arc.WriteInteger( num );
for( i = 1; i <= num; i++ )
{
arc.WriteInteger( inventory.ObjectAt( i ) );
}
arc.WriteObjectPointer( currentWeapon );
arc.WriteObjectPointer( currentItem );
arc.WriteObjectPointer( newWeapon );
arc.WriteString( currentAnim );
arc.WriteBoolean( animOverride );
arc.WriteEvent( *tempAnimEvent );
arc.WriteString( gun_bone_group_name );
arc.WriteBoolean( stopanimating_till
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -