?? actor.cpp
字號(hào):
{
enemydistance = MIN_AIM_DISTANCE;
}
// 0 is maximum accuracy
invaim = 1.0f - aim;
if ( invaim < 0 )
invaim = 0;
skl = min( skill->value, 3 );
if ( skl < 1 )
skl = 1;
accuracy = 1 - ( min( skl, 3 ) * 0.18 );
accuracy *= invaim;
spread = ( 8 * MIN_AIM_DISTANCE * accuracy ) / enemydistance;
ang.x += G_CRandom( spread );
ang.y += G_CRandom( spread );
ang.AngleVectors( forward, right, up );
}
qboolean Actor::CanShootFrom
(
Vector pos,
Entity *ent,
qboolean usecurrentangles
)
{
int mask;
Vector delta;
Vector start;
Vector end;
float len;
trace_t trace;
Vehicle *v;
Entity *t;
Vector ang;
if ( !currentWeapon || !WithinDistance( ent, vision_distance ) )
{
if (!currentWeapon && !has_melee )
return false;
}
if ( usecurrentangles )
{
Vector dir;
start = pos + GunPosition() - worldorigin;
// start = pos + centroid - worldorigin;
end = ent->centroid;
end.z += ( ent->absmax.z - ent->centroid.z ) * 0.75f;
delta = end - start;
ang = delta.toAngles();
ang.x = -ang.x;
ang.y = angles.y;
len = delta.length();
ang.AngleVectors( &dir, NULL, NULL );
dir *= len;
end = start + dir;
}
else
{
start = pos + GunPosition() - worldorigin;
end = ent->centroid;
end.z += ( ent->absmax.z - ent->centroid.z ) * 0.75f;
delta = end - start;
len = delta.length();
}
// check if we're too far away, or too close
if ( currentWeapon )
{
if ( ( len > attack_range ) || ( len > currentWeapon->GetMaxRange() ) || ( len < currentWeapon->GetMinRange() ) )
{
return false;
}
mask = MASK_SHOT;
}
else
{
if ( ( len > attack_range ) || ( len > melee_range ) )
{
return false;
}
mask = MASK_PROJECTILE;
}
// shoot past the guy we're shooting at
end += delta * 4;
#if 0
if ( usecurrentangles )
{
G_DebugLine( start, end, 1, 0, 0, 1 );
}
else
{
G_DebugLine( start, end, 1, 1, 0, 1 );
}
#endif
// Check if he's visible
trace = G_Trace( start, vec_zero, vec_zero, end, this, mask, "Actor::CanShootFrom" );
if ( trace.startsolid )
{
return false;
}
// If we hit the guy we wanted, then shoot
if ( trace.ent == ent->edict )
{
return true;
}
// if we hit a vehicle, check if the driver is someone we want to hit
t = trace.ent->entity;
if ( t && t->isSubclassOf( Vehicle ) )
{
v = ( Vehicle * )t;
if ( ( v->Driver() == ent ) || IsEnemy( v->Driver() ) )
{
return true;
}
return false;
}
// If we hit someone else we don't like, then shoot
if ( IsEnemy( t ) )
{
return true;
}
// if we hit something breakable, check if shooting it will
// let us shoot someone.
if ( t->isSubclassOf( Shatter ) ||
t->isSubclassOf( Object ) ||
t->isSubclassOf( DamageThreshold ) ||
t->isSubclassOf( ScriptModel ) )
{
trace = G_Trace( Vector( trace.endpos ), vec_zero, vec_zero, end, t, mask, "Actor::CanShootFrom 2" );
if ( trace.startsolid )
{
return false;
}
// If we hit the guy we wanted, then shoot
if ( trace.ent == ent->edict )
{
return true;
}
// If we hit someone else we don't like, then shoot
if ( IsEnemy( trace.ent->entity ) )
{
return true;
}
// Forget it then
return false;
}
return false;
}
qboolean Actor::CanShoot
(
Entity *ent,
qboolean usecurrentangles
)
{
return CanShootFrom( worldorigin, ent, usecurrentangles );
}
float Actor::AttackRange
(
void
)
{
if ( !currentWeapon && !has_melee )
{
return 0;
}
if ( currentWeapon )
{
return ( currentWeapon->GetMaxRange() );
}
else
{
return ( melee_range );
}
}
float Actor::MinimumAttackRange
(
void
)
{
float range;
float maxrange;
if ( !currentWeapon && !has_melee )
{
return 100;
}
range = melee_range * 0.75f;
maxrange = melee_range;
if ( currentWeapon )
{
range = currentWeapon->GetMinRange();
if ( !range && melee_range )
range = melee_range * 0.75f;
maxrange = currentWeapon->GetMaxRange();
}
if ( range > maxrange )
range = maxrange;
return range;
}
qboolean Actor::HasWeapon
(
void
)
{
return ( currentWeapon != NULL );
}
//***********************************************************************************************
//
// Actor type script commands
//
//***********************************************************************************************
void Actor::FriendEvent
(
Event *ev
)
{
actortype = IS_FRIEND;
}
void Actor::CivilianEvent
(
Event *ev
)
{
actortype = IS_CIVILIAN;
}
void Actor::EnemyEvent
(
Event *ev
)
{
actortype = IS_ENEMY;
}
void Actor::InanimateEvent
(
Event *ev
)
{
actortype = IS_INANIMATE;
//
// clear the monster flag so triggers are not triggered
//
edict->svflags &= ~SVF_MONSTER;
//
// don't make them move
//
setMoveType( MOVETYPE_NONE );
//
// don't make it bleed
//
flags &= ~FL_BLOOD;
//
// don't make it gib
//
flags &= ~FL_DIE_GIBS;
}
void Actor::MonsterEvent
(
Event *ev
)
{
actortype = IS_MONSTER;
}
void Actor::AnimalEvent
(
Event *ev
)
{
actortype = IS_ANIMAL;
}
//***********************************************************************************************
//
// Enemy management
//
//***********************************************************************************************
qboolean Actor::HasEnemies
(
void
)
{
return ( enemyList.NumObjects() > 0 );
}
qboolean Actor::IsEnemy
(
Entity *ent
)
{
return enemyList.ObjectInList( EntityPtr( ent ) ) && seenEnemy;
}
void Actor::MakeEnemy
(
Entity *ent,
qboolean force
)
{
// don't get mad at things that can't be hurt or the world
if (
ent &&
( ent != world ) &&
( ent != this ) &&
!( ent->flags & FL_NOTARGET ) &&
( ent->takedamage != DAMAGE_NO )
)
{
if ( !enemyList.ObjectInList( EntityPtr( ent ) ) )
{
enemyList.AddObject( EntityPtr( ent ) );
}
if ( !currentEnemy && !seenEnemy )
{
currentEnemy = ent;
if ( DoAction( "sightenemy", force ) )
{
seenEnemy = true;
Chatter( "snd_sightenemy", 5 );
}
else
{
currentEnemy = NULL;
}
}
}
}
void Actor::ClearEnemies
(
void
)
{
currentEnemy = NULL;
seenEnemy = false;
enemyList.ClearObjectList();
}
qboolean Actor::Likes
(
Entity *ent
)
{
Actor *act;
if ( ent->isClient() )
{
return ( actortype == IS_FRIEND );
}
else if ( actortype == IS_MONSTER )
{
// monsters don't like anyone, but they don't particular hate everyone
return false;
}
else if ( ent->isSubclassOf( Actor ) )
{
act = ( Actor * )ent;
return ( act->actortype == actortype );
}
return false;
}
qboolean Actor::Hates
(
Entity *ent
)
{
Actor *act;
assert( ent );
if ( !ent )
{
return false;
}
if ( ent->isClient() )
{
if ( ent->flags & FL_SP_MUTANT )
{
if ( actortype == IS_ENEMY )
return false;
else
return true;
}
else
{
return ( actortype != IS_CIVILIAN ) && ( actortype != IS_FRIEND );
}
}
else if ( ent->isSubclassOf( Actor ) && ( actortype != IS_INANIMATE ) )
{
act = ( Actor * )ent;
// if ( act->actortype == IS_INANIMATE )
// {
// // heh... Mutants hate inanimate objects. :)
// return ( actortype == IS_MONSTER );
// }
if ( ( act->actortype <= IS_ENEMY ) && ( actortype <= IS_ENEMY ) )
{
return false;
}
if ( ( act->actortype == IS_FRIEND ) && ( actortype <= IS_ENEMY ) )
{
return true;
}
if ( ( act->actortype <= IS_ENEMY ) && ( actortype == IS_FRIEND ) )
{
return true;
}
}
return false;
}
//***********************************************************************************************
//
// Targeting functions
//
//***********************************************************************************************
qboolean Actor::GetVisibleTargets
(
void
)
{
Sentient *ent;
Vector delta;
int i;
int n;
targetList.ClearObjectList();
nearbyList.ClearObjectList();
n = SentientList.NumObjects();
for( i = 1; i <= n; i++ )
{
ent = SentientList.ObjectAt( i );
//if ( ( ent == this ) || ent->deadflag || ( ent->flags & FL_NOTARGET ) || !Hates( ent ) )
if ( ( ent == this ) || ( ent->flags & FL_NOTARGET ) || ent->hidden() )
{
continue;
}
if ( WithinDistance( ent, vision_distance ) && CanSeeFOV( ent ) )
{
targetList.AddObject( EntityPtr( ent ) );
if ( WithinDistance( ent, 96 ) )
{
nearbyList.AddObject( EntityPtr( ent ) );
}
}
}
return ( targetList.NumObjects() > 0 );
}
void Actor::TargetEnemies
(
Event *ev
)
{
int i;
int n;
Entity *ent;
Entity *newtarget;
Actor *act;
if ( actortype == IS_INANIMATE )
{
// inanimate objects don't need to worry about this kind of thing
return;
}
if ( enemyList.NumObjects() >= 1 )
{
// don't target new enemies as much while we've already got an enemy
PostEvent( EV_Actor_TargetEnemies, 5 );
}
else
{
PostEvent( EV_Actor_TargetEnemies, 1 );
}
if ( hidden() )
{
// don't target while hidden (for cinematic characters)
//FIXME
// probably should have a start/stop function
return;
}
if ( GetVisibleTargets() )
{
n = targetList.NumObjects();
for( i = 1; i <= n; i++ )
{
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -