Exemple #1
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;
	}
}
Exemple #2
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;
    }
}