📄 misc.cpp
字号:
other = ev->GetEntity( 1 );
if ( !other || ( other == world ) )
return;
num = G_FindTarget( 0, Target() );
if ( !num )
{
warning( "Teleport", "Couldn't find destination\n" );
return;
}
dest = G_GetEntity( num );
assert( dest );
other->RandomGlobalSound( "snd_teleport" );
// unlink to make sure it can't possibly interfere with KillBox
other->unlink();
if ( other->isSubclassOf( Sentient ) )
{
PathManager.Teleport( other, other->worldorigin, dest->worldorigin );
other->worldorigin = dest->worldorigin + Vector( 0, 0, 1 );
other->velocity = vec_zero;
}
else
{
mid = ( absmax - absmin ) * 0.5;
other->worldorigin = dest->worldorigin + Vector( 0, 0, 1 );
other->origin += mid;
}
// draw the teleport splash at the destination
//other->edict->s.event = EV_PLAYER_TELEPORT;
// set angles
other->setAngles( dest->angles );
// set their gravity axis
other->SetGravityAxis( gravaxis );
if ( other->client )
{
Event * ev;
client = other->client;
if ( !gravaxis )
{
// clear the velocity and hold them in place briefly
client->ps.pmove.pm_time = 100;
client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT;
ev = new Event( EV_Player_SaveFov );
other->ProcessEvent( ev );
ev = new Event( EV_Player_Fov );
ev->AddFloat( 180 );
other->ProcessEvent( ev );
}
/*
if ( gravaxis )
{
ev = new Event( EV_Player_RestoreFov );
other->PostEvent( ev, 0.1f );
}
*/
for( i = 0; i < 3; i++ )
{
client->ps.pmove.delta_angles[ i ] = ANGLE2SHORT( dest->angles[ i ] - client->resp.cmd_angles[ i ] );
}
VectorCopy( angles.vec3(), client->ps.viewangles );
}
if ( dest->isSubclassOf( TeleporterDestination ) && !gravaxis )
{
float len;
len = other->velocity.length();
//
// give them a bit of a push
//
if ( len < 400 )
len = 400;
other->velocity = ( ( TeleporterDestination * )dest )->movedir * len;
}
// kill anything at the destination
KillBox( other );
other->setOrigin( other->worldorigin );
other->worldorigin.copyTo( other->edict->s.old_origin );
}
Teleporter::Teleporter()
{
if ( !Target() )
{
gi.dprintf( "teleporter without a target.\n" );
ProcessEvent( EV_Remove );
return;
}
if ( spawnflags & 1 )
{
showModel();
}
respondto = spawnflags ^ ( TRIGGER_PLAYERS | TRIGGER_MONSTERS | TRIGGER_PROJECTILES );
}
/*****************************************************************************/
/*SINED misc_teleporter_dest (1 0 0) (-32 -32 0) (32 32 8)
Point teleporters at these.
/*****************************************************************************/
CLASS_DECLARATION( Entity, TeleporterDestination, "misc_teleporter_dest" );
ResponseDef TeleporterDestination::Responses[] =
{
{ NULL, NULL }
};
TeleporterDestination::TeleporterDestination()
{
movedir = G_GetMovedir();
setAngles( movedir.toAngles() );
}
/*****************************************************************************/
/*SINED waypoint (0 0.5 0) (-8 -8 -8) (8 8 8)
Used as a positioning device for objects
/*****************************************************************************/
CLASS_DECLARATION( Entity, Waypoint, "waypoint" );
ResponseDef Waypoint::Responses[] =
{
{ NULL, NULL }
};
/*****************************************************************************/
/*SINED func_shatter (0 .5 .8) ? x x NOT_PLAYERS NOT_MONSTERS NOT_PROJECTILES HURT_SHATTER THRESHOLD
For shattering objects. Triggers only when a threshold of damage is exceeded.
Will also trigger any targeted func_areaportals when not invisible.
"health" specifies how much damage must occur before trigger fires. Default is 20.
"percentage" specifies how much of the thing to shatter. Default is 50
"minsize" specifies minsize for tesselation, default based off size
"maxsize" specifies maxsize for tesselation, default based off size
"thickness" specifies thickness for tesselation, default same as minsize
"key" The item needed to activate this. (default nothing)
"noise" sound to play when shattered, defaults to nothing
HURT_SHATTER - when the thing gets hurt, spawn pieces of itself
THRESHOLD - damage threshold behavior
If NOT_PLAYERS is set, the trigger does not respond to damage caused by players
If NOT_MONSTERS is set, the trigger does not respond to damage caused by monsters
If NOT_PROJECTILES is set, the trigger does not respond to damage caused by projectiles
/*****************************************************************************/
CLASS_DECLARATION( Trigger, Shatter, "func_shatter" );
ResponseDef Shatter::Responses[] =
{
{ &EV_Trigger_Effect, ( Response )Shatter ::DoShatter },
{ &EV_Damage, ( Response )Shatter ::DamageEvent },
{ NULL, NULL }
};
void Shatter::DamageEvent
(
Event *ev
)
{
Event *event;
Entity *inflictor;
Entity *attacker;
int damage;
if ( takedamage == DAMAGE_NO )
{
return;
}
damage = ev->GetInteger( 1 );
inflictor = ev->GetEntity( 2 );
attacker = ev->GetEntity( 3 );
if ( threshold && damage < health )
{
return;
}
else if ( !threshold )
{
health -= damage;
if (health > 0 )
{
damage_taken += damage;
return;
}
}
damage_taken += damage;
if ( attacker )
{
event = new Event( EV_Activate );
event->AddEntity( attacker );
ProcessEvent( event );
}
else
{
warning("Damage", "Attacker is null\n" );
}
}
void Shatter::DoShatter
(
Event *ev
)
{
Entity *other;
Event *event;
Vector dir;
if ( takedamage == DAMAGE_NO )
{
return;
}
if ( noise.length() > 1 )
{
sound( noise.c_str(), 1, CHAN_VOICE + CHAN_NO_PHS_ADD );
}
other = ev->GetEntity( 1 );
takedamage = DAMAGE_NO;
dir = worldorigin - other->worldorigin;
TesselateModel
(
this,
tess_min_size,
tess_max_size,
dir,
damage_taken,
tess_percentage,
tess_thickness,
vec3_origin
);
SetAreaPortals( Target(), true );
event = new Event( EV_Trigger_ActivateTargets );
event->AddEntity( other );
ProcessEvent( event );
ProcessEvent( EV_BreakingSound );
PostEvent( EV_Remove, 0 );
}
Shatter::Shatter()
{
//
// Can only be used once
//
count = -1;
threshold = false;
// Since we're a subclass of DamageThreshold, override the invisible behaviour
showModel();
PostEvent( Event( "setup" ), 0 );
tess_percentage = G_GetFloatArg( "percentage", tess_percentage*100 ) / 100.0f;
tess_min_size = G_GetIntArg( "minsize", tess_min_size );
tess_max_size = G_GetIntArg( "maxsize", tess_max_size );
tess_thickness = G_GetIntArg( "thickness", tess_thickness );
health = G_GetFloatArg( "health", 20 );
max_health = health;
noise = str( G_GetSpawnArg( "noise", "" ) );
if ( spawnflags & (1<<5) )
flags |= FL_TESSELATE;
if ( spawnflags & (1<<6) )
threshold = true;
tess_thickness = 10;
respondto = spawnflags ^ ( TRIGGER_PLAYERS | TRIGGER_MONSTERS | TRIGGER_PROJECTILES );
}
/*****************************************************************************/
/*SINED func_glass (0 .5 .8) ? x x NOT_PLAYERS NOT_MONSTERS NOT_PROJECTILES HURT_SHATTER THRESHOLD
For glass objects. Shatters when the accumulated damage is exceeded, or when activated
"health" specifies how much damage must occur before the glass shatters. Default is 60.
"percentage" specifies how much of the thing to shatter. Default is 50
"minsize" specifies minsize for tesselation, default based off size
"maxsize" specifies maxsize for tesselation, default based off size
"thickness" specifies thickness for tesselation, default same as minsize
"key" The item needed to activate this. (default nothing)
"noise" sound to play when shattered, defaults to glass breaking
If NOT_PLAYERS is set, the trigger does not respond to events caused by players
If NOT_MONSTERS is set, the trigger does not respond to events caused by monsters
If NOT_PROJECTILES is set, the trigger does not respond to events caused by projectiles
/*****************************************************************************/
CLASS_DECLARATION( Shatter, Glass, "func_glass" );
ResponseDef Glass::Responses[] =
{
{ NULL, NULL }
};
Glass::Glass()
{
if ( !noise.length() )
{
const char * realname;
if (max_health <= 60)
{
realname = gi.GlobalAlias_FindRandom( "impact_smlglass" );
if ( realname )
noise = str( realname );
}
else
{
realname = gi.GlobalAlias_FindRandom( "impact_lrgglass" );
if ( realname )
noise = str( realname );
}
}
gi.soundindex( noise.c_str() );
}
//
// MadeBreakingSound
//
// Entity-less notifier for AI
//
void MadeBreakingSound
(
Vector pos,
Entity * activator
)
{
Entity *ent;
Event *ev;
//
// make sure activator is valid
//
if ( !activator )
activator = world;
ent = NULL;
while( ent = findradius( ent, pos.vec3(), SOUND_BREAKING_RADIUS ) )
{
if ( !ent->deadflag && ent->isSubclassOf( Sentient ) && ( ent != activator ) &&
gi.inPHS( pos.vec3(), ent->centroid.vec3() )
)
{
ev = new Event( EV_HeardBreaking );
ev->AddEntity( activator );
ev->AddVector( pos );
ent->PostEvent( ev, 0 );
}
}
}
CLASS_DECLARATION( Entity, BloodSplat, NULL );
ResponseDef BloodSplat::Responses[] =
{
{ NULL, NULL }
};
int BloodSplat::numBloodSplats = 0;
Queue BloodSplat::queueBloodSplats;
BloodSplat::BloodSplat
(
Vector pos,
Vector ang,
float scale
)
{
BloodSplat *fadesplat;
if ( numBloodSplats > sv_maxbloodsplats->value )
{
// Fade one out of the list.
fadesplat = ( BloodSplat * )queueBloodSplats.Dequeue();
fadesplat->ProcessEvent( EV_FadeOut );
numBloodSplats--;
// Don't spawn one until we others have faded
PostEvent( EV_Remove, 0 );
return;
}
setMoveType( MOVETYPE_NONE );
setSolidType( SOLID_NOT );
setModel( "sprites/bloodsplat.spr" );
edict->s.frame = G_Random( 4 );
setSize( "0 0 0", "0 0 0" );
queueBloodSplats.Enqueue( this );
numBloodSplats++;
edict->s.scale = scale * edict->s.scale;
setAngles( ang );
setOrigin( pos );
}
BloodSplat::~BloodSplat()
{
if ( queueBloodSplats.Inqueue( this ) )
{
queueBloodSplats.Remove( this );
numBloodSplats--;
}
}
/*****************************************************************************/
/*SINED func_clipbox (0 .5 .8) (-16 -16 -16) (16 16 16)
Invisible bounding box used like a clip brush. This is mainly used for blocking
off areas or improving clipping without having to recompile the map. Because of
this, it will most likely only be spawned via script.
age is exceeded, or when activated
"mins" min point of the clip.
"maxs" max point of the clip.
"type" -
0 Monster and Player clip
1 Monster clip
2 Player clip
/*****************************************************************************/
CLASS_DECLARATION( Entity, ClipBox, "func_clipbox" );
ResponseDef ClipBox::Responses[] =
{
{ NULL, NULL }
};
ClipBox::ClipBox()
{
int type;
setMoveType( MOVETYPE_NONE );
setSolidType( SOLID_BBOX );
hideModel();
type = G_GetIntArg( "type" );
edict->clipmask = MASK_SOLID;
switch( type )
{
case 1 :
edict->svflags |= SVF_MONSTERCLIP;
break;
case 2 :
edict->svflags |= SVF_PLAYERCLIP;
break;
default :
edict->svflags |= SVF_PLAYERCLIP|SVF_MONSTERCLIP;
break;
}
mins = G_GetVectorArg( "mins" );
maxs = G_GetVectorArg( "maxs" );
origin = ( mins + maxs ) * 0.5;
setSize( mins - origin, maxs - origin );
setOrigin( origin );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -