Ejemplo n.º 1
0
qboolean PM_AdjustAnglesForKnockdown( gentity_t *ent, usercmd_t *ucmd, qboolean angleClampOnly )
{
	if ( PM_InKnockDown( &ent->client->ps ) )
	{//being knocked down or getting up, can't do anything!
		if ( !angleClampOnly )
		{
			ucmd->forwardmove = 0;
			ucmd->rightmove = 0;
			if ( ent->NPC )
			{
				VectorClear( ent->client->ps.moveDir );
			}
			//you can jump up out of a knockdown and you get get up into a crouch from a knockdown
			//ucmd->upmove = 0;
			//if ( !PM_InForceGetUp( &ent->client->ps ) || ent->client->ps.torsoAnimTimer > 800 || ent->s.weapon != WP_SABER )
			if ( ent->health > 0 )
			{//can only attack if you've started a force-getup and are using the saber
				ucmd->buttons = 0;
			}
		}
		if ( !PM_InForceGetUp( &ent->client->ps ) )
		{//can't turn unless in a force getup
			if ( ent->client->ps.viewEntity <= 0 || ent->client->ps.viewEntity >= ENTITYNUM_WORLD )
			{//don't clamp angles when looking through a viewEntity
				SetClientViewAngle( ent, ent->client->ps.viewangles );
			}
			ucmd->angles[PITCH] = ANGLE2SHORT( ent->client->ps.viewangles[PITCH] ) - ent->client->ps.delta_angles[PITCH];
			ucmd->angles[YAW] = ANGLE2SHORT( ent->client->ps.viewangles[YAW] ) - ent->client->ps.delta_angles[YAW];
			return qtrue;
		}
	}
	return qfalse;
}
Ejemplo n.º 2
0
//extern void G_Knockdown( gentity_t *victim );
//[/KnockdownSys]
static void Howler_TryDamage( int damage, qboolean tongue, qboolean knockdown )
{
	vec3_t	start, end, dir;
	trace_t	tr;
	float dist;

	if ( tongue )
	{
		G_GetBoltPosition( NPC, NPC->NPC->genericBolt1, start, 0 );
		G_GetBoltPosition( NPC, NPC->NPC->genericBolt2, end, 0 );
		VectorSubtract( end, start, dir );
		dist = VectorNormalize( dir );
		VectorMA( start, dist+16, dir, end );
	}
	else
	{
		VectorCopy( NPC->r.currentOrigin, start );
		AngleVectors( NPC->r.currentAngles, dir, NULL, NULL );
		VectorMA( start, MIN_DISTANCE*2, dir, end );
	}
/* RACC - don't need this for now.
#ifndef FINAL_BUILD
	if ( d_saberCombat.integer > 1 )
	{
		G_DebugLine(start, end, 1000, 0x000000ff, qtrue);
	}
#endif
*/
	// Should probably trace from the mouth, but, ah well.
	trap_Trace( &tr, start, vec3_origin, vec3_origin, end, NPC->s.number, MASK_SHOT );

	if ( tr.entityNum < ENTITYNUM_WORLD )
	{//hit *something*
		gentity_t *victim = &g_entities[tr.entityNum];
		if ( !victim->client
			|| victim->client->NPC_class != CLASS_HOWLER )
		{//not another howler

			if ( knockdown && victim->client )
			{//only do damage if victim isn't knocked down.  If he isn't, knock him down
				if ( PM_InKnockDown( &victim->client->ps ) )
				{
					return;
				}
			}
			//FIXME: some sort of damage effect (claws and tongue are cutting you... blood?)
			G_Damage( victim, NPC, NPC, dir, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, MOD_MELEE );
			if ( knockdown && victim->health > 0 )
			{//victim still alive
				//[KnockdownSys]
				G_Knockdown( victim, NPC, NPC->client->ps.velocity, 500, qfalse );
				//G_Knockdown(victim);
				//[/KnockdownSys]
			}
		}
	}
}
Ejemplo n.º 3
0
qboolean NPC_CanTryJump()
{
	if (!(NPCInfo->scriptFlags&SCF_NAV_CAN_JUMP)	||		// Can't Jump
		(NPCInfo->scriptFlags&SCF_NO_ACROBATICS)	||		// If Can't Jump At All
		(level.time<NPCInfo->jumpBackupTime)		||		// If Backing Up, Don't Try The Jump Again
		(level.time<NPCInfo->jumpNextCheckTime)		||		// Don't Even Try To Jump Again For This Amount Of Time
		(NPCInfo->jumpTime)							||		// Don't Jump If Already Going
		(PM_InKnockDown(&NPC->client->ps))			||		// Don't Jump If In Knockdown
		(BG_InRoll(&NPC->client->ps, NPC->client->ps.legsAnim))	||		// ... Or Roll
		(NPC->client->ps.groundEntityNum==ENTITYNUM_NONE)	// ... Or In The Air
		)
	{
		return qfalse;
	}
	return qtrue;
}
Ejemplo n.º 4
0
void NPC_Surrender( void )
{//FIXME: say "don't shoot!" if we weren't already surrendering
	if ( NPC->client->ps.weaponTime || PM_InKnockDown( &NPC->client->ps ) )
	{
		return;
	}
	if ( NPC->s.weapon != WP_NONE && 
		NPC->s.weapon != WP_MELEE &&
		NPC->s.weapon != WP_SABER )
	{
		WP_DropWeapon( NPC, NULL );
	}
	if ( NPCInfo->surrenderTime < level.time - 5000 )
	{//haven't surrendered for at least 6 seconds, tell them what you're doing
		//FIXME: need real dialogue EV_SURRENDER
		NPCInfo->blockedSpeechDebounceTime = 0;//make sure we say this
		G_AddVoiceEvent( NPC, Q_irand( EV_PUSHED1, EV_PUSHED3 ), 3000 );
	}
	NPC_SetAnim( NPC, SETANIM_TORSO, TORSO_SURRENDER_START, SETANIM_FLAG_HOLD|SETANIM_FLAG_OVERRIDE );
	NPC->client->ps.torsoAnimTimer = 1000;
	NPCInfo->surrenderTime = level.time + 1000;//stay surrendered for at least 1 second
	//FIXME: while surrendering, make a big sight/sound alert? Or G_AlertTeam?
}
Ejemplo n.º 5
0
qboolean NPC_CheckSurrender( void )
{
	if ( !g_AIsurrender->integer )
	{//not enabled
		return qfalse;
	}
	if ( !Q3_TaskIDPending( NPC, TID_MOVE_NAV ) 
		&& NPC->client->ps.groundEntityNum != ENTITYNUM_NONE 
		&& !NPC->client->ps.weaponTime && !PM_InKnockDown( &NPC->client->ps )
		&& NPC->enemy && NPC->enemy->client && NPC->enemy->enemy == NPC && NPC->enemy->s.weapon != WP_NONE && NPC->enemy->s.weapon != WP_MELEE 
		&& NPC->enemy->health > 20 && NPC->enemy->painDebounceTime < level.time - 3000 && NPC->enemy->client->ps.forcePowerDebounce[FP_SABER_DEFENSE] < level.time - 1000 )
	{//don't surrender if scripted to run somewhere or if we're in the air or if we're busy or if we don't have an enemy or if the enemy is not mad at me or is hurt or not a threat or busy being attacked
		//FIXME: even if not in a group, don't surrender if there are other enemies in the PVS and within a certain range?
		if ( NPC->s.weapon != WP_ROCKET_LAUNCHER 
			&& NPC->s.weapon != WP_REPEATER
			&& NPC->s.weapon != WP_FLECHETTE
			&& NPC->s.weapon != WP_SABER )
		{//jedi and heavy weapons guys never surrender
			//FIXME: rework all this logic into some orderly fashion!!!
			if ( NPC->s.weapon != WP_NONE )
			{//they have a weapon so they'd have to drop it to surrender
				//don't give up unless low on health
				if ( NPC->health > 25 || NPC->health >= NPC->max_health )
				{
					return qfalse;
				}
				if ( g_crosshairEntNum == NPC->s.number && NPC->painDebounceTime > level.time )
				{//if he just shot me, always give up
					//fall through
				}
				else
				{//don't give up unless facing enemy and he's very close
					if ( !InFOV( player, NPC, 60, 30 ) )
					{//I'm not looking at them
						return qfalse;
					}
					else if ( DistanceSquared( NPC->currentOrigin, player->currentOrigin ) < 65536/*256*256*/ )
					{//they're not close
						return qfalse;
					}
					else if ( !gi.inPVS( NPC->currentOrigin, player->currentOrigin ) )
					{//they're not in the same room
						return qfalse;
					}
				}
			}
			if ( NPCInfo->group && NPCInfo->group->numGroup <= 1 )
			{//I'm alone but I was in a group//FIXME: surrender anyway if just melee or no weap?
				if ( NPC->s.weapon == WP_NONE 
					//NPC has a weapon
					|| NPC->enemy == player
					|| (NPC->enemy->s.weapon == WP_SABER&&NPC->enemy->client&&NPC->enemy->client->ps.saberActive)
					|| (NPC->enemy->NPC && NPC->enemy->NPC->group && NPC->enemy->NPC->group->numGroup > 2) )
				{//surrender only if have no weapon or fighting a player or jedi or if we are outnumbered at least 3 to 1
					if ( NPC->enemy == player )
					{//player is the guy I'm running from
						if ( g_crosshairEntNum == NPC->s.number )
						{//give up if player is aiming at me
							NPC_Surrender();
							NPC_UpdateAngles( qtrue, qtrue );
							return qtrue;
						}
						else if ( player->s.weapon == WP_SABER )
						{//player is using saber
							if ( InFOV( NPC, player, 60, 30 ) )
							{//they're looking at me
								if ( DistanceSquared( NPC->currentOrigin, player->currentOrigin ) < 16384/*128*128*/ )
								{//they're close
									if ( gi.inPVS( NPC->currentOrigin, player->currentOrigin ) )
									{//they're in the same room
										NPC_Surrender();
										NPC_UpdateAngles( qtrue, qtrue );
										return qtrue;
									}
								}
							}
						}
					}
					else if ( NPC->enemy )
					{//???
						//should NPC's surrender to others?
						if ( InFOV( NPC, NPC->enemy, 30, 30 ) )
						{//they're looking at me
							if ( DistanceSquared( NPC->currentOrigin, NPC->enemy->currentOrigin ) < 4096 )
							{//they're close
								if ( gi.inPVS( NPC->currentOrigin, NPC->enemy->currentOrigin ) )
								{//they're in the same room
									//FIXME: should player-team NPCs not fire on surrendered NPCs?
									NPC_Surrender();
									NPC_UpdateAngles( qtrue, qtrue );
									return qtrue;
								}
							}
						}
					}
				}
			}
		}
	}
	return qfalse;
}
Ejemplo n.º 6
0
void NPC_ChoosePainAnimation( gentity_t *self, gentity_t *other, const vec3_t point, int damage, int mod, int hitLoc, int voiceEvent = -1 )
{
	//If we've already taken pain, then don't take it again
	if ( level.time < self->painDebounceTime && mod != MOD_ELECTROCUTE && mod != MOD_MELEE )
	{//FIXME: if hit while recoving from losing a saber lock, we should still play a pain anim?
		return;
	}

	int		pain_anim = -1;
	float	pain_chance;

	if ( self->s.weapon == WP_THERMAL && self->client->fireDelay > 0 )
	{//don't interrupt thermal throwing anim
		return;
	}
	else if (self->client->ps.powerups[PW_GALAK_SHIELD])
	{
		return;
	}
	else if ( self->client->NPC_class == CLASS_GALAKMECH )
	{
		if ( hitLoc == HL_GENERIC1 )
		{//hit the antenna!
			pain_chance = 1.0f;
			self->s.powerups |= ( 1 << PW_SHOCKED );
			self->client->ps.powerups[PW_SHOCKED] = level.time + Q_irand( 500, 2500 );
		}
		else if ( self->client->ps.powerups[PW_GALAK_SHIELD] )
		{//shield up
			return;
		}
		else if ( self->health > 200 && damage < 100 )
		{//have a *lot* of health
			pain_chance = 0.05f;
		}
		else
		{//the lower my health and greater the damage, the more likely I am to play a pain anim
			pain_chance = (200.0f-self->health)/100.0f + damage/50.0f;
		}
	}
	else if ( self->client && self->client->playerTeam == TEAM_PLAYER && other && !other->s.number )
	{//ally shot by player always complains
		pain_chance = 1.1f;
	}
	else
	{
		if ( other && (other->s.weapon == WP_SABER || mod == MOD_ELECTROCUTE || mod == MOD_CRUSH/*FIXME:MOD_FORCE_GRIP*/) )
		{
			if ( self->client->ps.weapon == WP_SABER
				&& other->s.number < MAX_CLIENTS )
			{//hmm, shouldn't *always* react to damage from player if I have a saber
				pain_chance = 1.05f - ((self->NPC->rank)/(float)RANK_CAPTAIN);
			}
			else
			{
				pain_chance = 1.0f;//always take pain from saber
			}
		}
		else if ( mod == MOD_GAS )
		{
			pain_chance = 1.0f;
		}
		else if ( mod == MOD_MELEE )
		{//higher in rank (skill) we are, less likely we are to be fazed by a punch
			pain_chance = 1.0f - ((RANK_CAPTAIN-self->NPC->rank)/(float)RANK_CAPTAIN);
		}
		else if ( self->client->NPC_class == CLASS_PROTOCOL )
		{
			pain_chance = 1.0f;
		}
		else
		{
			pain_chance = NPC_GetPainChance( self, damage );
		}
		if ( self->client->NPC_class == CLASS_DESANN )
		{
			pain_chance *= 0.5f;
		}
	}

	//See if we're going to flinch
	if ( Q_flrand(0.0f, 1.0f) < pain_chance )
	{
		//Pick and play our animation
		if ( (self->client->ps.eFlags&EF_FORCE_GRIPPED) )
		{
			G_AddVoiceEvent( self, Q_irand(EV_CHOKE1, EV_CHOKE3), 0 );
		}
		else if ( mod == MOD_GAS )
		{
			//SIGH... because our choke sounds are inappropriately long, I have to debounce them in code!
			if ( TIMER_Done( self, "gasChokeSound" ) )
			{
				TIMER_Set( self, "gasChokeSound", Q_irand( 1000, 2000 ) );
				G_AddVoiceEvent( self, Q_irand(EV_CHOKE1, EV_CHOKE3), 0 );
			}
		}
		else if ( (self->client->ps.eFlags&EF_FORCE_DRAINED) )
		{
			NPC_SetPainEvent( self );
		}
		else
		{//not being force-gripped or force-drained
			if ( G_CheckForStrongAttackMomentum( self )
				|| PM_SpinningAnim( self->client->ps.legsAnim )
				|| PM_SaberInSpecialAttack( self->client->ps.torsoAnim )
				|| PM_InKnockDown( &self->client->ps )
				|| PM_RollingAnim( self->client->ps.legsAnim )
				|| (PM_FlippingAnim( self->client->ps.legsAnim )&&!PM_InCartwheel( self->client->ps.legsAnim )) )
			{//strong attacks, rolls, knockdowns, flips and spins cannot be interrupted by pain
				return;
			}
			else
			{//play an anim
				if ( self->client->NPC_class == CLASS_GALAKMECH )
				{//only has 1 for now
					//FIXME: never plays this, it seems...
					pain_anim = BOTH_PAIN1;
				}
				else if ( mod == MOD_MELEE )
				{
					pain_anim = PM_PickAnim( self, BOTH_PAIN2, BOTH_PAIN3 );
				}
				else if ( self->s.weapon == WP_SABER )
				{//temp HACK: these are the only 2 pain anims that look good when holding a saber
					pain_anim = PM_PickAnim( self, BOTH_PAIN2, BOTH_PAIN3 );
				}
				else if ( mod != MOD_ELECTROCUTE )
				{
					pain_anim = G_PickPainAnim( self, point, damage, hitLoc );
				}

				if ( pain_anim == -1 )
				{
					pain_anim = PM_PickAnim( self, BOTH_PAIN1, BOTH_PAIN18 );
				}
				self->client->ps.saberAnimLevel = SS_FAST;//next attack must be a quick attack
				self->client->ps.saberMove = LS_READY;//don't finish whatever saber move you may have been in
				int parts = SETANIM_BOTH;
				if ( PM_CrouchAnim( self->client->ps.legsAnim ) || PM_InCartwheel( self->client->ps.legsAnim ) )
				{
					parts = SETANIM_LEGS;
				}
				self->NPC->aiFlags &= ~NPCAI_KNEEL;
				NPC_SetAnim( self, parts, pain_anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
			}
			if ( voiceEvent != -1 )
			{
				G_AddVoiceEvent( self, voiceEvent, Q_irand( 2000, 4000 ) );
			}
			else
			{
				NPC_SetPainEvent( self );
			}
		}

		//Setup the timing for it
		if ( mod == MOD_ELECTROCUTE )
		{
			self->painDebounceTime = level.time + 4000;
		}
		self->painDebounceTime = level.time + PM_AnimLength( self->client->clientInfo.animFileIndex, (animNumber_t) pain_anim );
		self->client->fireDelay = 0;
	}
}
Ejemplo n.º 7
0
void NPC_ChoosePainAnimation( gentity_t *self, gentity_t *other, vec3_t point, int damage, int mod, int hitLoc, int voiceEvent )
{
    int		pain_anim = -1;
    float	pain_chance;

    //If we've already taken pain, then don't take it again
    if ( level.time < self->painDebounceTime && /*mod != MOD_ELECTROCUTE &&*/ mod != MOD_MELEE ) //rwwFIXMEFIXME: MOD_ELECTROCUTE
    {   //FIXME: if hit while recoving from losing a saber lock, we should still play a pain anim?
        return;
    }

    if ( self->s.weapon == WP_THERMAL && self->client->ps.weaponTime > 0 )
    {   //don't interrupt thermal throwing anim
        return;
    }
    else if ( self->client->NPC_class == CLASS_GALAKMECH )
    {
        if ( hitLoc == HL_GENERIC1 )
        {   //hit the antenna!
            pain_chance = 1.0f;
            //	self->s.powerups |= ( 1 << PW_SHOCKED );
            //	self->client->ps.powerups[PW_SHOCKED] = level.time + Q_irand( 500, 2500 );
            //rwwFIXMEFIXME: support for this
        }
        //	else if ( self->client->ps.powerups[PW_GALAK_SHIELD] )
        //	{//shield up
        //		return;
        //	}
        //rwwFIXMEFIXME: and this
        else if ( self->health > 200 && damage < 100 )
        {   //have a *lot* of health
            pain_chance = 0.05f;
        }
        else
        {   //the lower my health and greater the damage, the more likely I am to play a pain anim
            pain_chance = (200.0f-self->health)/100.0f + damage/50.0f;
        }
    }
    else if ( self->client && self->client->playerTeam == NPCTEAM_PLAYER && other && !other->s.number )
    {   //ally shot by player always complains
        pain_chance = 1.1f;
    }
    else
    {
        if ( other && other->s.weapon == WP_SABER || /*mod == MOD_ELECTROCUTE ||*/ mod == MOD_CRUSH/*FIXME:MOD_FORCE_GRIP*/ )
        {
            pain_chance = 1.0f;//always take pain from saber
        }
        else if ( mod == MOD_MELEE )
        {   //higher in rank (skill) we are, less likely we are to be fazed by a punch
            pain_chance = 1.0f - ((RANK_CAPTAIN-self->NPC->rank)/(float)RANK_CAPTAIN);
        }
        else if ( self->client->NPC_class == CLASS_PROTOCOL )
        {
            pain_chance = 1.0f;
        }
        else
        {
            pain_chance = NPC_GetPainChance( self, damage );
        }
        if ( self->client->NPC_class == CLASS_DESANN )
        {
            pain_chance *= 0.5f;
        }
    }

    //See if we're going to flinch
    if ( random() < pain_chance )
    {
        int animLength;

        //Pick and play our animation
        if ( self->client->ps.fd.forceGripBeingGripped < level.time )
        {   //not being force-gripped or force-drained
            if ( /*G_CheckForStrongAttackMomentum( self ) //rwwFIXMEFIXME: Is this needed?
				||*/ PM_SpinningAnim( self->client->ps.legsAnim )
                || BG_SaberInSpecialAttack( self->client->ps.torsoAnim )
                || PM_InKnockDown( &self->client->ps )
                || PM_RollingAnim( self->client->ps.legsAnim )
                || (BG_FlippingAnim( self->client->ps.legsAnim )&&!PM_InCartwheel( self->client->ps.legsAnim )) )
            {   //strong attacks, rolls, knockdowns, flips and spins cannot be interrupted by pain
            }
            else
            {   //play an anim
                int parts;

                if ( self->client->NPC_class == CLASS_GALAKMECH )
                {   //only has 1 for now
                    //FIXME: never plays this, it seems...
                    pain_anim = BOTH_PAIN1;
                }
                else if ( mod == MOD_MELEE )
                {
                    pain_anim = BG_PickAnim( self->localAnimIndex, BOTH_PAIN2, BOTH_PAIN3 );
                }
                else if ( self->s.weapon == WP_SABER )
                {   //temp HACK: these are the only 2 pain anims that look good when holding a saber
                    pain_anim = BG_PickAnim( self->localAnimIndex, BOTH_PAIN2, BOTH_PAIN3 );
                }
                /*
                else if ( mod != MOD_ELECTROCUTE )
                {
                	pain_anim = G_PickPainAnim( self, point, damage, hitLoc );
                }
                */

                if ( pain_anim == -1 )
                {
                    pain_anim = BG_PickAnim( self->localAnimIndex, BOTH_PAIN1, BOTH_PAIN18 );
                }
                self->client->ps.fd.saberAnimLevel = FORCE_LEVEL_1;//next attack must be a quick attack
                self->client->ps.saberMove = LS_READY;//don't finish whatever saber move you may have been in
                parts = SETANIM_BOTH;
                if ( BG_CrouchAnim( self->client->ps.legsAnim ) || PM_InCartwheel( self->client->ps.legsAnim ) )
                {
                    parts = SETANIM_LEGS;
                }

                if (pain_anim != -1)
                {
                    NPC_SetAnim( self, parts, pain_anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
                }
            }
            if ( voiceEvent != -1 )
            {
                G_AddVoiceEvent( self, voiceEvent, Q_irand( 2000, 4000 ) );
            }
            else
            {
                NPC_SetPainEvent( self );
            }
        }
        else
        {
            G_AddVoiceEvent( self, Q_irand(EV_CHOKE1, EV_CHOKE3), 0 );
        }

        //Setup the timing for it
        /*
        if ( mod == MOD_ELECTROCUTE )
        {
        	self->painDebounceTime = level.time + 4000;
        }
        */
        animLength = bgAllAnims[self->localAnimIndex].anims[pain_anim].numFrames * fabs((float)(bgHumanoidAnimations[pain_anim].frameLerp));

        self->painDebounceTime = level.time + animLength;
        self->client->ps.weaponTime = 0;
    }
}
Ejemplo n.º 8
0
qboolean NPC_MoveToGoal( qboolean tryStraight ) 
{
	float	distance;
	vec3_t	dir;

#if	AI_TIMERS
	int	startTime = GetTime(0);
#endif//	AI_TIMERS
	//If taking full body pain, don't move
	if ( PM_InKnockDown( &NPC->client->ps ) || ( ( NPC->s.legsAnim >= BOTH_PAIN1 ) && ( NPC->s.legsAnim <= BOTH_PAIN18 ) ) )
	{
		return qtrue;
	}

	/*
	if( NPC->s.eFlags & EF_LOCKED_TO_WEAPON )
	{//If in an emplaced gun, never try to navigate!
		return qtrue;
	}
	*/
	//rwwFIXMEFIXME: emplaced support

	//FIXME: if can't get to goal & goal is a target (enemy), try to find a waypoint that has line of sight to target, at least?
	//Get our movement direction
#if 1
	if ( NPC_GetMoveDirectionAltRoute( dir, &distance, tryStraight ) == qfalse )
#else
	if ( NPC_GetMoveDirection( dir, &distance ) == qfalse )
#endif
		return qfalse;

	NPCInfo->distToGoal		= distance;

	//Convert the move to angles
	vectoangles( dir, NPCInfo->lastPathAngles );
	if ( (ucmd.buttons&BUTTON_WALKING) )
	{
		NPC->client->ps.speed = NPCInfo->stats.walkSpeed;
	}
	else
	{
		NPC->client->ps.speed = NPCInfo->stats.runSpeed;
	}

	//FIXME: still getting ping-ponging in certain cases... !!!  Nav/avoidance error?  WTF???!!!
	//If in combat move, then move directly towards our goal
	if ( NPC_CheckCombatMove() )
	{//keep current facing
		G_UcmdMoveForDir( NPC, &ucmd, dir );
	}
	else
	{//face our goal
		//FIXME: strafe instead of turn if change in dir is small and temporary
		NPCInfo->desiredPitch	= 0.0f;
		NPCInfo->desiredYaw		= AngleNormalize360( NPCInfo->lastPathAngles[YAW] );
		
		//Pitch towards the goal and also update if flying or swimming
		if ( (NPC->client->ps.eFlags2&EF2_FLYING) )//moveType == MT_FLYSWIM )
		{
			NPCInfo->desiredPitch = AngleNormalize360( NPCInfo->lastPathAngles[PITCH] );
			
			if ( dir[2] )
			{
				float scale = (dir[2] * distance);
				if ( scale > 64 )
				{
					scale = 64;
				}
				else if ( scale < -64 )
				{
					scale = -64;
				}
				NPC->client->ps.velocity[2] = scale;
				//NPC->client->ps.velocity[2] = (dir[2] > 0) ? 64 : -64;
			}
		}

		//Set any final info
		ucmd.forwardmove = 127;
	}

#if	AI_TIMERS
	navTime += GetTime( startTime );
#endif//	AI_TIMERS
	return qtrue;
}
Ejemplo n.º 9
0
qboolean NPC_MoveToGoal( qboolean tryStraight ) 
{
	float	distance;
	vec3_t	dir;

#if	AI_TIMERS
	int	startTime = GetTime(0);
#endif//	AI_TIMERS
	//If taking full body pain, don't move
	if ( PM_InKnockDown( &NPC->client->ps ) || ( ( NPC->s.legsAnim >= BOTH_PAIN1 ) && ( NPC->s.legsAnim <= BOTH_PAIN18 ) ) )
	{
		return qfalse;
	}

#ifdef __DOMINANCE_NPC__
	if (NPC->enemy 
		&& NPC->s.weapon == WP_SABER
		&& (!NPC_EnemyVisible( NPC, NPC->enemy ) || (Distance(NPC->r.currentOrigin, NPC->enemy->r.currentOrigin) > 96 || NPC->genericValue15 < level.time)))
	{
		// Enemy is visible, but out of range for lghtsaber... Move closer...
		NPC->client->ps.speed = NPCInfo->stats.runSpeed;

		if (!NPC_FollowRoutes())
		{
			//G_Printf("NPC_FollowRoutes failed!\n");
			return qfalse;
		}

		return qtrue;
	}
	else if (NPC->enemy 
		&& NPC_EnemyVisible( NPC, NPC->enemy ))
	{
		// Enemy is visible and in range, no need to move at the moment...
		return qfalse;
	}
	else if (NPC->enemy)
	{// Have an enemy that is not currently visible...
		if (NPC->s.weapon == WP_SABER
			&& (Distance(NPC->r.currentOrigin, NPC->enemy->r.currentOrigin) > 96 || NPC->genericValue15 < level.time))
		{
			if (NPC->genericValue14 < level.time)
			{
				// Give up...
				NPC->enemy = NULL;
				NPCInfo->goalEntity = NULL;
				NPC->longTermGoal = -1;
			}
		}
		else if (NPC->enemy 
			&& NPC->genericValue15 < level.time)
		{
			if (NPC->genericValue14 < level.time)
			{
				// Give up...
				NPC->enemy = NULL;
				NPCInfo->goalEntity = NULL;
				NPC->longTermGoal = -1;
			}
		}

		NPC->client->ps.speed = NPCInfo->stats.runSpeed;

		if (!NPC_FollowRoutes())
		{
			//G_Printf("NPC_FollowRoutes failed!\n");
			return qfalse;
		}

		return qtrue;
	}
	else
	{// Dominance: Use bot waypointing AI if it is available! - Unique1
		NPC->enemy = NULL;
		NPCInfo->goalEntity = NULL;

		NPC->client->ps.speed = NPCInfo->stats.walkSpeed;

		if (!NPC_FollowRoutes())
		{
			//G_Printf("NPC_FollowRoutes failed!\n");
			return qfalse;
		}

		return qtrue;
	}
#endif //__DOMINANCE_NPC__

	/*
	if( NPC->s.eFlags & EF_LOCKED_TO_WEAPON )
	{//If in an emplaced gun, never try to navigate!
		return qtrue;
	}
	*/
	//rwwFIXMEFIXME: emplaced support

	//FIXME: if can't get to goal & goal is a target (enemy), try to find a waypoint that has line of sight to target, at least?
	//Get our movement direction
#if 1
	if ( NPC_GetMoveDirectionAltRoute( dir, &distance, tryStraight ) == qfalse )
#else
	if ( NPC_GetMoveDirection( dir, &distance ) == qfalse )
#endif
		return qfalse;

	NPCInfo->distToGoal		= distance;

	//Convert the move to angles
	vectoangles( dir, NPCInfo->lastPathAngles );
	if ( (ucmd.buttons&BUTTON_WALKING) )
	{
		NPC->client->ps.speed = NPCInfo->stats.walkSpeed;
	}
	else
	{
		NPC->client->ps.speed = NPCInfo->stats.runSpeed;
	}

	//FIXME: still getting ping-ponging in certain cases... !!!  Nav/avoidance error?  WTF???!!!
	//If in combat move, then move directly towards our goal
	if ( NPC_CheckCombatMove() )
	{//keep current facing
		G_UcmdMoveForDir( NPC, &ucmd, dir );
	}
	else
	{//face our goal
		//FIXME: strafe instead of turn if change in dir is small and temporary
		NPCInfo->desiredPitch	= 0.0f;
		NPCInfo->desiredYaw		= AngleNormalize360( NPCInfo->lastPathAngles[YAW] );
		
		//Pitch towards the goal and also update if flying or swimming
		if ( (NPC->client->ps.eFlags2&EF2_FLYING) )//moveType == MT_FLYSWIM )
		{
			NPCInfo->desiredPitch = AngleNormalize360( NPCInfo->lastPathAngles[PITCH] );
			
			if ( dir[2] )
			{
				float scale = (dir[2] * distance);
				if ( scale > 64 )
				{
					scale = 64;
				}
				else if ( scale < -64 )
				{
					scale = -64;
				}
				NPC->client->ps.velocity[2] = scale;
				//NPC->client->ps.velocity[2] = (dir[2] > 0) ? 64 : -64;
			}
		}

		//Set any final info
		ucmd.forwardmove = 127;
	}

#if	AI_TIMERS
	navTime += GetTime( startTime );
#endif//	AI_TIMERS
	return qtrue;
}
Ejemplo n.º 10
0
qboolean NPC_MoveToGoal( qboolean tryStraight ) 
{
	qboolean ENEMY_VISIBLE = qfalse;

	if ( PM_InKnockDown( &NPC->client->ps ) || ( ( NPC->s.legsAnim >= BOTH_PAIN1 ) && ( NPC->s.legsAnim <= BOTH_PAIN18 ) ) )
	{// If taking full body pain, don't move...
		return qfalse;
	}

	if (!NPC->enemy)
	{
		NPCInfo->goalEntity = NPC->enemy = NPC_PickEnemyExt( qtrue );
	}

	if (NPC->enemy)
		ENEMY_VISIBLE = NPC_EnemyVisible( NPC, NPC->enemy );

	if (NPC->enemy 
		&& ENEMY_VISIBLE
		&& NPC->s.weapon == WP_SABER
		&& Distance(NPC->r.currentOrigin, NPC->enemy->r.currentOrigin) > 96)
	{// Enemy is visible, but out of range for lghtsaber... Move closer
		NPC->client->ps.speed = NPCInfo->stats.walkSpeed;
	}
	else if (NPC->enemy && !ENEMY_VISIBLE)
	{// Have an enemy that is not currently visible...
		if (NPC->genericValue14 < level.time)
		{// Give up...
			NPC->enemy = NULL;
			NPCInfo->goalEntity = NULL;
			NPC->longTermGoal = -1;
		}

		NPC->client->ps.speed = NPCInfo->stats.walkSpeed;
	}
	else if (NPC->enemy && ENEMY_VISIBLE)
	{// Enemy is visible and in range, no need to move at the moment...
		NPC->client->ps.speed = NPCInfo->stats.walkSpeed;
		return qfalse;
	}
	else
	{// No enemy at all, continue to follow routes...
		if (NPC->genericValue14 < level.time)
		{// Give up...
			NPC->enemy = NULL;
			NPCInfo->goalEntity = NULL;
			NPC->longTermGoal = -1;
		}

		NPC->client->ps.speed = NPCInfo->stats.walkSpeed;
	}

	// Do the actual routing and movement...
	if (!NPC_FollowRoutes())
	{
		//G_Printf("NPC_FollowRoutes failed!\n");
		return qfalse;
	}

#if	AI_TIMERS
	navTime += GetTime( startTime );
#endif//	AI_TIMERS

	return qtrue;
}
Ejemplo n.º 11
0
//----------------------------------
//replaced with SP version.
static void Howler_Combat( void )
{
	qboolean	faced = qfalse;
	float		distance;	
	qboolean	advance = qfalse;
	if ( NPC->client->ps.groundEntityNum == ENTITYNUM_NONE )
	{//not on the ground
		if ( NPC->client->ps.legsAnim == BOTH_JUMP1
			|| NPC->client->ps.legsAnim == BOTH_INAIR1 )
		{//flying through the air with the greatest of ease, etc
			Howler_TryDamage( 10, qfalse, qfalse );
		}
	}
	else
	{//not in air, see if we should attack or advance
		// If we cannot see our target or we have somewhere to go, then do that
		if ( !NPC_ClearLOS4( NPC->enemy ) )//|| UpdateGoal( ))
		{
			NPCInfo->goalEntity = NPC->enemy;
			NPCInfo->goalRadius = MAX_DISTANCE;	// just get us within combat range

			if ( NPCInfo->localState == LSTATE_BERZERK )
			{
				NPC_Howler_Move( 3 );
			}
			else
			{
				NPC_Howler_Move( 10 );
			}
			NPC_UpdateAngles( qfalse, qtrue );
			return;
		}

		distance = DistanceHorizontal( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin );	

		if ( NPC->enemy && NPC->enemy->client && PM_InKnockDown( &NPC->enemy->client->ps ) )
		{//get really close to knocked down enemies
			advance = (qboolean)( distance > MIN_DISTANCE ? qtrue : qfalse  );
		}
		else
		{
			advance = (qboolean)( distance > MAX_DISTANCE ? qtrue : qfalse  );//MIN_DISTANCE
		}

		if (( advance || NPCInfo->localState == LSTATE_WAITING ) && TIMER_Done( NPC, "attacking" )) // waiting monsters can't attack
		{
			if ( TIMER_Done2( NPC, "takingPain", qtrue ))
			{
				NPCInfo->localState = LSTATE_CLEAR;
			}
			else if ( TIMER_Done( NPC, "standing" ) )
			{
				faced = Howler_Move( qtrue );
			}
		}
		else
		{
			Howler_Attack( distance, qfalse );
		}
	}

	if ( !faced )
	{
		if ( //TIMER_Done( NPC, "standing" ) //not just standing there
			//!advance //not moving
			TIMER_Done( NPC, "attacking" ) )// not attacking
		{//not standing around
			// Sometimes I have problems with facing the enemy I'm attacking, so force the issue so I don't look dumb
			NPC_FaceEnemy( qtrue );
		}
		else
		{
			NPC_UpdateAngles( qfalse, qtrue );
		}
	}
}
Ejemplo n.º 12
0
static void Howler_Attack( float enemyDist, qboolean howl )
{
	int dmg = (NPCInfo->localState==LSTATE_BERZERK)?5:2;

	vec3_t boltOrg;
	vec3_t fwd;

	if ( !TIMER_Exists( NPC, "attacking" ))
	{
		int attackAnim = BOTH_GESTURE1;
		// Going to do an attack
		if ( NPC->enemy && NPC->enemy->client && PM_InKnockDown( &NPC->enemy->client->ps )
			&& enemyDist <= MIN_DISTANCE )
		{
			attackAnim = BOTH_ATTACK2;
		}
		else if ( !Q_irand( 0, 4 ) || howl )
		{//howl attack
			//G_SoundOnEnt( NPC, CHAN_VOICE, "sound/chars/howler/howl.mp3" );
		}
		else if ( enemyDist > MIN_DISTANCE && Q_irand( 0, 1 ) )
		{//lunge attack
			//jump foward
			vec3_t	fwd, yawAng;
			
			VectorSet( yawAng, 0, NPC->client->ps.viewangles[YAW], 0 );
			AngleVectors( yawAng, fwd, NULL, NULL );
			VectorScale( fwd, (enemyDist*3.0f), NPC->client->ps.velocity );
			NPC->client->ps.velocity[2] = 200;
			NPC->client->ps.groundEntityNum = ENTITYNUM_NONE;
			
			attackAnim = BOTH_ATTACK1;
		}
		else
		{//tongue attack
			attackAnim = BOTH_ATTACK2;
		}

		NPC_SetAnim( NPC, SETANIM_BOTH, attackAnim, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD | SETANIM_FLAG_RESTART );
		if ( NPCInfo->localState == LSTATE_BERZERK )
		{//attack again right away
			TIMER_Set( NPC, "attacking", NPC->client->ps.legsTimer );
		}
		else
		{
			TIMER_Set( NPC, "attacking", NPC->client->ps.legsTimer + Q_irand( 0, 1500 ) );//FIXME: base on skill
			TIMER_Set( NPC, "standing", -level.time );
			TIMER_Set( NPC, "walking", -level.time );
			TIMER_Set( NPC, "running", NPC->client->ps.legsTimer + 5000 );
		}

		TIMER_Set( NPC, "attack_dmg", 200 ); // level two damage
	}

	// Need to do delayed damage since the attack animations encapsulate multiple mini-attacks
	switch ( NPC->client->ps.legsAnim )
	{
	case BOTH_ATTACK1:
	case BOTH_MELEE1:
		if ( NPC->client->ps.legsTimer > 650//more than 13 frames left
			&& BG_AnimLength( NPC->localAnimIndex, (animNumber_t)NPC->client->ps.legsAnim ) - NPC->client->ps.legsTimer >= 800 )//at least 16 frames into anim
		{
			Howler_TryDamage( dmg, qfalse, qfalse );
		}
		break;
	case BOTH_ATTACK2:
	case BOTH_MELEE2:
		if ( NPC->client->ps.legsTimer > 350//more than 7 frames left
			&& BG_AnimLength( NPC->localAnimIndex, (animNumber_t)NPC->client->ps.legsAnim ) - NPC->client->ps.legsTimer >= 550 )//at least 11 frames into anim
		{
			Howler_TryDamage( dmg, qtrue, qfalse );
		}
		break;
	case BOTH_GESTURE1:
		{
			if ( NPC->client->ps.legsTimer > 1800//more than 36 frames left
				&& BG_AnimLength( NPC->localAnimIndex, (animNumber_t)NPC->client->ps.legsAnim ) - NPC->client->ps.legsTimer >= 950 )//at least 19 frames into anim
			{
				Howler_Howl();
				if ( !NPC->count )
				{
					//RAFIXME - this probably won't work correctly.
					G_GetBoltPosition(NPC, NPC->NPC->genericBolt1, boltOrg, 0);
					AngleVectors( NPC->client->ps.viewangles, fwd, NULL, NULL );
					G_PlayEffectID( G_EffectIndex( "howler/sonic" ), boltOrg, fwd);
					//G_PlayEffect( G_EffectIndex( "howler/sonic" ), NPC->ghoul2, NPC->NPC->genericBolt1, NPC->s.number, NPC->currentOrigin, 4750, qtrue );
					G_SoundOnEnt( NPC, CHAN_VOICE, "sound/chars/howler/howl.mp3" );
					NPC->count = 1;
				}
			}
		}
		break;
	default:
		//anims seem to get reset after a load, so just stop attacking and it will restart as needed.
		TIMER_Remove( NPC, "attacking" );
		break;
	}

	// Just using this to remove the attacking flag at the right time
	TIMER_Done2( NPC, "attacking", qtrue );
}
Ejemplo n.º 13
0
static void Howler_Howl( void )
{
	//gentity_t	*radiusEnts[ 128 ];
	int			radiusEntsNums[128];
	gentity_t	*ent;
	int			numEnts;
	const float	radius = (NPC->spawnflags&1)?256:128;
	const float	halfRadSquared = ((radius/2)*(radius/2));
	const float	radiusSquared = (radius*radius);
	float		distSq;
	int			i;
	vec3_t		boltOrg;

	AddSoundEvent( NPC, NPC->r.currentOrigin, 512, AEL_DANGER, qfalse, qtrue );

	//RACC - handLBolt never defined for Howlers? *shrug* just use the tongue base
	numEnts = NPC_GetEntsNearBolt( radiusEntsNums, radius, NPC->NPC->genericBolt1, boltOrg );
	//numEnts = NPC_GetEntsNearBolt( radiusEnts, radius, NPC->handLBolt, boltOrg );

	for ( i = 0; i < numEnts; i++ )
	{
		ent = &g_entities[radiusEntsNums[i]];

		if ( !ent->inuse )
		{
			continue;
		}
		
		if ( ent == NPC )
		{//Skip the rancor ent
			//RACC - assume this means the source howler
			continue;
		}
		
		if ( ent->client == NULL )
		{//must be a client
			continue;
		}

		if ( ent->client->NPC_class == CLASS_HOWLER )
		{//other howlers immune
			continue;
		}

		distSq = DistanceSquared( ent->r.currentOrigin, boltOrg );
		if ( distSq <= radiusSquared )
		{
			if ( distSq < halfRadSquared )
			{//close enough to do damage, too
				if ( Q_irand( 0, g_spskill.integer ) )
				{//does no damage on easy, does 1 point every other frame on medium, more often on hard
					//RACC - Impact isn't a MOD in MP.
					G_Damage( ent, NPC, NPC, vec3_origin, NPC->r.currentOrigin, 1, DAMAGE_NO_KNOCKBACK, MOD_CRUSH );
					//G_Damage( ent, NPC, NPC, vec3_origin, NPC->r.currentOrigin, 1, DAMAGE_NO_KNOCKBACK, MOD_IMPACT );
				}
			}
			if ( ent->health > 0 
				&& ent->client
				&& ent->client->NPC_class != CLASS_RANCOR
				&& ent->client->NPC_class != CLASS_ATST 
				&& !PM_InKnockDown( &ent->client->ps ) )
			{
				if ( BG_HasAnimation( ent->localAnimIndex, BOTH_SONICPAIN_START ) )
				{
					if ( ent->client->ps.torsoAnim != BOTH_SONICPAIN_START 
						&& ent->client->ps.torsoAnim != BOTH_SONICPAIN_HOLD )
					{
						NPC_SetAnim( ent, SETANIM_LEGS, BOTH_SONICPAIN_START, SETANIM_FLAG_NORMAL );
						NPC_SetAnim( ent, SETANIM_TORSO, BOTH_SONICPAIN_START, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
						ent->client->ps.torsoTimer += 100;
						ent->client->ps.weaponTime = ent->client->ps.torsoTimer;
					}
					else if ( ent->client->ps.torsoTimer <= 100 )
					{//at the end of the sonic pain start or hold anim
						NPC_SetAnim( ent, SETANIM_LEGS, BOTH_SONICPAIN_HOLD, SETANIM_FLAG_NORMAL );
						NPC_SetAnim( ent, SETANIM_TORSO, BOTH_SONICPAIN_HOLD, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
						ent->client->ps.torsoTimer += 100; 
						ent->client->ps.weaponTime = ent->client->ps.torsoTimer;
					}
				}
				/*  racc - commented out of SP code?
				else if ( distSq < halfRadSquared 
					&& radiusEnts[i]->client->ps.groundEntityNum != ENTITYNUM_NONE 
					&& !Q_irand( 0, 10 ) )//FIXME: base on skill
				{//within range
					G_Knockdown( radiusEnts[i], NPC, vec3_origin, 500, qfalse );
				}
				*/
			}
		}

		//camera shaking
		distSq = Distance( boltOrg, ent->r.currentOrigin );
		if ( distSq < 256.0f )
		{
			G_ScreenShake(boltOrg, ent, 1.0f*distSq/128.0f, 200, qfalse);
		}
	}

	//RACC - changed to work for multiple players
	/*
	playerDist = NPC_EntRangeFromBolt( player, NPC->genericBolt1 );
	if ( playerDist < 256.0f )
	{
		CGCam_Shake( 1.0f*playerDist/128.0f, 200 );
	}
	*/
}
Ejemplo n.º 14
0
static void Howler_Howl( void )
{
	gentity_t	*radiusEnts[ 128 ];
	int			numEnts;
	const float	radius = (NPC->spawnflags&1)?256:128;
	const float	halfRadSquared = ((radius/2)*(radius/2));
	const float	radiusSquared = (radius*radius);
	float		distSq;
	int			i;
	vec3_t		boltOrg;

	AddSoundEvent( NPC, NPC->currentOrigin, 512, AEL_DANGER, qfalse, qtrue );

	numEnts = NPC_GetEntsNearBolt( radiusEnts, radius, NPC->handLBolt, boltOrg );

	for ( i = 0; i < numEnts; i++ )
	{
		if ( !radiusEnts[i]->inuse )
		{
			continue;
		}
		
		if ( radiusEnts[i] == NPC )
		{//Skip the rancor ent
			continue;
		}
		
		if ( radiusEnts[i]->client == NULL )
		{//must be a client
			continue;
		}

		if ( radiusEnts[i]->client->NPC_class == CLASS_HOWLER )
		{//other howlers immune
			continue;
		}

		distSq = DistanceSquared( radiusEnts[i]->currentOrigin, boltOrg );
		if ( distSq <= radiusSquared )
		{
			if ( distSq < halfRadSquared )
			{//close enough to do damage, too
				if ( Q_irand( 0, g_spskill->integer ) )
				{//does no damage on easy, does 1 point every other frame on medium, more often on hard
					G_Damage( radiusEnts[i], NPC, NPC, vec3_origin, NPC->currentOrigin, 1, DAMAGE_NO_KNOCKBACK, MOD_IMPACT );
				}
			}
			if ( radiusEnts[i]->health > 0 
				&& radiusEnts[i]->client
				&& radiusEnts[i]->client->NPC_class != CLASS_RANCOR
				&& radiusEnts[i]->client->NPC_class != CLASS_ATST 
				&& !PM_InKnockDown( &radiusEnts[i]->client->ps ) )
			{
				if ( PM_HasAnimation( radiusEnts[i], BOTH_SONICPAIN_START ) )
				{
					if ( radiusEnts[i]->client->ps.torsoAnim != BOTH_SONICPAIN_START 
						&& radiusEnts[i]->client->ps.torsoAnim != BOTH_SONICPAIN_HOLD )
					{
						NPC_SetAnim( radiusEnts[i], SETANIM_LEGS, BOTH_SONICPAIN_START, SETANIM_FLAG_NORMAL );
						NPC_SetAnim( radiusEnts[i], SETANIM_TORSO, BOTH_SONICPAIN_START, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
						radiusEnts[i]->client->ps.torsoAnimTimer += 100;
						radiusEnts[i]->client->ps.weaponTime = radiusEnts[i]->client->ps.torsoAnimTimer;
					}
					else if ( radiusEnts[i]->client->ps.torsoAnimTimer <= 100 )
					{//at the end of the sonic pain start or hold anim
						NPC_SetAnim( radiusEnts[i], SETANIM_LEGS, BOTH_SONICPAIN_HOLD, SETANIM_FLAG_NORMAL );
						NPC_SetAnim( radiusEnts[i], SETANIM_TORSO, BOTH_SONICPAIN_HOLD, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
						radiusEnts[i]->client->ps.torsoAnimTimer += 100; 
						radiusEnts[i]->client->ps.weaponTime = radiusEnts[i]->client->ps.torsoAnimTimer;
					}
				}
				/*
				else if ( distSq < halfRadSquared 
					&& radiusEnts[i]->client->ps.groundEntityNum != ENTITYNUM_NONE 
					&& !Q_irand( 0, 10 ) )//FIXME: base on skill
				{//within range
					G_Knockdown( radiusEnts[i], NPC, vec3_origin, 500, qfalse );
				}
				*/
			}
		}
	}

	float playerDist = NPC_EntRangeFromBolt( player, NPC->genericBolt1 );
	if ( playerDist < 256.0f )
	{
		CGCam_Shake( 1.0f*playerDist/128.0f, 200 );
	}
}
Ejemplo n.º 15
0
void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) {
	int			respawn = 0;

	if (!other->client)
		return;
	if (other->health < 1)
		return;		// dead people can't pickup

	if ( other->client->ps.pm_time > 0 )
	{//cant pick up when out of control
		return;
	}

	// NPCs can pick it up
	if ((ent->spawnflags &  ITMSF_ALLOWNPC) && (!other->s.number))
	{
		return;
	}

	// Players cannot pick it up
	if ( (ent->spawnflags &  ITMSF_NOPLAYER) && (other->s.number) )
	{
		return;
	}

	if ( ent->noDamageTeam != TEAM_FREE && other->client->playerTeam != ent->noDamageTeam )
	{//only one team can pick it up
		return;
	}
	
	if ( !G_CanPickUpWeapons( other ) )
	{//FIXME: some flag would be better
		//droids can't pick up items/weapons!
		return;
	}

	//FIXME: need to make them run toward a dropped weapon when fleeing without one?
	//FIXME: need to make them come out of flee mode when pick up their old weapon?
	if ( CheckItemCanBePickedUpByNPC( ent, other ) )
	{
		if ( other->NPC && other->NPC->goalEntity && other->NPC->goalEntity == ent )
		{//they were running to pick me up, they did, so clear goal
			other->NPC->goalEntity	= NULL;
			other->NPC->squadState	= SQUAD_STAND_AND_SHOOT;
 			NPCInfo->tempBehavior	= BS_DEFAULT;
			TIMER_Set(other, "flee", -1); 
		}
		else
		{
			return;
		}
	}
	else if ( !(ent->spawnflags &  ITMSF_ALLOWNPC) )
	{// NPCs cannot pick it up
		if ( other->s.number != 0 )
		{// Not the player?
			return;
		}
	}

	// the same pickup rules are used for client side and server side
	if ( !BG_CanItemBeGrabbed( &ent->s, &other->client->ps ) ) {
		return;
	}

	if ( other->client )
	{
		if ( (other->client->ps.eFlags&EF_FORCE_GRIPPED) || (other->client->ps.eFlags&EF_FORCE_DRAINED) )
		{//can't pick up anything while being gripped
			return;
		}
		if ( PM_InKnockDown( &other->client->ps ) && !PM_InGetUp( &other->client->ps ) )
		{//can't pick up while in a knockdown
			return;
		}
	}
	if (!ent->item) {		//not an item!
		gi.Printf( "Touch_Item: %s is not an item!\n", ent->classname);
		return;
	}

	if ( ent->item->giType == IT_WEAPON
		&& ent->item->giTag == WP_SABER )
	{//a saber
		if ( ent->delay > level.time )
		{//just picked it up, don't pick up again right away
			return;
		}
	}

	if ( other->s.number < MAX_CLIENTS
		&& (ent->spawnflags&ITMSF_USEPICKUP) )
	{//only if player is holing use button
		if ( !(other->client->usercmd.buttons&BUTTON_USE) )
		{//not holding use?
			return;
		}
	}

	qboolean bHadWeapon = qfalse;
	// call the item-specific pickup function
	switch( ent->item->giType ) 
	{
	case IT_WEAPON:
		if ( other->NPC && other->s.weapon == WP_NONE )
		{//Make them duck and sit here for a few seconds
			int pickUpTime = Q_irand( 1000, 3000 );
			TIMER_Set( other, "duck", pickUpTime );
			TIMER_Set( other, "roamTime", pickUpTime );
			TIMER_Set( other, "stick", pickUpTime );
			TIMER_Set( other, "verifyCP", pickUpTime );
			TIMER_Set( other, "attackDelay", 600 );
			respawn = 0;
		}
		if ( other->client->ps.stats[STAT_WEAPONS] & ( 1 << ent->item->giTag ) )
		{
			bHadWeapon = qtrue;
		}
		respawn = Pickup_Weapon(ent, other);
		break;
	case IT_AMMO:
		respawn = Pickup_Ammo(ent, other);
		break;
	case IT_ARMOR:
		respawn = Pickup_Armor(ent, other);
		break;
	case IT_HEALTH:
		respawn = Pickup_Health(ent, other);
		break;
	case IT_HOLDABLE:
		respawn = Pickup_Holdable(ent, other);
		break;
	case IT_BATTERY:
		respawn = Pickup_Battery( ent, other );
		break;
	case IT_HOLOCRON:
		respawn = Pickup_Holocron( ent, other );
		break;
	default:
		return;
	}

	if ( !respawn ) 
	{
		return;
	}

	// play the normal pickup sound
	if ( !other->s.number && g_timescale->value < 1.0f  )
	{//SIGH... with timescale on, you lose events left and right
extern void CG_ItemPickup( int itemNum, qboolean bHadItem );
		// but we're SP so we'll cheat
		cgi_S_StartSound( NULL, other->s.number, CHAN_AUTO,	cgi_S_RegisterSound( ent->item->pickup_sound ) );
		// show icon and name on status bar
		CG_ItemPickup( ent->s.modelindex, bHadWeapon );
	}
	else
	{
		if ( bHadWeapon )
		{
			G_AddEvent( other, EV_ITEM_PICKUP, -ent->s.modelindex );
		} 
		else
		{
			G_AddEvent( other, EV_ITEM_PICKUP, ent->s.modelindex );
		}
	}

	// fire item targets
	G_UseTargets (ent, other);

	if ( ent->item->giType == IT_WEAPON
		&& ent->item->giTag == WP_SABER )
	{//a saber that was picked up
		if ( ent->count < 0 )
		{//infinite supply
			ent->delay = level.time + 500;
			return;
		}
		ent->count--;
		if ( ent->count > 0 )
		{//still have more to pick up
			ent->delay = level.time + 500;
			return;
		}
	}
	// wait of -1 will not respawn
//	if ( ent->wait == -1 ) 
	{
		//why not just remove me?
		G_FreeEntity( ent );
		/*
		//NOTE: used to do this:  (for respawning?)
		ent->svFlags |= SVF_NOCLIENT;
		ent->s.eFlags |= EF_NODRAW;
		ent->contents = 0;
		ent->unlinkAfterEvent = qtrue;
		*/
		return;
	}
}
Ejemplo n.º 16
0
void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) {
	int			respawn = 0;

	if (!other->client)
		return;
	if (other->health < 1)
		return;		// dead people can't pickup

	if ( other->client->ps.pm_time > 0 )
	{//cant pick up when out of control
		return;
	}

	// Only monsters can pick it up
	if ((ent->spawnflags &  ITMSF_MONSTER) && (other->client->playerTeam == TEAM_PLAYER))
	{
		return;
	}

	// Only starfleet can pick it up
	if ((ent->spawnflags &  ITMSF_TEAM) && (other->client->playerTeam != TEAM_PLAYER))
	{
		return;
	}


	if ( other->client->NPC_class == CLASS_ATST ||
		other->client->NPC_class == CLASS_GONK ||
		other->client->NPC_class == CLASS_MARK1 ||
		other->client->NPC_class == CLASS_MARK2 ||
		other->client->NPC_class == CLASS_MOUSE ||
		other->client->NPC_class == CLASS_PROBE ||
		other->client->NPC_class == CLASS_PROTOCOL ||
		other->client->NPC_class == CLASS_R2D2 ||
		other->client->NPC_class == CLASS_R5D2 ||
		other->client->NPC_class == CLASS_SEEKER ||
		other->client->NPC_class == CLASS_REMOTE ||
		other->client->NPC_class == CLASS_SENTRY )
	{//FIXME: some flag would be better
		//droids can't pick up items/weapons!
		return;
	}

	//FIXME: need to make them run toward a dropped weapon when fleeing without one?
	//FIXME: need to make them come out of flee mode when pick up their old weapon?
	if ( CheckItemCanBePickedUpByNPC( ent, other ) )
	{
		if ( other->NPC && other->NPC->goalEntity && other->NPC->goalEntity->enemy == ent )
		{//they were running to pick me up, they did, so clear goal
			other->NPC->goalEntity = NULL;
			other->NPC->squadState = SQUAD_STAND_AND_SHOOT;
		}
	}
	else if (!(ent->spawnflags &  ITMSF_TEAM) && !(ent->spawnflags &  ITMSF_MONSTER))
	{// Only player can pick it up
		if ( other->s.number != 0 )	// Not the player?
		{
			return;
		}
	}

	// the same pickup rules are used for client side and server side
	if ( !BG_CanItemBeGrabbed( &ent->s, &other->client->ps ) ) {
		return;
	}

	if ( other->client )
	{
		if ( other->client->ps.eFlags&EF_FORCE_GRIPPED )
		{//can't pick up anything while being gripped
			return;
		}
		if ( PM_InKnockDown( &other->client->ps ) && !PM_InGetUp( &other->client->ps ) )
		{//can't pick up while in a knockdown
			return;
		}
	}
	if (!ent->item) {		//not an item!
		gi.Printf( "Touch_Item: %s is not an item!\n", ent->classname);
		return;
	}
	qboolean bHadWeapon = qfalse;
	// call the item-specific pickup function
	switch( ent->item->giType )
	{
	case IT_WEAPON:
		if ( other->NPC && other->s.weapon == WP_NONE )
		{//Make them duck and sit here for a few seconds
			int pickUpTime = Q_irand( 1000, 3000 );
			TIMER_Set( other, "duck", pickUpTime );
			TIMER_Set( other, "roamTime", pickUpTime );
			TIMER_Set( other, "stick", pickUpTime );
			TIMER_Set( other, "verifyCP", pickUpTime );
			TIMER_Set( other, "attackDelay", 600 );
			respawn = 0;
		}
		if ( other->client->ps.stats[STAT_WEAPONS] & ( 1 << ent->item->giTag ) )
		{
			bHadWeapon = qtrue;
		}
		respawn = Pickup_Weapon(ent, other);
		break;
	case IT_AMMO:
		respawn = Pickup_Ammo(ent, other);
		break;
	case IT_ARMOR:
		respawn = Pickup_Armor(ent, other);
		break;
	case IT_HEALTH:
		respawn = Pickup_Health(ent, other);
		break;
	case IT_HOLDABLE:
		respawn = Pickup_Holdable(ent, other);
		break;
	case IT_BATTERY:
		respawn = Pickup_Battery( ent, other );
		break;
	case IT_HOLOCRON:
		respawn = Pickup_Holocron( ent, other );
		break;
	default:
		return;
	}

	if ( !respawn )
	{
		return;
	}

	// play the normal pickup sound
	if ( !other->s.number && g_timescale->value < 1.0f  )
	{//SIGH... with timescale on, you lose events left and right
extern void CG_ItemPickup( int itemNum, qboolean bHadItem );
		// but we're SP so we'll cheat
		cgi_S_StartSound( NULL, other->s.number, CHAN_AUTO,	cgi_S_RegisterSound( ent->item->pickup_sound ) );
		// show icon and name on status bar
		CG_ItemPickup( ent->s.modelindex, bHadWeapon );
	}
	else
	{
		if ( bHadWeapon )
		{
			G_AddEvent( other, EV_ITEM_PICKUP, -ent->s.modelindex );
		}
		else
		{
			G_AddEvent( other, EV_ITEM_PICKUP, ent->s.modelindex );
		}
	}

	// fire item targets
	G_UseTargets (ent, other);

	// wait of -1 will not respawn
//	if ( ent->wait == -1 )
	{
		//why not just remove me?
		G_FreeEntity( ent );
		/*
		//NOTE: used to do this:  (for respawning?)
		ent->svFlags |= SVF_NOCLIENT;
		ent->s.eFlags |= EF_NODRAW;
		ent->contents = 0;
		ent->unlinkAfterEvent = qtrue;
		*/
		return;
	}
}