⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 actor.cpp

📁 this keik game source
💻 CPP
📖 第 1 页 / 共 5 页
字号:
	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 + -