?? actor.cpp
字號:
vision_distance = G_GetFloatArg( "visiondistance", 1024 );
eyeoffset = "0 0 0";
eyeposition = "0 0 64";
hasalert = false;
lastEnemy = NULL;
enemyRange = RANGE_FAR;
seenEnemy = false;
nodeathfade = false;
nochatter = false;
turnspeed = 60;
if ( !parentmode->value )
{
flags |= FL_BLOOD;
flags |= FL_DIE_GIBS;
}
//
// don't talk all at once initially
//
chattime = G_Random( 20 );
nextsoundtime = 0;
trig = NULL;
deathgib = false;
// set default crouchsize
crouchsize_min = "-16 -16 0";
crouchsize_max = "16 16 32";
standsize_min = mins;
standsize_max = maxs;
// use a cvar to help with debugging
ai_actorscript = gi.cvar( "ai_actorscript", "", 0 );
actorscript = G_GetStringArg( "script", "global/enemy.scr" );
actorstart = G_GetStringArg( "thread", "" );
kill_thread = G_GetStringArg( "killthread", "" );
// default melee characteristics
melee_range = 100;
melee_damage = 30;
// default aim (normal)
aim = G_GetFloatArg( "aim", 0 );
// default pain_threshold is 10
pain_threshold = G_GetFloatArg( "painthreshold", 10 * skill->value );
// default shots per attack is 5 + ( 2 * skill->level )
shots_per_attack = G_GetFloatArg( "shotsperattack", 3 + ( 2 * skill->value ) );
startpos = worldorigin;
next_drown_time = 0;
air_finished = level.time + 5;
last_jump_time = 0;
CheckWater();
setSize( "-16 -16 0", "16 16 76" );
//setModel( G_GetSpawnArg( "model", "grunt.def" ) );
showModel();
if ( !LoadingSavegame )
{
// save off our spawn args
args.SetArgs();
G_InitSpawnArguments();
// force the init commands to be processed so that we start the right actor script immediately
CancelEventsOfType( EV_ProcessInitCommands );
ev = new Event( EV_ProcessInitCommands );
ev->AddInteger( edict->s.modelindex );
ProcessEvent( ev );
SetupThread();
if ( eyeposition.z > maxs.z )
{
eyeposition.z = maxs.z;
}
// restore our args
G_InitSpawnArguments();
args.RestoreArgs();
// wait until the script starts before thinking
PostEvent( EV_Actor_Start, FRAMETIME );
}
//
// I put this here, so that the initcommands would already be processed
//
skinname = G_GetSpawnArg( "skin" );
if ( skinname && skinname[ 0 ] )
{
int skinnum;
skinnum = gi.Skin_NumForName( edict->s.modelindex, skinname );
if (skinnum >= 0)
edict->s.skinnum = skinnum;
}
}
Actor::~Actor()
{
int n;
int i;
if ( actorthread )
{
actorthread->ProcessEvent( EV_ScriptThread_End );
actorthread = NULL;
}
// delete the old action/response list
n = actionList.NumObjects();
for( i = n; i >= 1; i-- )
{
delete actionList.ObjectAt( i );
}
actionList.ClearObjectList();
if ( behavior )
{
delete behavior;
behavior = NULL;
}
if ( path )
{
delete path;
path = NULL;
}
if ( trig )
{
delete trig;
trig = NULL;
}
ClearStateStack();
}
void Actor::Start
(
Event *ev
)
{
MonsterStart *start;
// This is only used for choosing delay times for targeting enemies
static int actornum = 0;
hasalert = ( gi.Anim_Random( edict->s.modelindex, "alert" ) != -1 );
start = MonsterStart::GetRandomSpot( spawngroup );
if ( start )
{
setOrigin( start->worldorigin );
worldorigin.copyTo( edict->s.old_origin );
setAngles( start->worldangles );
if ( start->animname != "" )
{
SetAnim( start->animname );
}
}
droptofloor( 16 );
flags |= FL_PRETHINK;
// see if we have any melee attacks
if ( HasAnim( "melee" ) )
{
has_melee = true;
}
else
{
//
// make sure we can't knock the weapon out of this characters hands
//
if ( currentWeapon )
{
Event * ev;
ev = new Event( EV_Weapon_NotDroppable );
currentWeapon->ProcessEvent( ev );
}
has_melee = false;
}
// spread their targeting about a bit
PostEvent( EV_Actor_TargetEnemies, ( actornum++ % 10 ) * FRAMETIME );
}
//***********************************************************************************************
//
// Vision functions
//
//***********************************************************************************************
range_t Actor::Range
(
Entity *targ
)
{
float r;
Vector delta;
delta = centroid - targ->centroid;
r = delta * delta;
if ( r < 120 * 120 )
{
return RANGE_MELEE;
}
if ( r < 500 * 500 )
{
return RANGE_NEAR;
}
if ( r < 1000 * 1000 )
{
return RANGE_MID;
}
return RANGE_FAR;
}
inline qboolean Actor::InFOV
(
Vector pos
)
{
Vector delta;
float dot;
delta = pos - EyePosition();
if ( !delta.x && !delta.y )
{
// special case for straight up and down
return true;
}
// give better vertical vision
delta.z = 0;
delta.normalize();
dot = DotProduct( orientation[ 0 ], delta.vec3() );
return ( dot > fovdot );
}
inline qboolean Actor::InFOV
(
Entity *ent
)
{
return InFOV( ent->centroid );
}
inline qboolean Actor::CanSeeFOV
(
Entity *ent
)
{
return InFOV( ent ) && CanSeeFrom( worldorigin, ent );
}
inline qboolean Actor::CanSeeFrom
(
Vector pos,
Entity *ent
)
{
trace_t trace;
Vector p;
p = ent->centroid;
// Check if he's visible
trace = G_Trace( pos + eyeposition, vec_zero, vec_zero, p, this, MASK_OPAQUE, "Actor::CanSeeFrom 1" );
if ( trace.fraction == 1.0 || trace.ent == ent->edict )
{
return true;
}
// Check if his head is visible
p.z = ent->absmax.z;
trace = G_Trace( pos + eyeposition, vec_zero, vec_zero, p, this, MASK_OPAQUE, "Actor::CanSeeFrom 2" );
if ( trace.fraction == 1.0 || trace.ent == ent->edict )
{
return true;
}
return false;
}
qboolean Actor::CanSee
(
Entity *ent
)
{
return CanSeeFrom( worldorigin, ent );
}
int Actor::EnemyCanSeeMeFrom
(
Vector pos
)
{
Entity *ent;
int i;
int n;
float rad;
Vector d;
Vector p1;
Vector p2;
int c;
rad = max( size.x, size.y ) * 1.44 * 0.5;
c = 0;
n = enemyList.NumObjects();
for( i = 1; i <= n; i++ )
{
ent = enemyList.ObjectAt( i );
if ( !ent || ent->deadflag || ( ent->flags & FL_NOTARGET ) )
{
continue;
}
if ( WithinDistance( ent, vision_distance ) )
{
// To check if we're visible, I create a plane that intersects the actor
// and is perpendicular to the delta vector between the actor and his enemy.
// I place four points on this plane that "frame" the actor and check if
// the enemy can see any of those points.
d = ent->centroid - pos;
d.z = 0;
d.normalize();
p1.x = -d.y;
p1.y = d.x;
p1 *= rad;
p2 = p1;
p1.z = mins.z;
p2.z = maxs.z;
if ( CanSeeFrom( pos + p1, ent ) )
{
c++;
}
if ( CanSeeFrom( pos + p2, ent ) )
{
c++;
}
p1.z = -p1.z;
p2.z = -p2.z;
if ( CanSeeFrom( pos - p1, ent ) )
{
c++;
}
if ( CanSeeFrom( pos - p2, ent ) )
{
c++;
}
}
}
return c;
}
qboolean Actor::CanSeeEnemyFrom
(
Vector pos
)
{
Entity *ent;
int i;
int n;
n = enemyList.NumObjects();
for( i = 1; i <= n; i++ )
{
ent = enemyList.ObjectAt( i );
if ( !ent || ent->deadflag || ( ent->flags & FL_NOTARGET ) )
{
continue;
}
if ( WithinDistance( ent, vision_distance ) && CanSeeFrom( pos, ent ) )
{
return true;
}
}
return false;
}
//***********************************************************************************************
//
// Weapon functions
//
//***********************************************************************************************
qboolean Actor::WeaponReady
(
void
)
{
if ( currentWeapon && currentWeapon->ReadyToFire() )
{
return true;
}
else if ( !currentWeapon && has_melee )
{
return true;
}
return false;
}
void Actor::Attack
(
Event *ev
)
{
Vector delta;
Vector ang;
Vector ang2;
if ( ( currentWeapon ) && currentWeapon->ReadyToFire() && currentWeapon->HasAmmo() )
{
if ( currentEnemy )
{
ang = angles;
delta = currentEnemy->centroid - GunPosition();
ang2 = delta.toAngles();
ang2[ 0 ] = -ang2[ 0 ];
setAngles( ang2 );
currentWeapon->Fire();
setAngles( ang );
}
else
{
currentWeapon->Fire();
}
}
}
Vector Actor::GunPosition
(
void
)
{
vec3_t trans[ 3 ];
vec3_t orient;
int groupindex;
int tri_num;
Vector offset = vec_zero;
Vector result;
// get the gun position of the actor
if ( !gi.GetBoneInfo( edict->s.modelindex, "gun", &groupindex, &tri_num, orient ) )
{
// Gun doesn't have a barrel, just return the default
return worldorigin + gunoffset;
}
gi.GetBoneTransform( edict->s.modelindex, groupindex, tri_num, orient, edict->s.anim,
edict->s.frame, edict->s.scale, trans, offset.vec3() );
MatrixTransformVector( offset.vec3(), orientation, result.vec3() );
result += worldorigin;
return result;
}
inline Vector Actor::MyGunAngles
(
Vector muzzlepos,
qboolean firing
)
{
Vector ang;
Vector dir;
if ( currentEnemy && firing )
{
dir = currentEnemy->centroid - muzzlepos;
dir.z += ( currentEnemy->absmax.z - currentEnemy->centroid.z ) * 0.75f;
dir.normalize();
ang = dir.toAngles();
ang.x = -ang.x;
}
else
{
ang.x = -worldangles.x;
ang.y = worldangles.y;
ang.z = worldangles.z;
}
return ang;
}
#define MIN_AIM_DISTANCE 400
inline void Actor::GetGunOrientation
(
Vector muzzlepos,
Vector *forward,
Vector *right,
Vector *up
)
{
Vector ang;
float accuracy;
float spread;
float invaim;
float skl;
float enemydistance;
ang = MyGunAngles( muzzlepos, true );
if ( currentEnemy )
{
enemydistance = ( currentEnemy->centroid - muzzlepos ).length();
if ( enemydistance < MIN_AIM_DISTANCE )
enemydistance = MIN_AIM_DISTANCE;
}
else
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -