codemp/game/NPC_reactions.c File Reference

#include "b_local.h"
#include "anims.h"
#include "w_saber.h"
#include "../namespace_begin.h"
#include "../namespace_end.h"

Go to the source code of this file.

Defines

#define MIN_PAIN_TIME   200

Functions

qboolean G_CheckForStrongAttackMomentum (gentity_t *self)
void G_AddVoiceEvent (gentity_t *self, int event, int speakDebounceTime)
void G_SoundOnEnt (gentity_t *ent, soundChannel_t channel, const char *soundPath)
void cgi_S_StartSound (vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx)
qboolean Q3_TaskIDPending (gentity_t *ent, taskID_t taskType)
qboolean NPC_CheckLookTarget (gentity_t *self)
void NPC_SetLookTarget (gentity_t *self, int entNum, int clearTime)
qboolean Jedi_WaitingAmbush (gentity_t *self)
void Jedi_Ambush (gentity_t *self)
qboolean NPC_SomeoneLookingAtMe (gentity_t *ent)
qboolean BG_SaberInSpecialAttack (int anim)
qboolean PM_SpinningSaberAnim (int anim)
qboolean PM_SpinningAnim (int anim)
qboolean PM_InKnockDown (playerState_t *ps)
qboolean BG_FlippingAnim (int anim)
qboolean PM_RollingAnim (int anim)
qboolean PM_InCartwheel (int anim)
qboolean BG_CrouchAnim (int anim)
void NPC_SetPainEvent (gentity_t *self)
float NPC_GetPainChance (gentity_t *self, int damage)
int G_PickPainAnim (gentity_t *self, vec3_t point, int damage, int hitLoc)
void NPC_ChoosePainAnimation (gentity_t *self, gentity_t *other, vec3_t point, int damage, int mod, int hitLoc, int voiceEvent)
void NPC_Pain (gentity_t *self, gentity_t *attacker, int damage)
qboolean INV_SecurityKeyGive (gentity_t *target, const char *keyname)
void NPC_Touch (gentity_t *self, gentity_t *other, trace_t *trace)
void NPC_TempLookTarget (gentity_t *self, int lookEntNum, int minLookTime, int maxLookTime)
void NPC_Respond (gentity_t *self, int userNum)
void NPC_UseResponse (gentity_t *self, gentity_t *user, qboolean useWhenDone)
void Add_Batteries (gentity_t *ent, int *count)
void NPC_Use (gentity_t *self, gentity_t *other, gentity_t *activator)
void NPC_CheckPlayerAim (void)
void NPC_CheckAllClear (void)

Variables

int teamLastEnemyTime []
int killPlayerTimer


Define Documentation

#define MIN_PAIN_TIME   200
 

Definition at line 204 of file NPC_reactions.c.


Function Documentation

void Add_Batteries gentity_t ent,
int *  count
 

qboolean BG_CrouchAnim int  anim  ) 
 

Definition at line 49 of file bg_panimate.c.

References BOTH_CROUCH1, BOTH_CROUCH1IDLE, BOTH_CROUCH1WALK, BOTH_CROUCH1WALKBACK, BOTH_CROUCH2TOSTAND1, BOTH_CROUCH3, BOTH_CROUCHATTACKBACK1, BOTH_KNEES1, BOTH_ROLL_STAB, BOTH_SIT1, BOTH_SIT2, BOTH_SIT3, qboolean, qfalse, and qtrue.

Referenced by NPC_BSGM_Attack(), NPC_ChoosePainAnimation(), and WP_ResistForcePush().

00050 {
00051         switch ( anim )
00052         {
00053         case BOTH_SIT1:                         //# Normal chair sit.
00054         case BOTH_SIT2:                         //# Lotus position.
00055         case BOTH_SIT3:                         //# Sitting in tired position: elbows on knees
00056         case BOTH_CROUCH1:                      //# Transition from standing to crouch
00057         case BOTH_CROUCH1IDLE:          //# Crouching idle
00058         case BOTH_CROUCH1WALK:          //# Walking while crouched
00059         case BOTH_CROUCH1WALKBACK:      //# Walking while crouched
00060         case BOTH_CROUCH2TOSTAND1:      //# going from crouch2 to stand1
00061         case BOTH_CROUCH3:                      //# Desann crouching down to Kyle (cin 9)
00062         case BOTH_KNEES1:                       //# Tavion on her knees
00063         case BOTH_CROUCHATTACKBACK1://FIXME: not if in middle of anim?
00064         case BOTH_ROLL_STAB:
00065                 return qtrue;
00066                 break;
00067         }
00068         return qfalse;
00069 }

qboolean BG_FlippingAnim int  anim  ) 
 

Definition at line 433 of file bg_panimate.c.

References BOTH_A7_SOULCAL, BOTH_ARIAL_F1, BOTH_ARIAL_LEFT, BOTH_ARIAL_RIGHT, BOTH_BUTTERFLY_FL1, BOTH_BUTTERFLY_FR1, BOTH_BUTTERFLY_LEFT, BOTH_BUTTERFLY_RIGHT, BOTH_CARTWHEEL_LEFT, BOTH_CARTWHEEL_RIGHT, BOTH_FLIP_ATTACK7, BOTH_FLIP_B, BOTH_FLIP_BACK1, BOTH_FLIP_BACK2, BOTH_FLIP_BACK3, BOTH_FLIP_F, BOTH_FLIP_L, BOTH_FLIP_R, BOTH_FORCEWALLRUNFLIP_ALT, BOTH_FORCEWALLRUNFLIP_END, BOTH_JUMPATTACK6, BOTH_JUMPATTACK7, BOTH_JUMPFLIPSLASHDOWN1, BOTH_JUMPFLIPSTABDOWN, BOTH_WALL_FLIP_BACK1, BOTH_WALL_FLIP_LEFT, BOTH_WALL_FLIP_RIGHT, BOTH_WALL_RUN_LEFT, BOTH_WALL_RUN_LEFT_FLIP, BOTH_WALL_RUN_LEFT_STOP, BOTH_WALL_RUN_RIGHT, BOTH_WALL_RUN_RIGHT_FLIP, BOTH_WALL_RUN_RIGHT_STOP, qboolean, qfalse, and qtrue.

Referenced by Boba_FireDecide(), Jedi_SaberBusy(), NPC_ChoosePainAnimation(), PM_CheckAltKickAttack(), PM_SetSaberMove(), PM_WeaponLightsaber(), and WP_ResistForcePush().

00434 {
00435         switch ( anim )
00436         {
00437         case BOTH_FLIP_F:                       //# Flip forward
00438         case BOTH_FLIP_B:                       //# Flip backwards
00439         case BOTH_FLIP_L:                       //# Flip left
00440         case BOTH_FLIP_R:                       //# Flip right
00441         case BOTH_WALL_RUN_RIGHT_FLIP:
00442         case BOTH_WALL_RUN_LEFT_FLIP:
00443         case BOTH_WALL_FLIP_RIGHT:
00444         case BOTH_WALL_FLIP_LEFT:
00445         case BOTH_FLIP_BACK1:
00446         case BOTH_FLIP_BACK2:
00447         case BOTH_FLIP_BACK3:
00448         case BOTH_WALL_FLIP_BACK1:
00449         //Not really flips, but...
00450         case BOTH_WALL_RUN_RIGHT:
00451         case BOTH_WALL_RUN_LEFT:
00452         case BOTH_WALL_RUN_RIGHT_STOP:
00453         case BOTH_WALL_RUN_LEFT_STOP:
00454         case BOTH_BUTTERFLY_LEFT:
00455         case BOTH_BUTTERFLY_RIGHT:
00456         case BOTH_BUTTERFLY_FL1:
00457         case BOTH_BUTTERFLY_FR1:
00458         //
00459         case BOTH_ARIAL_LEFT:
00460         case BOTH_ARIAL_RIGHT:
00461         case BOTH_ARIAL_F1:
00462         case BOTH_CARTWHEEL_LEFT:
00463         case BOTH_CARTWHEEL_RIGHT:
00464         case BOTH_JUMPFLIPSLASHDOWN1:
00465         case BOTH_JUMPFLIPSTABDOWN:
00466         case BOTH_JUMPATTACK6:
00467         case BOTH_JUMPATTACK7:
00468         //JKA
00469         case BOTH_FORCEWALLRUNFLIP_END:
00470         case BOTH_FORCEWALLRUNFLIP_ALT:
00471         case BOTH_FLIP_ATTACK7:
00472         case BOTH_A7_SOULCAL:
00473                 return qtrue;
00474                 break;
00475         }
00476         return qfalse;
00477 }

qboolean BG_SaberInSpecialAttack int  anim  ) 
 

Definition at line 587 of file bg_panimate.c.

References BOTH_A1_SPECIAL, BOTH_A2_SPECIAL, BOTH_A2_STABBACK1, BOTH_A3_SPECIAL, BOTH_A6_FB, BOTH_A6_LR, BOTH_A6_SABERPROTECT, BOTH_A7_HILT, BOTH_A7_KICK_B, BOTH_A7_KICK_B_AIR, BOTH_A7_KICK_BF, BOTH_A7_KICK_F, BOTH_A7_KICK_F_AIR, BOTH_A7_KICK_L, BOTH_A7_KICK_L_AIR, BOTH_A7_KICK_R, BOTH_A7_KICK_R_AIR, BOTH_A7_KICK_RL, BOTH_A7_KICK_S, BOTH_A7_SOULCAL, BOTH_ALORA_SPIN_SLASH, BOTH_ATTACK_BACK, BOTH_BUTTERFLY_FL1, BOTH_BUTTERFLY_FR1, BOTH_BUTTERFLY_LEFT, BOTH_BUTTERFLY_RIGHT, BOTH_CROUCHATTACKBACK1, BOTH_FJSS_TL_BR, BOTH_FJSS_TR_BL, BOTH_FLIP_ATTACK7, BOTH_FORCELEAP2_T__B_, BOTH_FORCELONGLEAP_ATTACK, BOTH_JUMPATTACK6, BOTH_JUMPATTACK7, BOTH_JUMPFLIPSLASHDOWN1, BOTH_JUMPFLIPSTABDOWN, BOTH_LUNGE2_B__T_, BOTH_PULL_IMPALE_STAB, BOTH_PULL_IMPALE_SWING, BOTH_ROLL_STAB, BOTH_SPINATTACK6, BOTH_SPINATTACK7, BOTH_STABDOWN, BOTH_STABDOWN_DUAL, BOTH_STABDOWN_STAFF, BOTH_VS_ATL_S, BOTH_VS_ATR_S, BOTH_VT_ATL_S, BOTH_VT_ATR_S, qboolean, qfalse, and qtrue.

Referenced by G_SPSaberDamageTraceLerped(), Jedi_CheckFlipEvasions(), Jedi_SaberBlockGo(), Jedi_SaberBusy(), NPC_ChoosePainAnimation(), PM_ForceJumpingUp(), PM_SaberAttackForMovement(), PM_SetSaberMove(), and WP_SaberStartMissileBlockCheck().

00588 {
00589         switch ( anim )
00590         {
00591         case BOTH_A2_STABBACK1:
00592         case BOTH_ATTACK_BACK:
00593         case BOTH_CROUCHATTACKBACK1:
00594         case BOTH_ROLL_STAB:
00595         case BOTH_BUTTERFLY_LEFT:
00596         case BOTH_BUTTERFLY_RIGHT:
00597         case BOTH_BUTTERFLY_FL1:
00598         case BOTH_BUTTERFLY_FR1:
00599         case BOTH_FJSS_TR_BL:
00600         case BOTH_FJSS_TL_BR:
00601         case BOTH_LUNGE2_B__T_:
00602         case BOTH_FORCELEAP2_T__B_:
00603         case BOTH_JUMPFLIPSLASHDOWN1://#
00604         case BOTH_JUMPFLIPSTABDOWN://#
00605         case BOTH_JUMPATTACK6:
00606         case BOTH_JUMPATTACK7:
00607         case BOTH_SPINATTACK6:
00608         case BOTH_SPINATTACK7:
00609         case BOTH_FORCELONGLEAP_ATTACK:
00610         case BOTH_VS_ATR_S:
00611         case BOTH_VS_ATL_S:
00612         case BOTH_VT_ATR_S:
00613         case BOTH_VT_ATL_S:
00614         case BOTH_A7_KICK_F:
00615         case BOTH_A7_KICK_B:
00616         case BOTH_A7_KICK_R:
00617         case BOTH_A7_KICK_L:
00618         case BOTH_A7_KICK_S:
00619         case BOTH_A7_KICK_BF:
00620         case BOTH_A7_KICK_RL:
00621         case BOTH_A7_KICK_F_AIR:
00622         case BOTH_A7_KICK_B_AIR:
00623         case BOTH_A7_KICK_R_AIR:
00624         case BOTH_A7_KICK_L_AIR:
00625         case BOTH_STABDOWN:
00626         case BOTH_STABDOWN_STAFF:
00627         case BOTH_STABDOWN_DUAL:
00628         case BOTH_A6_SABERPROTECT:
00629         case BOTH_A7_SOULCAL:
00630         case BOTH_A1_SPECIAL:
00631         case BOTH_A2_SPECIAL:
00632         case BOTH_A3_SPECIAL:
00633         case BOTH_FLIP_ATTACK7:
00634         case BOTH_PULL_IMPALE_STAB:
00635         case BOTH_PULL_IMPALE_SWING:
00636         case BOTH_ALORA_SPIN_SLASH:
00637         case BOTH_A6_FB:
00638         case BOTH_A6_LR:        
00639         case BOTH_A7_HILT:
00640                 return qtrue;
00641         }
00642         return qfalse;
00643 }

void cgi_S_StartSound vec3_t  origin,
int  entityNum,
int  entchannel,
sfxHandle_t  sfx
 

void G_AddVoiceEvent gentity_t self,
int  event,
int  speakDebounceTime
 

Definition at line 23 of file NPC_sounds.c.

00024 {
00025         if ( !self->NPC )
00026         {
00027                 return;
00028         }
00029 
00030         if ( !self->client || self->client->ps.pm_type >= PM_DEAD )
00031         {
00032                 return;
00033         }
00034 
00035         if ( self->NPC->blockedSpeechDebounceTime > level.time )
00036         {
00037                 return;
00038         }
00039 
00040         if ( trap_ICARUS_TaskIDPending( self, TID_CHAN_VOICE ) )
00041         {
00042                 return;
00043         }
00044 
00045         
00046         if ( (self->NPC->scriptFlags&SCF_NO_COMBAT_TALK) && ( (event >= EV_ANGER1 && event <= EV_VICTORY3) || (event >= EV_CHASE1 && event <= EV_SUSPICIOUS5) ) )//(event < EV_FF_1A || event > EV_FF_3C) && (event < EV_RESPOND1 || event > EV_MISSION3) )
00047         {
00048                 return;
00049         }
00050         
00051         if ( (self->NPC->scriptFlags&SCF_NO_ALERT_TALK) && (event >= EV_GIVEUP1 && event <= EV_SUSPICIOUS5) )
00052         {
00053                 return;
00054         }
00055         //FIXME: Also needs to check for teammates. Don't want
00056         //              everyone babbling at once
00057 
00058         //NOTE: was losing too many speech events, so we do it directly now, screw networking!
00059         //G_AddEvent( self, event, 0 );
00060         G_SpeechEvent( self, event );
00061 
00062         //won't speak again for 5 seconds (unless otherwise specified)
00063         self->NPC->blockedSpeechDebounceTime = level.time + ((speakDebounceTime==0) ? 5000 : speakDebounceTime);
00064 }

qboolean G_CheckForStrongAttackMomentum gentity_t self  ) 
 

int G_PickPainAnim gentity_t self,
vec3_t  point,
int  damage,
int  hitLoc
 

void G_SoundOnEnt gentity_t ent,
soundChannel_t  channel,
const char *  soundPath
 

Referenced by Boba_FlyStart(), Boba_StartFlameThrower(), Droid_Patrol(), G_ATSTCheckPain(), G_DroidSounds(), ImperialProbe_AttackDecision(), ImperialProbe_Patrol(), Interrogator_Attack(), Interrogator_Idle(), Jedi_CheckFlipEvasions(), NPC_BSSniper_Attack(), NPC_GM_StartLaser(), NPC_Sentry_Patrol(), Sentry_AttackDecision(), and Sentry_RangedAttack().

qboolean INV_SecurityKeyGive gentity_t target,
const char *  keyname
 

void Jedi_Ambush gentity_t self  ) 
 

Definition at line 5547 of file NPC_AI_Jedi.c.

05548 {
05549         self->client->noclip = qfalse;
05550 //      self->client->ps.pm_flags |= PMF_JUMPING|PMF_SLOW_MO_FALL;
05551         NPC_SetAnim( self, SETANIM_BOTH, BOTH_CEILING_DROP, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
05552         self->client->ps.weaponTime = self->client->ps.torsoTimer; //NPC->client->ps.torsoTimer; //what the?
05553         if ( self->client->NPC_class != CLASS_BOBAFETT )
05554         {
05555                 WP_ActivateSaber(self);
05556         }
05557         Jedi_Decloak( self );
05558         G_AddVoiceEvent( self, Q_irand( EV_ANGER1, EV_ANGER3 ), 1000 );
05559 }

qboolean Jedi_WaitingAmbush gentity_t self  ) 
 

void NPC_CheckAllClear void   ) 
 

Definition at line 1113 of file NPC_reactions.c.

Referenced by NPC_ExecuteBState().

01114 {
01115         //FIXME: need to make this happen only once after losing enemies, not over and over again
01116         /*
01117         if ( NPC->client && !NPC->enemy && level.time - teamLastEnemyTime[NPC->client->playerTeam] > 10000 )
01118         {//Team hasn't seen an enemy in 10 seconds
01119                 if ( !Q_irand( 0, 2 ) )
01120                 {
01121                         G_AddVoiceEvent( NPC, Q_irand(EV_SETTLE1, EV_SETTLE3), 3000 );
01122                 }
01123         }
01124         */
01125 }

qboolean NPC_CheckLookTarget gentity_t self  ) 
 

Definition at line 1653 of file NPC_utils.c.

References gentity_s::client, gentity_s::enemy, ENTITYNUM_WORLD, g_entities, gentity_t, level, renderInfo_s::lookTarget, renderInfo_s::lookTargetClearTime, NPC_ClearLookTarget(), NULL, qboolean, qfalse, qtrue, gclient_s::renderInfo, and level_locals_t::time.

Referenced by G_ClearEnemy(), NPC_ExecuteBState(), and NPC_TempLookTarget().

01654 {
01655         if ( self->client )
01656         {
01657                 if ( self->client->renderInfo.lookTarget >= 0 && self->client->renderInfo.lookTarget < ENTITYNUM_WORLD )
01658                 {//within valid range
01659                         if ( (&g_entities[self->client->renderInfo.lookTarget] == NULL) || !g_entities[self->client->renderInfo.lookTarget].inuse )
01660                         {//lookTarget not inuse or not valid anymore
01661                                 NPC_ClearLookTarget( self );
01662                         }
01663                         else if ( self->client->renderInfo.lookTargetClearTime && self->client->renderInfo.lookTargetClearTime < level.time )
01664                         {//Time to clear lookTarget
01665                                 NPC_ClearLookTarget( self );
01666                         }
01667                         else if ( g_entities[self->client->renderInfo.lookTarget].client && self->enemy && (&g_entities[self->client->renderInfo.lookTarget] != self->enemy) )
01668                         {//should always look at current enemy if engaged in battle... FIXME: this could override certain scripted lookTargets...???
01669                                 NPC_ClearLookTarget( self );
01670                         }
01671                         else
01672                         {
01673                                 return qtrue;
01674                         }
01675                 }
01676         }
01677 
01678         return qfalse;
01679 }

void NPC_CheckPlayerAim void   ) 
 

Definition at line 1095 of file NPC_reactions.c.

Referenced by NPC_ExecuteBState().

01096 {
01097         //FIXME: need appropriate dialogue
01098         /*
01099         gentity_t *player = &g_entities[0];
01100 
01101         if ( player && player->client && player->client->ps.weapon > (int)(WP_NONE) && player->client->ps.weapon < (int)(WP_TRICORDER) )
01102         {//player has a weapon ready
01103                 if ( g_crosshairEntNum == NPC->s.number && level.time - g_crosshairEntTime < 200 
01104                         && g_crosshairSameEntTime >= 3000 && g_crosshairEntDist < 256 )
01105                 {//if the player holds the crosshair on you for a few seconds
01106                         //ask them what the fuck they're doing
01107                         G_AddVoiceEvent( NPC, Q_irand( EV_FF_1A, EV_FF_1C ), 0 );
01108                 }
01109         }
01110         */
01111 }

void NPC_ChoosePainAnimation gentity_t self,
gentity_t other,
vec3_t  point,
int  damage,
int  mod,
int  hitLoc,
int  voiceEvent
 

Definition at line 207 of file NPC_reactions.c.

References BG_CrouchAnim(), BG_FlippingAnim(), BG_PickAnim(), BG_SaberInSpecialAttack(), bgAllAnims, bgHumanoidAnimations, BOTH_PAIN1, BOTH_PAIN18, BOTH_PAIN2, BOTH_PAIN3, CLASS_DESANN, CLASS_GALAKMECH, CLASS_PROTOCOL, gentity_s::client, EV_CHOKE1, EV_CHOKE3, fabs(), playerState_s::fd, FORCE_LEVEL_1, forcedata_s::forceGripBeingGripped, G_AddVoiceEvent(), gentity_t, gentity_s::health, HL_GENERIC1, playerState_s::legsAnim, level, gentity_s::localAnimIndex, LS_READY, MOD_CRUSH, MOD_MELEE, gentity_s::NPC, gclient_s::NPC_class, NPC_GetPainChance(), NPC_SetAnim(), NPC_SetPainEvent(), NPCTEAM_PLAYER, entityState_s::number, gentity_s::painDebounceTime, gclient_s::playerTeam, PM_InCartwheel(), PM_InKnockDown(), PM_RollingAnim(), PM_SpinningAnim(), gclient_s::ps, Q_irand(), random, gNPC_t::rank, RANK_CAPTAIN, gentity_s::s, forcedata_s::saberAnimLevel, playerState_s::saberMove, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, SETANIM_LEGS, level_locals_t::time, playerState_s::torsoAnim, vec3_t, entityState_s::weapon, playerState_s::weaponTime, WP_SABER, and WP_THERMAL.

Referenced by NPC_Pain().

00208 {
00209         int             pain_anim = -1;
00210         float   pain_chance;
00211         
00212         //If we've already taken pain, then don't take it again
00213         if ( level.time < self->painDebounceTime && /*mod != MOD_ELECTROCUTE &&*/ mod != MOD_MELEE ) //rwwFIXMEFIXME: MOD_ELECTROCUTE
00214         {//FIXME: if hit while recoving from losing a saber lock, we should still play a pain anim?
00215                 return;
00216         }
00217         
00218         if ( self->s.weapon == WP_THERMAL && self->client->ps.weaponTime > 0 )
00219         {//don't interrupt thermal throwing anim
00220                 return;
00221         }
00222         else if ( self->client->NPC_class == CLASS_GALAKMECH )
00223         {
00224                 if ( hitLoc == HL_GENERIC1 )
00225                 {//hit the antenna!
00226                         pain_chance = 1.0f;
00227                 //      self->s.powerups |= ( 1 << PW_SHOCKED );
00228                 //      self->client->ps.powerups[PW_SHOCKED] = level.time + Q_irand( 500, 2500 );
00229                         //rwwFIXMEFIXME: support for this
00230                 }
00231         //      else if ( self->client->ps.powerups[PW_GALAK_SHIELD] )
00232         //      {//shield up
00233         //              return;
00234         //      }
00235                 //rwwFIXMEFIXME: and this
00236                 else if ( self->health > 200 && damage < 100 )
00237                 {//have a *lot* of health
00238                         pain_chance = 0.05f;
00239                 }
00240                 else
00241                 {//the lower my health and greater the damage, the more likely I am to play a pain anim
00242                         pain_chance = (200.0f-self->health)/100.0f + damage/50.0f;
00243                 }
00244         }
00245         else if ( self->client && self->client->playerTeam == NPCTEAM_PLAYER && other && !other->s.number )
00246         {//ally shot by player always complains
00247                 pain_chance = 1.1f;
00248         }
00249         else 
00250         {
00251                 if ( other && other->s.weapon == WP_SABER || /*mod == MOD_ELECTROCUTE ||*/ mod == MOD_CRUSH/*FIXME:MOD_FORCE_GRIP*/ )
00252                 {
00253                         pain_chance = 1.0f;//always take pain from saber
00254                 }
00255                 else if ( mod == MOD_MELEE )
00256                 {//higher in rank (skill) we are, less likely we are to be fazed by a punch
00257                         pain_chance = 1.0f - ((RANK_CAPTAIN-self->NPC->rank)/(float)RANK_CAPTAIN);
00258                 }
00259                 else if ( self->client->NPC_class == CLASS_PROTOCOL )
00260                 {
00261                         pain_chance = 1.0f;
00262                 }
00263                 else
00264                 {
00265                         pain_chance = NPC_GetPainChance( self, damage );
00266                 }
00267                 if ( self->client->NPC_class == CLASS_DESANN )
00268                 {
00269                         pain_chance *= 0.5f;
00270                 }
00271         }
00272 
00273         //See if we're going to flinch
00274         if ( random() < pain_chance )
00275         {
00276                 int animLength;
00277 
00278                 //Pick and play our animation
00279                 if ( self->client->ps.fd.forceGripBeingGripped < level.time )
00280                 {//not being force-gripped or force-drained
00281                         if ( /*G_CheckForStrongAttackMomentum( self ) //rwwFIXMEFIXME: Is this needed?
00282                                 ||*/ PM_SpinningAnim( self->client->ps.legsAnim )
00283                                 || BG_SaberInSpecialAttack( self->client->ps.torsoAnim )
00284                                 || PM_InKnockDown( &self->client->ps )
00285                                 || PM_RollingAnim( self->client->ps.legsAnim )
00286                                 || (BG_FlippingAnim( self->client->ps.legsAnim )&&!PM_InCartwheel( self->client->ps.legsAnim )) )
00287                         {//strong attacks, rolls, knockdowns, flips and spins cannot be interrupted by pain
00288                         }
00289                         else
00290                         {//play an anim
00291                                 int parts;
00292 
00293                                 if ( self->client->NPC_class == CLASS_GALAKMECH )
00294                                 {//only has 1 for now
00295                                         //FIXME: never plays this, it seems...
00296                                         pain_anim = BOTH_PAIN1;
00297                                 }
00298                                 else if ( mod == MOD_MELEE )
00299                                 {
00300                                         pain_anim = BG_PickAnim( self->localAnimIndex, BOTH_PAIN2, BOTH_PAIN3 );
00301                                 }
00302                                 else if ( self->s.weapon == WP_SABER )
00303                                 {//temp HACK: these are the only 2 pain anims that look good when holding a saber
00304                                         pain_anim = BG_PickAnim( self->localAnimIndex, BOTH_PAIN2, BOTH_PAIN3 );
00305                                 }
00306                                 /*
00307                                 else if ( mod != MOD_ELECTROCUTE )
00308                                 {
00309                                         pain_anim = G_PickPainAnim( self, point, damage, hitLoc );
00310                                 }
00311                                 */
00312 
00313                                 if ( pain_anim == -1 )
00314                                 {
00315                                         pain_anim = BG_PickAnim( self->localAnimIndex, BOTH_PAIN1, BOTH_PAIN18 );
00316                                 }
00317                                 self->client->ps.fd.saberAnimLevel = FORCE_LEVEL_1;//next attack must be a quick attack
00318                                 self->client->ps.saberMove = LS_READY;//don't finish whatever saber move you may have been in
00319                                 parts = SETANIM_BOTH;
00320                                 if ( BG_CrouchAnim( self->client->ps.legsAnim ) || PM_InCartwheel( self->client->ps.legsAnim ) )
00321                                 {
00322                                         parts = SETANIM_LEGS;
00323                                 }
00324 
00325                                 if (pain_anim != -1)
00326                                 {
00327                                         NPC_SetAnim( self, parts, pain_anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00328                                 }
00329                         }
00330                         if ( voiceEvent != -1 )
00331                         {
00332                                 G_AddVoiceEvent( self, voiceEvent, Q_irand( 2000, 4000 ) );
00333                         }
00334                         else
00335                         {
00336                                 NPC_SetPainEvent( self );
00337                         }
00338                 }
00339                 else
00340                 {
00341                         G_AddVoiceEvent( self, Q_irand(EV_CHOKE1, EV_CHOKE3), 0 );
00342                 }
00343                 
00344                 //Setup the timing for it
00345                 /*
00346                 if ( mod == MOD_ELECTROCUTE )
00347                 {
00348                         self->painDebounceTime = level.time + 4000;
00349                 }
00350                 */
00351                 animLength = bgAllAnims[self->localAnimIndex].anims[pain_anim].numFrames * fabs((float)(bgHumanoidAnimations[pain_anim].frameLerp));
00352 
00353                 self->painDebounceTime = level.time + animLength;
00354                 self->client->ps.weaponTime = 0;
00355         }
00356 }

float NPC_GetPainChance gentity_t self,
int  damage
 

Definition at line 157 of file NPC_reactions.c.

References gentity_s::client, gentity_s::enemy, g_spskill, gentity_t, gentity_s::health, vmCvar_t::integer, gclient_s::ps, STAT_MAX_HEALTH, and playerState_s::stats.

Referenced by NPC_ChoosePainAnimation(), NPC_Droid_Pain(), and NPC_Probe_Pain().

00158 {
00159         float pain_chance;
00160         if ( !self->enemy )
00161         {//surprised, always take pain
00162                 return 1.0f;
00163         }
00164 
00165         if (!self->client)
00166         {
00167                 return 1.0f;
00168         }
00169 
00170         //if ( damage > self->max_health/2.0f )
00171         if (damage > self->client->ps.stats[STAT_MAX_HEALTH]/2.0f)
00172         {
00173                 return 1.0f;
00174         }
00175 
00176         pain_chance = (float)(self->client->ps.stats[STAT_MAX_HEALTH]-self->health)/(self->client->ps.stats[STAT_MAX_HEALTH]*2.0f) + (float)damage/(self->client->ps.stats[STAT_MAX_HEALTH]/2.0f);
00177         switch ( g_spskill.integer )
00178         {
00179         case 0: //easy
00180                 //return 0.75f;
00181                 break;
00182 
00183         case 1://med
00184                 pain_chance *= 0.5f;
00185                 //return 0.35f;
00186                 break;
00187 
00188         case 2://hard
00189         default:
00190                 pain_chance *= 0.1f;
00191                 //return 0.05f;
00192                 break;
00193         }
00194         //Com_Printf( "%s: %4.2f\n", self->NPC_type, pain_chance );
00195         return pain_chance;
00196 }

void NPC_Pain gentity_t self,
gentity_t attacker,
int  damage
 

Definition at line 363 of file NPC_reactions.c.

References gNPC_t::behaviorState, gNPC_t::blockedSpeechDebounceTime, BS_DEFAULT, BSET_FFIRE, BSET_FLEE, BSET_PAIN, gNPC_t::charmedTime, gentity_s::client, gNPC_t::confusionTime, gNPC_t::defaultBehavior, gentity_s::enemy, EV_FFTURN, EV_FFWARN, gNPC_t::ffireCount, FL_NOTARGET, gentity_s::flags, G_ActivateBehavior(), G_SetEnemy(), g_spskill, G_UseTargets2(), gentity_t, gPainHitLoc, gPainMOD, gPainPoint, gentity_s::health, gNPC_t::ignorePain, vmCvar_t::integer, killPlayerTimer, level, gentity_s::NPC, NPC, NPC_ChoosePainAnimation(), NPCInfo, NULL, entityState_s::number, gentity_s::paintarget, gclient_s::playerTeam, PM_DEAD, playerState_s::pm_type, gclient_s::ps, Q_irand(), qfalse, gentity_s::r, RestoreNPCGlobals(), gentity_s::s, SaveNPCGlobals(), SCF_CHASE_ENEMIES, SCF_CROUCHED, SCF_DONT_FIRE, SCF_FORCED_MARCH, SCF_NO_COMBAT_TALK, SCF_NO_MIND_TRICK, SCF_WALKING, gNPC_t::scriptFlags, SetNPCGlobals(), STAT_MAX_HEALTH, playerState_s::stats, SVF_ICARUS_FREEZE, entityShared_t::svFlags, TEAM_FREE, team_t, gNPC_t::tempBehavior, level_locals_t::time, vec3_t, and VectorCopy.

Referenced by NPC_ATST_Pain(), NPC_Droid_Pain(), NPC_GM_Pain(), NPC_Grenadier_Pain(), NPC_Jedi_Pain(), NPC_Mark1_Pain(), NPC_Mark2_Pain(), NPC_Probe_Pain(), NPC_Remote_Pain(), NPC_Seeker_Pain(), NPC_Sentry_Pain(), NPC_Sniper_Pain(), and NPC_ST_Pain().

00364 {
00365         team_t otherTeam = TEAM_FREE;
00366         int             voiceEvent = -1;
00367         gentity_t *other = attacker;
00368         int mod = gPainMOD;
00369         int hitLoc = gPainHitLoc;
00370         vec3_t point;
00371 
00372         VectorCopy(gPainPoint, point);
00373 
00374         if ( self->NPC == NULL ) 
00375                 return;
00376 
00377         if ( other == NULL ) 
00378                 return;
00379 
00380         //or just remove ->pain in player_die?
00381         if ( self->client->ps.pm_type == PM_DEAD )
00382                 return;
00383 
00384         if ( other == self ) 
00385                 return;
00386 
00387         //MCG: Ignore damage from your own team for now
00388         if ( other->client )
00389         {
00390                 otherTeam = other->client->playerTeam;
00391         //      if ( otherTeam == TEAM_DISGUISE )
00392         //      {
00393         //              otherTeam = TEAM_PLAYER;
00394         //      }
00395         }
00396 
00397         if ( self->client->playerTeam 
00398                 && other->client 
00399                 && otherTeam == self->client->playerTeam 
00400         /*      && (!player->client->ps.viewEntity || other->s.number != player->client->ps.viewEntity)*/) 
00401         //rwwFIXMEFIXME: Will need modification when player controllable npcs are done
00402         {//hit by a teammate
00403                 if ( other != self->enemy && self != other->enemy )
00404                 {//we weren't already enemies
00405                         if ( self->enemy || other->enemy 
00406                                 
00407                                 //|| (other->s.number&&other->s.number!=player->client->ps.viewEntity) 
00408                                 //rwwFIXMEFIXME: same
00409 
00410                                 /*|| (!other->s.number&&Q_irand( 0, 3 ))*/ )
00411                         {//if one of us actually has an enemy already, it's okay, just an accident OR wasn't hit by player or someone controlled by player OR player hit ally and didn't get 25% chance of getting mad (FIXME:accumulate anger+base on diff?)
00412                                 //FIXME: player should have to do a certain amount of damage to ally or hit them several times to make them mad
00413                                 //Still run pain and flee scripts
00414                                 if ( self->client && self->NPC )
00415                                 {//Run any pain instructions
00416                                         if ( self->health <= (self->client->ps.stats[STAT_MAX_HEALTH]/3) && G_ActivateBehavior(self, BSET_FLEE) )
00417                                         {
00418                                                 
00419                                         }
00420                                         else// if( VALIDSTRING( self->behaviorSet[BSET_PAIN] ) )
00421                                         {
00422                                                 G_ActivateBehavior(self, BSET_PAIN);
00423                                         }
00424                                 }
00425                                 if ( damage != -1 )
00426                                 {//-1 == don't play pain anim
00427                                         //Set our proper pain animation
00428                                         if ( Q_irand( 0, 1 ) )
00429                                         {
00430                                                 NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, EV_FFWARN );
00431                                         }
00432                                         else
00433                                         {
00434                                                 NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, -1 );
00435                                         }
00436                                 }
00437                                 return;
00438                         }
00439                         else if ( self->NPC && !other->s.number )//should be assumed, but...
00440                         {//dammit, stop that!
00441                                 if ( self->NPC->charmedTime )
00442                                 {//mindtricked
00443                                         return;
00444                                 }
00445                                 else if ( self->NPC->ffireCount < 3+((2-g_spskill.integer)*2) )
00446                                 {//not mad enough yet
00447                                         //Com_Printf( "chck: %d < %d\n", self->NPC->ffireCount, 3+((2-g_spskill.integer)*2) );
00448                                         if ( damage != -1 )
00449                                         {//-1 == don't play pain anim
00450                                                 //Set our proper pain animation
00451                                                 if ( Q_irand( 0, 1 ) )
00452                                                 {
00453                                                         NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, EV_FFWARN );
00454                                                 }
00455                                                 else
00456                                                 {
00457                                                         NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, -1 );
00458                                                 }
00459                                         }
00460                                         return;
00461                                 }
00462                                 else if ( G_ActivateBehavior( self, BSET_FFIRE ) )
00463                                 {//we have a specific script to run, so do that instead
00464                                         return;
00465                                 }
00466                                 else
00467                                 {//okay, we're going to turn on our ally, we need to set and lock our enemy and put ourselves in a bstate that lets us attack him (and clear any flags that would stop us)
00468                                         self->NPC->blockedSpeechDebounceTime = 0;
00469                                         voiceEvent = EV_FFTURN;
00470                                         self->NPC->behaviorState = self->NPC->tempBehavior = self->NPC->defaultBehavior = BS_DEFAULT;
00471                                         other->flags &= ~FL_NOTARGET;
00472                                         //self->svFlags &= ~(SVF_IGNORE_ENEMIES|SVF_ICARUS_FREEZE|SVF_NO_COMBAT_SOUNDS);
00473                                         self->r.svFlags &= ~SVF_ICARUS_FREEZE;
00474                                         G_SetEnemy( self, other );
00475                                         //self->svFlags |= SVF_LOCKEDENEMY; //rwwFIXMEFIXME: proper support for these flags.
00476                                         self->NPC->scriptFlags &= ~(SCF_DONT_FIRE|SCF_CROUCHED|SCF_WALKING|SCF_NO_COMBAT_TALK|SCF_FORCED_MARCH);
00477                                         self->NPC->scriptFlags |= (SCF_CHASE_ENEMIES|SCF_NO_MIND_TRICK);
00478                                         //NOTE: we also stop ICARUS altogether
00479                                         //stop_icarus = qtrue;
00480                                         //rwwFIXMEFIXME: stop icarus?
00481                                         if ( !killPlayerTimer )
00482                                         {
00483                                                 killPlayerTimer = level.time + 10000;
00484                                         }
00485                                 }
00486                         }
00487                 }
00488         }
00489 
00490         SaveNPCGlobals();
00491         SetNPCGlobals( self );
00492 
00493         //Do extra bits
00494         if ( NPCInfo->ignorePain == qfalse )
00495         {
00496                 NPCInfo->confusionTime = 0;//clear any charm or confusion, regardless
00497                 if ( damage != -1 )
00498                 {//-1 == don't play pain anim
00499                         //Set our proper pain animation
00500                         NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, voiceEvent );
00501                 }
00502                 //Check to take a new enemy
00503                 if ( NPC->enemy != other && NPC != other )
00504                 {//not already mad at them
00505                         NPC_CheckAttacker( other, mod );
00506                 }
00507         }
00508 
00509         //Attempt to run any pain instructions
00510         if ( self->client && self->NPC )
00511         {
00512                 //FIXME: This needs better heuristics perhaps
00513                 if(self->health <= (self->client->ps.stats[STAT_MAX_HEALTH]/3) && G_ActivateBehavior(self, BSET_FLEE) )
00514                 {
00515                 }
00516                 else //if( VALIDSTRING( self->behaviorSet[BSET_PAIN] ) )
00517                 {
00518                         G_ActivateBehavior(self, BSET_PAIN);
00519                 }
00520         }
00521 
00522         //Attempt to fire any paintargets we might have
00523         if( self->paintarget && self->paintarget[0] )
00524         {
00525                 G_UseTargets2(self, other, self->paintarget);
00526         }
00527 
00528         RestoreNPCGlobals();
00529 }

void NPC_Respond gentity_t self,
int  userNum
 

Definition at line 690 of file NPC_reactions.c.

References CHAN_AUTO, CLASS_BESPIN_COP, CLASS_GONK, CLASS_JAN, CLASS_JEDI, CLASS_LANDO, CLASS_LUKE, CLASS_MOUSE, CLASS_PRISONER, CLASS_R2D2, CLASS_R5D2, CLASS_REBEL, gentity_s::client, gentity_s::enemy, EV_ANGER1, EV_ANGER3, EV_CHASE1, EV_CHASE3, EV_CONFUSE1, EV_COVER1, EV_COVER5, EV_DETECTED1, EV_DETECTED5, EV_ESCAPING2, EV_GIVEUP3, EV_GIVEUP4, EV_JDETECTED1, EV_JDETECTED2, EV_LOST1, EV_OUTFLANK1, EV_OUTFLANK2, EV_SIGHT1, EV_SIGHT2, EV_SIGHT3, EV_SOUND1, EV_SOUND3, EV_SUSPICIOUS4, EV_TAUNT1, EV_TAUNT2, G_AddVoiceEvent(), G_Sound(), G_SoundIndex(), gentity_t, gentity_s::NPC, gclient_s::NPC_class, NPC_TempLookTarget(), gentity_s::NPC_type, Q_irand(), Q_stricmp(), qboolean, SCF_NO_COMBAT_TALK, gNPC_t::scriptFlags, and va().

Referenced by NPC_UseResponse().

00691 {
00692         int event = -1;
00693         /*
00694 
00695         if ( Q_irand( 0, 1 ) )
00696         {
00697                 event = Q_irand(EV_RESPOND1, EV_RESPOND3);
00698         }
00699         else
00700         {
00701                 event = Q_irand(EV_BUSY1, EV_BUSY3);
00702         }
00703         */
00704 
00705         if ( !Q_irand( 0, 1 ) )
00706         {//set looktarget to them for a second or two
00707                 NPC_TempLookTarget( self, userNum, 1000, 3000 );
00708         }
00709 
00710         //some last-minute hacked in responses
00711         switch ( self->client->NPC_class )
00712         {
00713         case CLASS_JAN:
00714                 if ( self->enemy )
00715                 {
00716                         if ( !Q_irand( 0, 2 ) )
00717                         {
00718                                 event = Q_irand( EV_CHASE1, EV_CHASE3 );
00719                         }
00720                         else if ( Q_irand( 0, 1 ) )
00721                         {
00722                                 event = Q_irand( EV_OUTFLANK1, EV_OUTFLANK2 );
00723                         }
00724                         else
00725                         {
00726                                 event = Q_irand( EV_COVER1, EV_COVER5 );
00727                         }
00728                 }
00729                 else if ( !Q_irand( 0, 2 ) )
00730                 {
00731                         event = EV_SUSPICIOUS4;
00732                 }
00733                 else if ( !Q_irand( 0, 1 ) )
00734                 {
00735                         event = EV_SOUND1;
00736                 }
00737                 else
00738                 {
00739                         event = EV_CONFUSE1;
00740                 }
00741                 break;
00742         case CLASS_LANDO:
00743                 if ( self->enemy )
00744                 {
00745                         if ( !Q_irand( 0, 2 ) )
00746                         {
00747                                 event = Q_irand( EV_CHASE1, EV_CHASE3 );
00748                         }
00749                         else if ( Q_irand( 0, 1 ) )
00750                         {
00751                                 event = Q_irand( EV_OUTFLANK1, EV_OUTFLANK2 );
00752                         }
00753                         else
00754                         {
00755                                 event = Q_irand( EV_COVER1, EV_COVER5 );
00756                         }
00757                 }
00758                 else if ( !Q_irand( 0, 6 ) )
00759                 {
00760                         event = EV_SIGHT2;
00761                 }
00762                 else if ( !Q_irand( 0, 5 ) )
00763                 {
00764                         event = EV_GIVEUP4;
00765                 }
00766                 else if ( Q_irand( 0, 4 ) > 1 )
00767                 {
00768                         event = Q_irand( EV_SOUND1, EV_SOUND3 );
00769                 }
00770                 else
00771                 {
00772                         event = Q_irand( EV_JDETECTED1, EV_JDETECTED2 );
00773                 }
00774                 break;
00775         case CLASS_LUKE:
00776                 if ( self->enemy )
00777                 {
00778                         event = EV_COVER1;
00779                 }
00780                 else
00781                 {
00782                         event = Q_irand( EV_SOUND1, EV_SOUND3 );
00783                 }
00784                 break;
00785         case CLASS_JEDI:
00786                 if ( !self->enemy )
00787                 {
00788                         /*
00789                         if ( !(self->svFlags&SVF_IGNORE_ENEMIES) 
00790                                 && (self->NPC->scriptFlags&SCF_LOOK_FOR_ENEMIES)
00791                                 && self->client->enemyTeam == TEAM_ENEMY )
00792                                 */
00793                         if (0) //rwwFIXMEFIXME: support flags!
00794                         {
00795                                 event = Q_irand( EV_ANGER1, EV_ANGER3 );
00796                         }
00797                         else
00798                         {
00799                                 event = Q_irand( EV_TAUNT1, EV_TAUNT2 );
00800                         }
00801                 }
00802                 break;
00803         case CLASS_PRISONER:
00804                 if ( self->enemy )
00805                 {
00806                         if ( Q_irand( 0, 1 ) )
00807                         {
00808                                 event = Q_irand( EV_CHASE1, EV_CHASE3 );
00809                         }
00810                         else
00811                         {
00812                                 event = Q_irand( EV_OUTFLANK1, EV_OUTFLANK2 );
00813                         }
00814                 }
00815                 else
00816                 {
00817                         event = Q_irand( EV_SOUND1, EV_SOUND3 );
00818                 }
00819                 break;
00820         case CLASS_REBEL:
00821                 if ( self->enemy )
00822                 {
00823                         if ( !Q_irand( 0, 2 ) )
00824                         {
00825                                 event = Q_irand( EV_CHASE1, EV_CHASE3 );
00826                         }
00827                         else
00828                         {
00829                                 event = Q_irand( EV_DETECTED1, EV_DETECTED5 );
00830                         }
00831                 }
00832                 else
00833                 {
00834                         event = Q_irand( EV_SOUND1, EV_SOUND3 );
00835                 }
00836                 break;
00837         case CLASS_BESPIN_COP:
00838                 if ( !Q_stricmp( "bespincop", self->NPC_type ) )
00839                 {//variant 1
00840                         if ( self->enemy )
00841                         {
00842                                 if ( Q_irand( 0, 9 ) > 6 )
00843                                 {
00844                                         event = Q_irand( EV_CHASE1, EV_CHASE3 );
00845                                 }
00846                                 else if ( Q_irand( 0, 6 ) > 4 )
00847                                 {
00848                                         event = Q_irand( EV_OUTFLANK1, EV_OUTFLANK2 );
00849                                 }
00850                                 else
00851                                 {
00852                                         event = Q_irand( EV_COVER1, EV_COVER5 );
00853                                 }
00854                         }
00855                         else if ( !Q_irand( 0, 3 ) )
00856                         {
00857                                 event = Q_irand( EV_SIGHT2, EV_SIGHT3 );
00858                         }
00859                         else if ( !Q_irand( 0, 1 ) )
00860                         {
00861                                 event = Q_irand( EV_SOUND1, EV_SOUND3 );
00862                         }
00863                         else if ( !Q_irand( 0, 2 ) )
00864                         {
00865                                 event = EV_LOST1;
00866                         }
00867                         else if ( !Q_irand( 0, 1 ) )
00868                         {
00869                                 event = EV_ESCAPING2;
00870                         }
00871                         else
00872                         {
00873                                 event = EV_GIVEUP4;
00874                         }
00875                 }
00876                 else
00877                 {//variant2
00878                         if ( self->enemy )
00879                         {
00880                                 if ( Q_irand( 0, 9 ) > 6 )
00881                                 {
00882                                         event = Q_irand( EV_CHASE1, EV_CHASE3 );
00883                                 }
00884                                 else if ( Q_irand( 0, 6 ) > 4 )
00885                                 {
00886                                         event = Q_irand( EV_OUTFLANK1, EV_OUTFLANK2 );
00887                                 }
00888                                 else
00889                                 {
00890                                         event = Q_irand( EV_COVER1, EV_COVER5 );
00891                                 }
00892                         }
00893                         else if ( !Q_irand( 0, 3 ) )
00894                         {
00895                                 event = Q_irand( EV_SIGHT1, EV_SIGHT2 );
00896                         }
00897                         else if ( !Q_irand( 0, 1 ) )
00898                         {
00899                                 event = Q_irand( EV_SOUND1, EV_SOUND3 );
00900                         }
00901                         else if ( !Q_irand( 0, 2 ) )
00902                         {
00903                                 event = EV_LOST1;
00904                         }
00905                         else if ( !Q_irand( 0, 1 ) )
00906                         {
00907                                 event = EV_GIVEUP3;
00908                         }
00909                         else
00910                         {
00911                                 event = EV_CONFUSE1;
00912                         }
00913                 }
00914                 break;
00915         case CLASS_R2D2:                                // droid
00916                 G_Sound(self, CHAN_AUTO, G_SoundIndex(va("sound/chars/r2d2/misc/r2d2talk0%d.wav",Q_irand(1, 3))));
00917                 break;
00918         case CLASS_R5D2:                                // droid
00919                 G_Sound(self, CHAN_AUTO, G_SoundIndex(va("sound/chars/r5d2/misc/r5talk%d.wav",Q_irand(1, 4))));
00920                 break;
00921         case CLASS_MOUSE:                               // droid
00922                 G_Sound(self, CHAN_AUTO, G_SoundIndex(va("sound/chars/mouse/misc/mousego%d.wav",Q_irand(1, 3))));
00923                 break;
00924         case CLASS_GONK:                                // droid
00925                 G_Sound(self, CHAN_AUTO, G_SoundIndex(va("sound/chars/gonk/misc/gonktalk%d.wav",Q_irand(1, 2))));
00926                 break;
00927         }
00928         
00929         if ( event != -1 )
00930         {
00931                 //hack here because we reuse some "combat" and "extra" sounds
00932                 qboolean addFlag = (self->NPC->scriptFlags&SCF_NO_COMBAT_TALK);
00933                 self->NPC->scriptFlags &= ~SCF_NO_COMBAT_TALK;
00934 
00935                 G_AddVoiceEvent( self, event, 3000 );
00936 
00937                 if ( addFlag )
00938                 {
00939                         self->NPC->scriptFlags |= SCF_NO_COMBAT_TALK;
00940                 }
00941         }
00942 }

void NPC_SetLookTarget gentity_t self,
int  entNum,
int  clearTime
 

Definition at line 1632 of file NPC_utils.c.

01633 {
01634         if ( !self->client )
01635         {
01636                 return;
01637         }
01638 
01639         if ( (self->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
01640         {//lookTarget is set by and to the monster that's holding you, no other operations can change that
01641                 return;
01642         }
01643 
01644         self->client->renderInfo.lookTarget = entNum;
01645         self->client->renderInfo.lookTargetClearTime = clearTime;
01646 }

void NPC_SetPainEvent gentity_t self  ) 
 

Definition at line 133 of file NPC_reactions.c.

References gNPC_t::aiFlags, gentity_s::client, EV_PAIN, floor(), G_AddEvent(), gentity_t, gentity_s::health, gentity_s::NPC, NPCAI_DIE_ON_IMPACT, gclient_s::ps, STAT_MAX_HEALTH, playerState_s::stats, TID_CHAN_VOICE, and trap_ICARUS_TaskIDPending().

Referenced by NPC_ChoosePainAnimation(), and NPC_GM_Pain().

00134 {
00135         if ( !self->NPC || !(self->NPC->aiFlags&NPCAI_DIE_ON_IMPACT) )
00136         {
00137         // no more borg
00138         //      if( self->client->playerTeam != TEAM_BORG )
00139         //      {
00140                         //if ( !Q3_TaskIDPending( self, TID_CHAN_VOICE ) )
00141                         if (!trap_ICARUS_TaskIDPending(self, TID_CHAN_VOICE) && self->client)
00142                         {
00143                                 //G_AddEvent( self, EV_PAIN, floor((float)self->health/self->max_health*100.0f) );
00144                                 G_AddEvent( self, EV_PAIN, floor((float)self->health/self->client->ps.stats[STAT_MAX_HEALTH]*100.0f) );
00145                                 //rwwFIXMEFIXME: Do this properly?
00146                         }
00147         //      }
00148         }
00149 }

qboolean NPC_SomeoneLookingAtMe gentity_t ent  ) 
 

Definition at line 1042 of file NPC_utils.c.

References gentity_s::client, entityShared_t::currentOrigin, g_entities, gentity_t, InFOV(), gentity_s::inuse, MAX_CLIENTS, playerState_s::pm_flags, PMF_FOLLOW, gclient_s::ps, qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, gclient_s::sess, clientSession_t::sessionTeam, TEAM_SPECTATOR, trap_InPVS(), entityState_s::weapon, and WP_NONE.

Referenced by Jedi_CheckAmbushPlayer(), NPC_BSDefault(), and NPC_CheckSurrender().

01043 {
01044         int i = 0;
01045         gentity_t *pEnt;
01046 
01047         while (i < MAX_CLIENTS)
01048         {
01049                 pEnt = &g_entities[i];
01050 
01051                 if (pEnt && pEnt->inuse && pEnt->client && pEnt->client->sess.sessionTeam != TEAM_SPECTATOR &&
01052                         !(pEnt->client->ps.pm_flags & PMF_FOLLOW) && pEnt->s.weapon != WP_NONE)
01053                 {
01054                         if (trap_InPVS(ent->r.currentOrigin, pEnt->r.currentOrigin))
01055                         {
01056                                 if (InFOV( ent, pEnt, 30, 30 ))
01057                                 { //I'm in a 30 fov or so cone from this player.. that's enough I guess.
01058                                         return qtrue;
01059                                 }
01060                         }
01061                 }
01062 
01063                 i++;
01064         }
01065 
01066         return qfalse;
01067 }

void NPC_TempLookTarget gentity_t self,
int  lookEntNum,
int  minLookTime,
int  maxLookTime
 

Definition at line 661 of file NPC_reactions.c.

References gentity_s::client, EF2_HELD_BY_MONSTER, playerState_s::eFlags2, gentity_t, level, NPC_CheckLookTarget(), NPC_SetLookTarget(), gclient_s::ps, Q_irand(), and level_locals_t::time.

Referenced by NPC_CheckEnemyStealth(), and NPC_Respond().

00662 {
00663         if ( !self->client )
00664         {
00665                 return;
00666         }
00667 
00668         if ( (self->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
00669         {//lookTarget is set by and to the monster that's holding you, no other operations can change that
00670                 return;
00671         }
00672 
00673         if ( !minLookTime )
00674         {
00675                 minLookTime = 1000;
00676         }
00677 
00678         if ( !maxLookTime )
00679         {
00680                 maxLookTime = 1000;
00681         }
00682 
00683         if ( !NPC_CheckLookTarget( self ) )
00684         {//Not already looking at something else
00685                 //Look at him for 1 to 3 seconds
00686                 NPC_SetLookTarget( self, lookEntNum, level.time + Q_irand( minLookTime, maxLookTime ) );
00687         }
00688 }

void NPC_Touch gentity_t self,
gentity_t other,
trace_t trace
 

Definition at line 537 of file NPC_reactions.c.

References gNPC_t::aiFlags, gNPC_t::behaviorState, BS_HUNT_AND_KILL, gentity_s::client, gentity_s::enemy, gclient_s::enemyTeam, FL_NOTARGET, gentity_s::flags, G_SetEnemy(), gentity_t, gNPC_t::goalEntity, gentity_s::health, MAX_CLIENTS, gentity_s::message, NPC, gentity_s::NPC, NPCAI_TOUCHED_GOAL, NPCInfo, entityState_s::number, gclient_s::playerTeam, RestoreNPCGlobals(), gentity_s::s, SaveNPCGlobals(), SetNPCGlobals(), gNPC_t::tempBehavior, and gNPC_t::touchedByPlayer.

Referenced by NPC_TouchFunc().

00538 {
00539         if(!self->NPC)
00540                 return;
00541 
00542         SaveNPCGlobals();
00543         SetNPCGlobals( self );
00544 
00545         if ( self->message && self->health <= 0 )
00546         {//I am dead and carrying a key
00547                 //if ( other && player && player->health > 0 && other == player )
00548                 if (other && other->client && other->s.number < MAX_CLIENTS)
00549                 {//player touched me
00550                         /*
00551                         char *text;
00552                         qboolean        keyTaken;
00553                         //give him my key
00554                         if ( Q_stricmp( "goodie", self->message ) == 0 )
00555                         {//a goodie key
00556                                 if ( (keyTaken = INV_GoodieKeyGive( other )) == qtrue )
00557                                 {
00558                                         text = "cp @SP_INGAME_TOOK_IMPERIAL_GOODIE_KEY";
00559                                         G_AddEvent( other, EV_ITEM_PICKUP, (FindItemForInventory( INV_GOODIE_KEY )-bg_itemlist) );
00560                                 }
00561                                 else
00562                                 {
00563                                         text = "cp @SP_INGAME_CANT_CARRY_GOODIE_KEY";
00564                                 }
00565                         }
00566                         else
00567                         {//a named security key
00568                                 if ( (keyTaken = INV_SecurityKeyGive( player, self->message )) == qtrue )
00569                                 {
00570                                         text = "cp @SP_INGAME_TOOK_IMPERIAL_SECURITY_KEY";
00571                                         G_AddEvent( other, EV_ITEM_PICKUP, (FindItemForInventory( INV_SECURITY_KEY )-bg_itemlist) );
00572                                 }
00573                                 else
00574                                 {
00575                                         text = "cp @SP_INGAME_CANT_CARRY_SECURITY_KEY";
00576                                 }
00577                         }
00578                         */
00579                         //rwwFIXMEFIXME: support for goodie/security keys?
00580                         /*
00581                         if ( keyTaken )
00582                         {//remove my key
00583                                 NPC_SetSurfaceOnOff( self, "l_arm_key", 0x00000002 );
00584                                 self->message = NULL;
00585                                 //FIXME: temp pickup sound
00586                                 G_Sound( player, G_SoundIndex( "sound/weapons/key_pkup.wav" ) );
00587                                 //FIXME: need some event to pass to cgame for sound/graphic/message?
00588                         }
00589                         //FIXME: temp message
00590                         gi.SendServerCommand( NULL, text );
00591                         */
00592                 }
00593         }
00594 
00595         if ( other->client ) 
00596         {//FIXME:  if pushing against another bot, both ucmd.rightmove = 127???
00597                 //Except if not facing one another...
00598                 if ( other->health > 0 ) 
00599                 {
00600                         NPCInfo->touchedByPlayer = other;
00601                 }
00602 
00603                 if ( other == NPCInfo->goalEntity ) 
00604                 {
00605                         NPCInfo->aiFlags |= NPCAI_TOUCHED_GOAL;
00606                 }
00607 
00608                 if(  !(other->flags & FL_NOTARGET) )
00609                 {
00610                         if ( self->client->enemyTeam )
00611                         {//See if we bumped into an enemy
00612                                 if ( other->client->playerTeam == self->client->enemyTeam )
00613                                 {//bumped into an enemy
00614                                         if( NPCInfo->behaviorState != BS_HUNT_AND_KILL && !NPCInfo->tempBehavior )
00615                                         {//MCG - Begin: checking specific BS mode here, this is bad, a HACK
00616                                                 //FIXME: not medics?
00617                                                 if ( NPC->enemy != other )
00618                                                 {//not already mad at them
00619                                                         G_SetEnemy( NPC, other );
00620                                                 }
00621                 //                              NPCInfo->tempBehavior = BS_HUNT_AND_KILL;
00622                                         }
00623                                 }
00624                         }
00625                 }
00626 
00627                 //FIXME: do this if player is moving toward me and with a certain dist?
00628                 /*
00629                 if ( other->s.number == 0 && self->client->playerTeam == other->client->playerTeam )
00630                 {
00631                         VectorAdd( self->client->pushVec, other->client->ps.velocity, self->client->pushVec );
00632                 }
00633                 */
00634         }
00635         else 
00636         {//FIXME: check for SVF_NONNPC_ENEMY flag here?
00637                 if ( other->health > 0 ) 
00638                 {
00639                         //if ( NPC->enemy == other && (other->svFlags&SVF_NONNPC_ENEMY) )
00640                         if (0) //rwwFIXMEFIXME: Can probably just check if num < MAX_CLIENTS for non-npc enemy stuff
00641                         {
00642                                 NPCInfo->touchedByPlayer = other;
00643                         }
00644                 }
00645 
00646                 if ( other == NPCInfo->goalEntity ) 
00647                 {
00648                         NPCInfo->aiFlags |= NPCAI_TOUCHED_GOAL;
00649                 }
00650         }
00651 
00652         RestoreNPCGlobals();
00653 }

void NPC_Use gentity_t self,
gentity_t other,
gentity_t activator
 

Definition at line 1008 of file NPC_reactions.c.

References gentity_s::behaviorSet, bgEntity_t, vehicleInfo_t::Board, BSET_USE, CLASS_GONK, CLASS_VEHICLE, gentity_s::client, vehicleInfo_t::Eject, vehicleInfo_t::EjectAll, gentity_s::enemy, gentity_t, Jedi_Ambush(), Jedi_WaitingAmbush(), gentity_s::m_pVehicle, Vehicle_s::m_pVehicleInfo, NPC, gentity_s::NPC, gclient_s::NPC_class, NPC_UseResponse(), entityState_s::number, entityState_s::owner, PM_DEAD, playerState_s::pm_type, gclient_s::ps, qfalse, qtrue, RestoreNPCGlobals(), gentity_s::s, SaveNPCGlobals(), SCF_NO_RESPONSE, gNPC_t::scriptFlags, SetNPCGlobals(), and Vehicle_t.

Referenced by NPC_Begin().

01009 {
01010         if (self->client->ps.pm_type == PM_DEAD)
01011         {//or just remove ->pain in player_die?
01012                 return;
01013         }
01014 
01015         SaveNPCGlobals();
01016         SetNPCGlobals( self );
01017 
01018         if(self->client && self->NPC)
01019         {
01020                 // If this is a vehicle, let the other guy board it. Added 12/14/02 by AReis.
01021                 if ( self->client->NPC_class == CLASS_VEHICLE )
01022                 {
01023                         Vehicle_t *pVeh = self->m_pVehicle;
01024 
01025                         if ( pVeh && pVeh->m_pVehicleInfo )
01026                         {
01027                                 //if I used myself, eject everyone on me
01028                                 if ( other == self )
01029                                 {
01030                                         pVeh->m_pVehicleInfo->EjectAll( pVeh );
01031                                 }
01032                                 // If other is already riding this vehicle (self), eject him.
01033                                 else if ( other->s.owner == self->s.number )
01034                                 {
01035                                         pVeh->m_pVehicleInfo->Eject( pVeh, (bgEntity_t *)other, qfalse );
01036                                 }
01037                                 // Otherwise board this vehicle.
01038                                 else
01039                                 {
01040                                         pVeh->m_pVehicleInfo->Board( pVeh, (bgEntity_t *)other );
01041                                 }
01042                         }
01043                 }
01044                 else if ( Jedi_WaitingAmbush( NPC ) )
01045                 {
01046                         Jedi_Ambush( NPC );
01047                 }
01048                 //Run any use instructions
01049                 if ( activator && activator->s.number == 0 && self->client->NPC_class == CLASS_GONK )
01050                 {
01051                         // must be using the gonk, so attempt to give battery power.
01052                         // NOTE: this will steal up to MAX_BATTERIES for the activator, leaving the residual on the gonk for potential later use.
01053 //                      Add_Batteries( activator, &self->client->ps.batteryCharge );
01054                         //rwwFIXMEFIXME: support for this?
01055                 }
01056                 // Not using MEDICs anymore
01057 /*
01058                 if ( self->NPC->behaviorState == BS_MEDIC_HIDE && activator->client )
01059                 {//Heal me NOW, dammit!
01060                         if ( activator->health < activator->client->ps.stats[STAT_MAX_HEALTH] )
01061                         {//person needs help
01062                                 if ( self->NPC->eventualGoal != activator )
01063                                 {//not my current patient already
01064                                         NPC_TakePatient( activator );
01065                                         G_ActivateBehavior( self, BSET_USE );
01066                                 }
01067                         }
01068                         else if ( !self->enemy && activator->s.number == 0 && !gi.VoiceVolume[self->s.number] && !(self->NPC->scriptFlags&SCF_NO_RESPONSE) )
01069                         {//I don't have an enemy and I'm not talking and I was used by the player
01070                                 NPC_UseResponse( self, other, qfalse );
01071                         }
01072                 }
01073 */
01074 //              else if ( self->behaviorSet[BSET_USE] )
01075                 if ( self->behaviorSet[BSET_USE] )
01076                 {
01077                         NPC_UseResponse( self, other, qtrue );
01078                 }
01079 //              else if ( isMedic( self ) )
01080 //              {//Heal me NOW, dammit!
01081 //                      NPC_TakePatient( activator );
01082 //              }
01083                 else if ( !self->enemy 
01084                         && activator->s.number == 0 
01085                         &&  !(self->NPC->scriptFlags&SCF_NO_RESPONSE) )
01086                         //rwwFIXMEFIXME: voice volume support?
01087                 {//I don't have an enemy and I'm not talking and I was used by the player
01088                         NPC_UseResponse( self, other, qfalse );
01089                 }
01090         }
01091 
01092         RestoreNPCGlobals();
01093 }

void NPC_UseResponse gentity_t self,
gentity_t user,
qboolean  useWhenDone
 

Definition at line 950 of file NPC_reactions.c.

References gNPC_t::blockedSpeechDebounceTime, BSET_USE, gentity_s::client, G_ActivateBehavior(), gentity_t, level, gentity_s::NPC, NPC_Respond(), NPCTEAM_NEUTRAL, entityState_s::number, gclient_s::playerTeam, gentity_s::s, and level_locals_t::time.

Referenced by ForceTelepathyCheckDirectNPCTarget(), and NPC_Use().

00951 {
00952         if ( !self->NPC || !self->client )
00953         {
00954                 return;
00955         }
00956 
00957         if ( user->s.number != 0 )
00958         {//not used by the player
00959                 if ( useWhenDone )
00960                 {
00961                         G_ActivateBehavior( self, BSET_USE );
00962                 }
00963                 return;
00964         }
00965 
00966         if ( user->client && self->client->playerTeam != user->client->playerTeam && self->client->playerTeam != NPCTEAM_NEUTRAL )
00967         {//only those on the same team react
00968                 if ( useWhenDone )
00969                 {
00970                         G_ActivateBehavior( self, BSET_USE );
00971                 }
00972                 return;
00973         }
00974 
00975         if ( self->NPC->blockedSpeechDebounceTime > level.time )
00976         {//I'm not responding right now
00977                 return;
00978         }
00979 
00980         /*
00981         if ( gi.VoiceVolume[self->s.number] )
00982         {//I'm talking already
00983                 if ( !useWhenDone )
00984                 {//you're not trying to use me
00985                         return;
00986                 }
00987         }
00988         */
00989         //rwwFIXMEFIXME: Support for this?
00990 
00991         if ( useWhenDone )
00992         {
00993                 G_ActivateBehavior( self, BSET_USE );
00994         }
00995         else
00996         {
00997                 NPC_Respond( self, user->s.number );
00998         }
00999 }

qboolean PM_InCartwheel int  anim  ) 
 

Definition at line 995 of file bg_panimate.c.

References BOTH_ARIAL_F1, BOTH_ARIAL_LEFT, BOTH_ARIAL_RIGHT, BOTH_CARTWHEEL_LEFT, BOTH_CARTWHEEL_RIGHT, qboolean, qfalse, and qtrue.

Referenced by NPC_ChoosePainAnimation().

00996 {
00997         switch ( anim )
00998         {
00999         case BOTH_ARIAL_LEFT:
01000         case BOTH_ARIAL_RIGHT:
01001         case BOTH_ARIAL_F1:
01002         case BOTH_CARTWHEEL_LEFT:
01003         case BOTH_CARTWHEEL_RIGHT:
01004                 return qtrue;
01005                 break;
01006         }
01007         return qfalse;
01008 }

qboolean PM_InKnockDown playerState_t ps  ) 
 

Definition at line 1216 of file bg_panimate.c.

References BOTH_FORCE_GETUP_B1, BOTH_FORCE_GETUP_B2, BOTH_FORCE_GETUP_B3, BOTH_FORCE_GETUP_B4, BOTH_FORCE_GETUP_B5, BOTH_FORCE_GETUP_F1, BOTH_FORCE_GETUP_F2, BOTH_GETUP1, BOTH_GETUP2, BOTH_GETUP3, BOTH_GETUP4, BOTH_GETUP5, BOTH_GETUP_BROLL_B, BOTH_GETUP_BROLL_F, BOTH_GETUP_BROLL_L, BOTH_GETUP_BROLL_R, BOTH_GETUP_FROLL_B, BOTH_GETUP_FROLL_F, BOTH_GETUP_FROLL_L, BOTH_GETUP_FROLL_R, BOTH_KNOCKDOWN1, BOTH_KNOCKDOWN2, BOTH_KNOCKDOWN3, BOTH_KNOCKDOWN4, BOTH_KNOCKDOWN5, playerState_s::legsAnim, playerState_s::legsTimer, playerState_t, qboolean, qfalse, and qtrue.

Referenced by CG_DrawActiveFrame(), Jedi_CheckFlipEvasions(), Jedi_SaberBlockGo(), NPC_CheckSurrender(), NPC_ChoosePainAnimation(), NPC_MoveToGoal(), NPC_Surrender(), PM_SetSaberMove(), PM_WeaponLightsaber(), WP_ResistForcePush(), and WP_SaberStartMissileBlockCheck().

01217 {
01218         switch ( (ps->legsAnim) )
01219         {
01220         case BOTH_KNOCKDOWN1:
01221         case BOTH_KNOCKDOWN2:
01222         case BOTH_KNOCKDOWN3:
01223         case BOTH_KNOCKDOWN4:
01224         case BOTH_KNOCKDOWN5:
01225                 return qtrue;
01226                 break;
01227         case BOTH_GETUP1:
01228         case BOTH_GETUP2:
01229         case BOTH_GETUP3:
01230         case BOTH_GETUP4:
01231         case BOTH_GETUP5:
01232         case BOTH_FORCE_GETUP_F1:
01233         case BOTH_FORCE_GETUP_F2:
01234         case BOTH_FORCE_GETUP_B1:
01235         case BOTH_FORCE_GETUP_B2:
01236         case BOTH_FORCE_GETUP_B3:
01237         case BOTH_FORCE_GETUP_B4:
01238         case BOTH_FORCE_GETUP_B5:
01239         case BOTH_GETUP_BROLL_B:
01240         case BOTH_GETUP_BROLL_F:
01241         case BOTH_GETUP_BROLL_L:
01242         case BOTH_GETUP_BROLL_R:
01243         case BOTH_GETUP_FROLL_B:
01244         case BOTH_GETUP_FROLL_F:
01245         case BOTH_GETUP_FROLL_L:
01246         case BOTH_GETUP_FROLL_R:
01247                 if ( ps->legsTimer )
01248                 {
01249                         return qtrue;
01250                 }
01251                 break;
01252         }
01253         return qfalse;
01254 }

qboolean PM_RollingAnim int  anim  ) 
 

Definition at line 4636 of file bg_pmove.c.

References BOTH_ROLL_B, BOTH_ROLL_F, BOTH_ROLL_L, BOTH_ROLL_R, qboolean, qfalse, and qtrue.

Referenced by Jedi_SaberBusy(), NPC_ChoosePainAnimation(), and WP_ResistForcePush().

04637 {
04638         switch ( anim )
04639         {
04640         case BOTH_ROLL_F:                       //# Roll forward
04641         case BOTH_ROLL_B:                       //# Roll backward
04642         case BOTH_ROLL_L:                       //# Roll left
04643         case BOTH_ROLL_R:                       //# Roll right
04644                 return qtrue;
04645                 break;
04646         }
04647         return qfalse;
04648 }

qboolean PM_SpinningAnim int  anim  ) 
 

Definition at line 1338 of file bg_panimate.c.

References BG_SpinningSaberAnim(), and qboolean.

Referenced by NPC_ChoosePainAnimation().

01339 {
01340         /*
01341         switch ( anim )
01342         {
01343         //FIXME: list any other spinning anims
01344         default:
01345                 break;
01346         }
01347         */
01348         return BG_SpinningSaberAnim( anim );
01349 }

qboolean PM_SpinningSaberAnim int  anim  ) 
 

qboolean Q3_TaskIDPending gentity_t ent,
taskID_t  taskType
 


Variable Documentation

int killPlayerTimer
 

Definition at line 29 of file NPC_reactions.c.

Referenced by NPC_Pain().

int teamLastEnemyTime[]
 

Definition at line 28 of file NPC_reactions.c.