codemp/game/NPC_AI_Jedi.c File Reference

#include "b_local.h"
#include "g_nav.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 MAX_VIEW_DIST   2048
#define MAX_VIEW_SPEED   100
#define JEDI_MAX_LIGHT_INTENSITY   64
#define JEDI_MIN_LIGHT_THRESHOLD   10
#define JEDI_MAX_LIGHT_THRESHOLD   50
#define DISTANCE_SCALE   0.25f
#define SPEED_SCALE   0.25f
#define FOV_SCALE   0.5f
#define LIGHT_SCALE   0.25f
#define REALIZE_THRESHOLD   0.6f
#define CAUTIOUS_THRESHOLD   ( REALIZE_THRESHOLD * 0.3 )
#define MAX_CHECK_THRESHOLD   1
#define APEX_HEIGHT   200.0f
#define PARA_WIDTH   (sqrt(APEX_HEIGHT)+sqrt(APEX_HEIGHT))
#define JUMP_SPEED   200.0f

Enumerations

enum  { LSTATE_NONE = 0, LSTATE_UNDERFIRE, LSTATE_INVESTIGATE }

Functions

qboolean BG_SabersOff (playerState_t *ps)
void CG_DrawAlert (vec3_t origin, float rating)
void G_AddVoiceEvent (gentity_t *self, int event, int speakDebounceTime)
void ForceJump (gentity_t *self, usercmd_t *ucmd)
void G_StartMatrixEffect (gentity_t *ent)
void NPC_ClearLookTarget (gentity_t *self)
void NPC_SetLookTarget (gentity_t *self, int entNum, int clearTime)
void NPC_TempLookTarget (gentity_t *self, int lookEntNum, int minLookTime, int maxLookTime)
qboolean G_ExpandPointToBBox (vec3_t point, const vec3_t mins, const vec3_t maxs, int ignore, int clipmask)
qboolean NPC_CheckEnemyStealth (void)
void G_SoundOnEnt (gentity_t *ent, soundChannel_t channel, const char *soundPath)
gitem_tBG_FindItemForAmmo (ammo_t ammo)
void ForceThrow (gentity_t *self, qboolean pull)
void ForceLightning (gentity_t *self)
void ForceHeal (gentity_t *self)
void ForceRage (gentity_t *self)
void ForceProtect (gentity_t *self)
void ForceAbsorb (gentity_t *self)
int WP_MissileBlockForBlock (int saberBlock)
qboolean G_GetHitLocFromSurfName (gentity_t *ent, const char *surfName, int *hitLoc, vec3_t point, vec3_t dir, vec3_t bladeDir, int mod)
qboolean WP_ForcePowerUsable (gentity_t *self, forcePowers_t forcePower, int overrideAmt)
qboolean WP_ForcePowerAvailable (gentity_t *self, forcePowers_t forcePower, int overrideAmt)
void WP_ForcePowerStop (gentity_t *self, forcePowers_t forcePower)
void WP_DeactivateSaber (gentity_t *self, qboolean clearLength)
void WP_ActivateSaber (gentity_t *self)
qboolean PM_SaberInStart (int move)
qboolean BG_SaberInSpecialAttack (int anim)
qboolean BG_SaberInAttack (int move)
qboolean PM_SaberInBounce (int move)
qboolean PM_SaberInParry (int move)
qboolean PM_SaberInKnockaway (int move)
qboolean PM_SaberInBrokenParry (int move)
qboolean PM_SaberInDeflect (int move)
qboolean BG_SpinningSaberAnim (int anim)
qboolean BG_FlippingAnim (int anim)
qboolean PM_RollingAnim (int anim)
qboolean PM_InKnockDown (playerState_t *ps)
qboolean BG_InRoll (playerState_t *ps, int anim)
qboolean BG_CrouchAnim (int anim)
qboolean NPC_SomeoneLookingAtMe (gentity_t *ent)
int WP_GetVelocityForForceJump (gentity_t *self, vec3_t jumpVel, usercmd_t *ucmd)
void G_TestLine (vec3_t start, vec3_t end, int color, int time)
qboolean Jedi_WaitingAmbush (gentity_t *self)
void NPC_ShadowTrooper_Precache (void)
void Jedi_ClearTimers (gentity_t *ent)
void Jedi_PlayBlockedPushSound (gentity_t *self)
void Jedi_PlayDeflectSound (gentity_t *self)
void NPC_Jedi_PlayConfusionSound (gentity_t *self)
void Boba_Precache (void)
void G_CreateG2AttachedWeaponModel (gentity_t *ent, const char *weaponModel, int boltNum, int weaponNum)
void ChangeWeapon (gentity_t *ent, int newWeapon)
void Boba_ChangeWeapon (int wp)
void WP_ResistForcePush (gentity_t *self, gentity_t *pusher, qboolean noPenalty)
qboolean Boba_StopKnockdown (gentity_t *self, gentity_t *pusher, vec3_t pushDir, qboolean forceKnockdown)
void Boba_FlyStart (gentity_t *self)
void Boba_FlyStop (gentity_t *self)
qboolean Boba_Flying (gentity_t *self)
void Boba_FireFlameThrower (gentity_t *self)
void Boba_StartFlameThrower (gentity_t *self)
void Boba_DoFlameThrower (gentity_t *self)
void Boba_FireDecide (void)
void Jedi_Cloak (gentity_t *self)
void Jedi_Decloak (gentity_t *self)
void Jedi_CheckCloak (void)
void NPC_Jedi_RateNewEnemy (gentity_t *self, gentity_t *enemy)
void Jedi_RageStop (gentity_t *self)
qboolean NPC_MoveDirClear (int forwardmove, int rightmove, qboolean reset)
evasionType_t Jedi_CheckFlipEvasions (gentity_t *self, float rightdot, float zdiff)
int Jedi_ReCalcParryTime (gentity_t *self, evasionType_t evasionType)
qboolean Jedi_QuickReactions (gentity_t *self)
qboolean Jedi_SaberBusy (gentity_t *self)
qboolean G_FindClosestPointOnLineSegment (const vec3_t start, const vec3_t end, const vec3_t from, vec3_t result)
evasionType_t Jedi_SaberBlockGo (gentity_t *self, usercmd_t *cmd, vec3_t pHitloc, vec3_t phitDir, gentity_t *incoming, float dist)
float ShortestLineSegBewteen2LineSegs (vec3_t start1, vec3_t end1, vec3_t start2, vec3_t end2, vec3_t close_pnt1, vec3_t close_pnt2)
int WPDEBUG_SaberColor (saber_colors_t saberColor)
gentity_tJedi_FindEnemyInCone (gentity_t *self, gentity_t *fallback, float minDot)
float WP_SpeedOfMissileForWeapon (int wp, qboolean alt_fire)
void G_UcmdMoveForDir (gentity_t *self, usercmd_t *cmd, vec3_t dir)
void NPC_Jedi_Pain (gentity_t *self, gentity_t *attacker, int damage)
qboolean Jedi_CheckDanger (void)
qboolean Jedi_CheckAmbushPlayer (void)
void Jedi_Ambush (gentity_t *self)
qboolean Jedi_CanPullBackSaber (gentity_t *self)
void NPC_BSJedi_FollowLeader (void)
void NPC_BSST_Patrol (void)
void NPC_BSSniper_Default (void)
void NPC_BSJedi_Default (void)

Variables

vmCvar_t g_saberRealisticCombat
vmCvar_t d_slowmodeath
int bg_parryDebounce []


Define Documentation

#define APEX_HEIGHT   200.0f
 

Definition at line 4469 of file NPC_AI_Jedi.c.

Referenced by NPC_BSJump().

#define CAUTIOUS_THRESHOLD   ( REALIZE_THRESHOLD * 0.3 )
 

Definition at line 34 of file NPC_AI_Jedi.c.

#define DISTANCE_SCALE   0.25f
 

Definition at line 27 of file NPC_AI_Jedi.c.

#define FOV_SCALE   0.5f
 

Definition at line 30 of file NPC_AI_Jedi.c.

#define JEDI_MAX_LIGHT_INTENSITY   64
 

Definition at line 23 of file NPC_AI_Jedi.c.

#define JEDI_MAX_LIGHT_THRESHOLD   50
 

Definition at line 25 of file NPC_AI_Jedi.c.

#define JEDI_MIN_LIGHT_THRESHOLD   10
 

Definition at line 24 of file NPC_AI_Jedi.c.

#define JUMP_SPEED   200.0f
 

Definition at line 4471 of file NPC_AI_Jedi.c.

#define LIGHT_SCALE   0.25f
 

Definition at line 31 of file NPC_AI_Jedi.c.

#define MAX_CHECK_THRESHOLD   1
 

Definition at line 36 of file NPC_AI_Jedi.c.

#define MAX_VIEW_DIST   2048
 

Definition at line 21 of file NPC_AI_Jedi.c.

#define MAX_VIEW_SPEED   100
 

Definition at line 22 of file NPC_AI_Jedi.c.

#define PARA_WIDTH   (sqrt(APEX_HEIGHT)+sqrt(APEX_HEIGHT))
 

Definition at line 4470 of file NPC_AI_Jedi.c.

#define REALIZE_THRESHOLD   0.6f
 

Definition at line 33 of file NPC_AI_Jedi.c.

#define SPEED_SCALE   0.25f
 

Definition at line 29 of file NPC_AI_Jedi.c.


Enumeration Type Documentation

anonymous enum
 

Enumeration values:
LSTATE_NONE 
LSTATE_UNDERFIRE 
LSTATE_INVESTIGATE 

Definition at line 96 of file NPC_AI_Jedi.c.

00097 {
00098         LSTATE_NONE = 0,
00099         LSTATE_UNDERFIRE,
00100         LSTATE_INVESTIGATE,
00101 };


Function Documentation

qboolean BG_CrouchAnim int  anim  ) 
 

Definition at line 49 of file bg_panimate.c.

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 }

gitem_t* BG_FindItemForAmmo ammo_t  ammo  ) 
 

Definition at line 1941 of file bg_misc.c.

01941                                            {
01942         gitem_t *it;
01943         
01944         for ( it = bg_itemlist + 1 ; it->classname ; it++) {
01945                 if ( it->giType == IT_AMMO && it->giTag == ammo ) {
01946                         return it;
01947                 }
01948         }
01949 
01950         Com_Error( ERR_DROP, "Couldn't find item for ammo %i", ammo);
01951         return NULL;
01952 }

qboolean BG_FlippingAnim int  anim  ) 
 

Definition at line 433 of file bg_panimate.c.

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_InRoll playerState_t ps,
int  anim
 

Definition at line 789 of file bg_panimate.c.

References 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_ROLL_B, BOTH_ROLL_F, BOTH_ROLL_L, BOTH_ROLL_R, playerState_s::legsTimer, playerState_t, qboolean, qfalse, and qtrue.

Referenced by BG_AdjustClientSpeed(), Jedi_CheckFlipEvasions(), Jedi_SaberBlockGo(), PM_ForceLegsAnim(), PM_SetSaberMove(), PM_WeaponLightsaber(), PmoveSingle(), and WP_SabersCheckLock().

00790 {
00791         switch ( (anim) )
00792         {
00793         case BOTH_GETUP_BROLL_B:
00794         case BOTH_GETUP_BROLL_F:
00795         case BOTH_GETUP_BROLL_L:
00796         case BOTH_GETUP_BROLL_R:
00797         case BOTH_GETUP_FROLL_B:
00798         case BOTH_GETUP_FROLL_F:
00799         case BOTH_GETUP_FROLL_L:
00800         case BOTH_GETUP_FROLL_R:
00801         case BOTH_ROLL_F:
00802         case BOTH_ROLL_B:
00803         case BOTH_ROLL_R:
00804         case BOTH_ROLL_L:
00805                 if ( ps->legsTimer > 0 )
00806                 {
00807                         return qtrue;
00808                 }
00809                 break;
00810         }
00811         return qfalse;
00812 }

qboolean BG_SaberInAttack int  move  ) 
 

Definition at line 227 of file bg_panimate.c.

References LS_A1_SPECIAL, LS_A2_SPECIAL, LS_A3_SPECIAL, LS_A_BACK, LS_A_BACK_CR, LS_A_BACKFLIP_ATK, LS_A_BACKSTAB, LS_A_FLIP_SLASH, LS_A_FLIP_STAB, LS_A_JUMP_T__B_, LS_A_LUNGE, LS_A_T2B, LS_A_TL2BR, LS_BUTTERFLY_LEFT, LS_BUTTERFLY_RIGHT, LS_DUAL_FB, LS_DUAL_LR, LS_DUAL_SPIN_PROTECT, LS_HILT_BASH, LS_JUMPATTACK_ARIAL_LEFT, LS_JUMPATTACK_ARIAL_RIGHT, LS_JUMPATTACK_CART_LEFT, LS_JUMPATTACK_CART_RIGHT, LS_JUMPATTACK_DUAL, LS_JUMPATTACK_STAFF_LEFT, LS_JUMPATTACK_STAFF_RIGHT, LS_KICK_B, LS_KICK_B_AIR, LS_KICK_BF, LS_KICK_F, LS_KICK_F_AIR, LS_KICK_L, LS_KICK_L_AIR, LS_KICK_R, LS_KICK_R_AIR, LS_KICK_RL, LS_KICK_S, LS_LEAP_ATTACK, LS_PULL_ATTACK_STAB, LS_PULL_ATTACK_SWING, LS_ROLL_STAB, LS_SPINATTACK, LS_SPINATTACK_ALORA, LS_SPINATTACK_DUAL, LS_STABDOWN, LS_STABDOWN_DUAL, LS_STABDOWN_STAFF, LS_STAFF_SOULCAL, LS_SWOOP_ATTACK_LEFT, LS_SWOOP_ATTACK_RIGHT, LS_TAUNTAUN_ATTACK_LEFT, LS_TAUNTAUN_ATTACK_RIGHT, LS_UPSIDE_DOWN_ATTACK, qboolean, qfalse, and qtrue.

Referenced by BG_AdjustClientSpeed(), CG_AddSaberBlade(), ClientThink_real(), G_SPSaberDamageTraceLerped(), Jedi_CheckFlipEvasions(), Jedi_SaberBlockGo(), Jedi_SaberBusy(), PM_SaberAttackForMovement(), PM_SetSaberMove(), PM_WeaponLightsaber(), WP_SaberCanBlock(), WP_SaberPositionUpdate(), and WP_SaberStartMissileBlockCheck().

00228 {
00229         if ( move >= LS_A_TL2BR && move <= LS_A_T2B )
00230         {
00231                 return qtrue;
00232         }
00233         switch ( move )
00234         {
00235         case LS_A_BACK:
00236         case LS_A_BACK_CR:
00237         case LS_A_BACKSTAB:
00238         case LS_ROLL_STAB:
00239         case LS_A_LUNGE:
00240         case LS_A_JUMP_T__B_:
00241         case LS_A_FLIP_STAB:
00242         case LS_A_FLIP_SLASH:
00243         case LS_JUMPATTACK_DUAL:
00244         case LS_JUMPATTACK_ARIAL_LEFT:
00245         case LS_JUMPATTACK_ARIAL_RIGHT:
00246         case LS_JUMPATTACK_CART_LEFT:
00247         case LS_JUMPATTACK_CART_RIGHT:
00248         case LS_JUMPATTACK_STAFF_LEFT:
00249         case LS_JUMPATTACK_STAFF_RIGHT:
00250         case LS_BUTTERFLY_LEFT:
00251         case LS_BUTTERFLY_RIGHT:
00252         case LS_A_BACKFLIP_ATK:
00253         case LS_SPINATTACK_DUAL:
00254         case LS_SPINATTACK:
00255         case LS_LEAP_ATTACK:
00256         case LS_SWOOP_ATTACK_RIGHT:
00257         case LS_SWOOP_ATTACK_LEFT:
00258         case LS_TAUNTAUN_ATTACK_RIGHT:
00259         case LS_TAUNTAUN_ATTACK_LEFT:
00260         case LS_KICK_F:
00261         case LS_KICK_B:
00262         case LS_KICK_R:
00263         case LS_KICK_L:
00264         case LS_KICK_S:
00265         case LS_KICK_BF:
00266         case LS_KICK_RL:
00267         case LS_KICK_F_AIR:
00268         case LS_KICK_B_AIR:
00269         case LS_KICK_R_AIR:
00270         case LS_KICK_L_AIR:
00271         case LS_STABDOWN:
00272         case LS_STABDOWN_STAFF:
00273         case LS_STABDOWN_DUAL:
00274         case LS_DUAL_SPIN_PROTECT:
00275         case LS_STAFF_SOULCAL:
00276         case LS_A1_SPECIAL:
00277         case LS_A2_SPECIAL:
00278         case LS_A3_SPECIAL:
00279         case LS_UPSIDE_DOWN_ATTACK:
00280         case LS_PULL_ATTACK_STAB:
00281         case LS_PULL_ATTACK_SWING:
00282         case LS_SPINATTACK_ALORA:
00283         case LS_DUAL_FB:
00284         case LS_DUAL_LR:
00285         case LS_HILT_BASH:
00286                 return qtrue;
00287                 break;
00288         }
00289         return qfalse;
00290 }

qboolean BG_SaberInSpecialAttack int  anim  ) 
 

Definition at line 587 of file bg_panimate.c.

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 }

qboolean BG_SabersOff playerState_t ps  ) 
 

Definition at line 201 of file bg_pmove.c.

00202 {
00203         if ( !ps->saberHolstered )
00204         {
00205                 return qfalse;
00206         }
00207         if ( ps->fd.saberAnimLevelBase == SS_DUAL
00208                 || ps->fd.saberAnimLevelBase == SS_STAFF )
00209         {
00210                 if ( ps->saberHolstered < 2 )
00211                 {
00212                         return qfalse;
00213                 }
00214         }
00215         return qtrue;
00216 }

qboolean BG_SpinningSaberAnim int  anim  ) 
 

Definition at line 479 of file bg_panimate.c.

References BOTH_ATTACK_BACK, BOTH_BUTTERFLY_LEFT, BOTH_BUTTERFLY_RIGHT, BOTH_CROUCHATTACKBACK1, BOTH_FJSS_TL_BR, BOTH_FJSS_TR_BL, BOTH_JUMPFLIPSLASHDOWN1, BOTH_JUMPFLIPSTABDOWN, BOTH_T1__L__R, BOTH_T1__L_BR, BOTH_T1__R__L, BOTH_T1__R_BL, BOTH_T1_BL__R, BOTH_T1_BL_BR, BOTH_T1_BL_TR, BOTH_T1_BR__L, BOTH_T1_BR_BL, BOTH_T1_BR_TL, BOTH_T1_TL_BR, BOTH_T1_TR_BL, BOTH_T2__L_BR, BOTH_T2__R_BL, BOTH_T2_BL__R, BOTH_T2_BL_BR, BOTH_T2_BR__L, BOTH_T2_BR_BL, BOTH_T3__L_BR, BOTH_T3__R_BL, BOTH_T3_BL__R, BOTH_T3_BL_BR, BOTH_T3_BR__L, BOTH_T3_BR_BL, BOTH_T4__L_BR, BOTH_T4__R_BL, BOTH_T4_BL__R, BOTH_T4_BL_BR, BOTH_T4_BR__L, BOTH_T4_BR_BL, BOTH_T5__L__R, BOTH_T5__L_BR, BOTH_T5__R__L, BOTH_T5__R_BL, BOTH_T5_BL__R, BOTH_T5_BL_BR, BOTH_T5_BL_TR, BOTH_T5_BR__L, BOTH_T5_BR_BL, BOTH_T5_BR_TL, BOTH_T5_TL_BR, BOTH_T5_TR_BL, BOTH_T6__L__R, BOTH_T6__L_BR, BOTH_T6__L_T_, BOTH_T6__L_TR, BOTH_T6__R__L, BOTH_T6__R_BL, BOTH_T6__R_TL, BOTH_T6_BL__R, BOTH_T6_BL_BR, BOTH_T6_BL_T_, BOTH_T6_BL_TR, BOTH_T6_BR__L, BOTH_T6_BR_BL, BOTH_T6_BR_TL, BOTH_T6_T__BL, BOTH_T6_T__TL, BOTH_T6_TL__R, BOTH_T6_TL_BR, BOTH_T6_TL_TR, BOTH_T6_TR__L, BOTH_T6_TR_BL, BOTH_T6_TR_TL, BOTH_T7__L__R, BOTH_T7__L_BR, BOTH_T7__L_TR, BOTH_T7__R__L, BOTH_T7__R_BL, BOTH_T7_BL__R, BOTH_T7_BL_BR, BOTH_T7_BL_TR, BOTH_T7_BR__L, BOTH_T7_BR_BL, BOTH_T7_BR_TL, BOTH_T7_T___R, BOTH_T7_T__BR, BOTH_T7_TL_BR, BOTH_T7_TL_TR, BOTH_T7_TR__L, BOTH_V7_BL_S7, qboolean, qfalse, and qtrue.

Referenced by BG_AdjustClientSpeed(), G_SPSaberDamageTraceLerped(), Jedi_SaberBlockGo(), Jedi_SaberBusy(), PM_SetSaberMove(), PM_SpinningAnim(), PmoveSingle(), and WP_ResistForcePush().

00480 {
00481         switch ( anim )
00482         {
00483         //level 1 - FIXME: level 1 will have *no* spins
00484         case BOTH_T1_BR_BL:
00485         case BOTH_T1__R__L:
00486         case BOTH_T1__R_BL:
00487         case BOTH_T1_TR_BL:
00488         case BOTH_T1_BR_TL:
00489         case BOTH_T1_BR__L:
00490         case BOTH_T1_TL_BR:
00491         case BOTH_T1__L_BR:
00492         case BOTH_T1__L__R:
00493         case BOTH_T1_BL_BR:
00494         case BOTH_T1_BL__R:
00495         case BOTH_T1_BL_TR:
00496         //level 2
00497         case BOTH_T2_BR__L:
00498         case BOTH_T2_BR_BL:
00499         case BOTH_T2__R_BL:
00500         case BOTH_T2__L_BR:
00501         case BOTH_T2_BL_BR:
00502         case BOTH_T2_BL__R:
00503         //level 3
00504         case BOTH_T3_BR__L:
00505         case BOTH_T3_BR_BL:
00506         case BOTH_T3__R_BL:
00507         case BOTH_T3__L_BR:
00508         case BOTH_T3_BL_BR:
00509         case BOTH_T3_BL__R:
00510         //level 4
00511         case BOTH_T4_BR__L:
00512         case BOTH_T4_BR_BL:
00513         case BOTH_T4__R_BL:
00514         case BOTH_T4__L_BR:
00515         case BOTH_T4_BL_BR:
00516         case BOTH_T4_BL__R:
00517         //level 5
00518         case BOTH_T5_BR_BL:
00519         case BOTH_T5__R__L:
00520         case BOTH_T5__R_BL:
00521         case BOTH_T5_TR_BL:
00522         case BOTH_T5_BR_TL:
00523         case BOTH_T5_BR__L:
00524         case BOTH_T5_TL_BR:
00525         case BOTH_T5__L_BR:
00526         case BOTH_T5__L__R:
00527         case BOTH_T5_BL_BR:
00528         case BOTH_T5_BL__R:
00529         case BOTH_T5_BL_TR:
00530         //level 6
00531         case BOTH_T6_BR_TL:
00532         case BOTH_T6__R_TL:
00533         case BOTH_T6__R__L:
00534         case BOTH_T6__R_BL:
00535         case BOTH_T6_TR_TL:
00536         case BOTH_T6_TR__L:
00537         case BOTH_T6_TR_BL:
00538         case BOTH_T6_T__TL:
00539         case BOTH_T6_T__BL:
00540         case BOTH_T6_TL_BR:
00541         case BOTH_T6__L_BR:
00542         case BOTH_T6__L__R:
00543         case BOTH_T6_TL__R:
00544         case BOTH_T6_TL_TR:
00545         case BOTH_T6__L_TR:
00546         case BOTH_T6__L_T_:
00547         case BOTH_T6_BL_T_:
00548         case BOTH_T6_BR__L:
00549         case BOTH_T6_BR_BL:
00550         case BOTH_T6_BL_BR:
00551         case BOTH_T6_BL__R:
00552         case BOTH_T6_BL_TR:
00553         //level 7
00554         case BOTH_T7_BR_TL:
00555         case BOTH_T7_BR__L:
00556         case BOTH_T7_BR_BL:
00557         case BOTH_T7__R__L:
00558         case BOTH_T7__R_BL:
00559         case BOTH_T7_TR__L:
00560         case BOTH_T7_T___R:
00561         case BOTH_T7_TL_BR:
00562         case BOTH_T7__L_BR:
00563         case BOTH_T7__L__R:
00564         case BOTH_T7_BL_BR:
00565         case BOTH_T7_BL__R:
00566         case BOTH_T7_BL_TR:
00567         case BOTH_T7_TL_TR:
00568         case BOTH_T7_T__BR:
00569         case BOTH_T7__L_TR:
00570         case BOTH_V7_BL_S7:
00571         //special
00572         //case BOTH_A2_STABBACK1:
00573         case BOTH_ATTACK_BACK:
00574         case BOTH_CROUCHATTACKBACK1:
00575         case BOTH_BUTTERFLY_LEFT:
00576         case BOTH_BUTTERFLY_RIGHT:
00577         case BOTH_FJSS_TR_BL:
00578         case BOTH_FJSS_TL_BR:
00579         case BOTH_JUMPFLIPSLASHDOWN1:
00580         case BOTH_JUMPFLIPSTABDOWN:
00581                 return qtrue;
00582                 break;
00583         }
00584         return qfalse;
00585 }

void Boba_ChangeWeapon int  wp  ) 
 

Definition at line 193 of file NPC_AI_Jedi.c.

References EV_GENERAL_SOUND, G_AddEvent(), G_SoundIndex(), NPC, NPC_ChangeWeapon(), gentity_s::s, and entityState_s::weapon.

Referenced by Boba_FireDecide(), and NPC_BSJedi_Default().

00194 {
00195         if ( NPC->s.weapon == wp )
00196         {
00197                 return;
00198         }
00199         NPC_ChangeWeapon( wp );
00200         G_AddEvent( NPC, EV_GENERAL_SOUND, G_SoundIndex( "sound/weapons/change.wav" ));
00201 }

void Boba_DoFlameThrower gentity_t self  ) 
 

Definition at line 471 of file NPC_AI_Jedi.c.

References Boba_FireFlameThrower(), Boba_StartFlameThrower(), BOTH_FORCELIGHTNING_HOLD, gentity_t, NPC_SetAnim(), SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, SETANIM_TORSO, and TIMER_Done().

Referenced by Boba_FireDecide().

00472 {
00473         NPC_SetAnim( self, SETANIM_TORSO, BOTH_FORCELIGHTNING_HOLD, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00474         if ( TIMER_Done( self, "nextAttackDelay" ) && TIMER_Done( self, "flameTime" ) )
00475         {
00476                 Boba_StartFlameThrower( self );
00477         }
00478         Boba_FireFlameThrower( self );
00479 }

void Boba_FireDecide void   ) 
 

TIMER_Done( NPC, "stick" ) ||

Definition at line 481 of file NPC_AI_Jedi.c.

References AngleVectors(), BG_FlippingAnim(), Boba_ChangeWeapon(), Boba_DoFlameThrower(), Boba_FlyStart(), gNPC_t::burstMax, gNPC_t::burstMean, gNPC_t::burstMin, gNPC_t::burstSpacing, BUTTON_ALT_ATTACK, BUTTON_ATTACK, usercmd_s::buttons, CalcEntitySpot(), gentity_s::client, entityShared_t::currentOrigin, gNPC_t::desiredPitch, gNPC_t::desiredYaw, DotProduct, trace_t::endpos, gentity_s::enemy, enemyDist, gNPC_t::enemyLastSeenLocation, gNPC_t::enemyLastSeenTime, gclient_s::enemyTeam, ENTITYNUM_NONE, playerState_s::fd, forcedata_s::forceJumpZStart, g_entities, gentity_t, playerState_s::groundEntityNum, gNPC_t::group, gentity_s::health, AIGroupInfo_s::lastSeenEnemyTime, playerState_s::legsAnim, level, MASK_SHOT, clientPersistant_t::maxHealth, MIN_ROCKET_DIST_SQUARED, NPC, NPC_ChangeWeapon(), NPC_ClearLOS4(), NPC_ShotEntity(), NPC_UpdateAngles(), NPCInfo, NULL, entityState_s::number, gclient_s::pers, PITCH, gclient_s::playerTeam, gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, SCF_ALT_FIRE, SCF_FIRE_WEAPON, gNPC_t::scriptFlags, SPOT_HEAD, SVF_GLASS_BRUSH, entityShared_t::svFlags, gentity_s::takedamage, level_locals_t::time, TIMER_Done(), TIMER_Set(), trap_InPVS(), trap_Trace(), ucmd, vec3_origin, vec3_t, vectoangles(), VectorClear, VectorCopy, VectorMA, VectorNormalize(), VectorSubtract, playerState_s::viewangles, entityState_s::weapon, playerState_s::weapon, WeaponThink(), playerState_s::weaponTime, WP_BLASTER, WP_DET_PACK, WP_DISRUPTOR, WP_EMPLACED_GUN, WP_FLECHETTE, WP_NONE, WP_REPEATER, WP_ROCKET_LAUNCHER, WP_SABER, WP_THERMAL, WP_TRIP_MINE, and YAW.

Referenced by NPC_BSSeeker_Default().

00482 {
00483         qboolean enemyLOS = qfalse;
00484         qboolean enemyCS = qfalse;
00485         qboolean enemyInFOV = qfalse;
00486         //qboolean move = qtrue;
00487         qboolean faceEnemy = qfalse;
00488         qboolean shoot = qfalse;
00489         qboolean hitAlly = qfalse;
00490         vec3_t  impactPos;
00491         float   enemyDist;
00492         float   dot;
00493         vec3_t  enemyDir, shootDir;
00494 
00495         if ( NPC->client->ps.groundEntityNum == ENTITYNUM_NONE 
00496                 && NPC->client->ps.fd.forceJumpZStart
00497                 && !BG_FlippingAnim( NPC->client->ps.legsAnim )
00498                 && !Q_irand( 0, 10 ) )
00499         {//take off
00500                 Boba_FlyStart( NPC );
00501         }
00502 
00503         if ( !NPC->enemy )
00504         {
00505                 return;
00506         }
00507 
00508         /*
00509         if ( NPC->enemy->enemy != NPC && NPC->health == NPC->client->pers.maxHealth )
00510         {
00511                 NPCInfo->scriptFlags |= SCF_ALT_FIRE;
00512                 Boba_ChangeWeapon( WP_DISRUPTOR );
00513         }
00514         else */if ( NPC->enemy->s.weapon == WP_SABER )
00515         {
00516                 NPCInfo->scriptFlags &= ~SCF_ALT_FIRE;
00517                 Boba_ChangeWeapon( WP_ROCKET_LAUNCHER );
00518         }
00519         else
00520         {
00521                 if ( NPC->health < NPC->client->pers.maxHealth*0.5f )
00522                 {
00523                         NPCInfo->scriptFlags |= SCF_ALT_FIRE;
00524                         Boba_ChangeWeapon( WP_BLASTER );
00525                         NPCInfo->burstMin = 3;
00526                         NPCInfo->burstMean = 12;
00527                         NPCInfo->burstMax = 20;
00528                         NPCInfo->burstSpacing = Q_irand( 300, 750 );//attack debounce
00529                 }
00530                 else
00531                 {
00532                         NPCInfo->scriptFlags &= ~SCF_ALT_FIRE;
00533                         Boba_ChangeWeapon( WP_BLASTER );
00534                 }
00535         }
00536 
00537         VectorClear( impactPos );
00538         enemyDist = DistanceSquared( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin );
00539 
00540         VectorSubtract( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, enemyDir );
00541         VectorNormalize( enemyDir );
00542         AngleVectors( NPC->client->ps.viewangles, shootDir, NULL, NULL );
00543         dot = DotProduct( enemyDir, shootDir );
00544         if ( dot > 0.5f ||( enemyDist * (1.0f-dot)) < 10000 )
00545         {//enemy is in front of me or they're very close and not behind me
00546                 enemyInFOV = qtrue;
00547         }
00548 
00549         if ( (enemyDist < (128*128)&&enemyInFOV) || !TIMER_Done( NPC, "flameTime" ) )
00550         {//flamethrower
00551                 Boba_DoFlameThrower( NPC );
00552                 enemyCS = qfalse;
00553                 shoot = qfalse;
00554                 NPCInfo->enemyLastSeenTime = level.time;
00555                 faceEnemy = qtrue;
00556                 ucmd.buttons &= ~(BUTTON_ATTACK|BUTTON_ALT_ATTACK);
00557         }
00558         else if ( enemyDist < MIN_ROCKET_DIST_SQUARED )//128
00559         {//enemy within 128
00560                 if ( (NPC->client->ps.weapon == WP_FLECHETTE || NPC->client->ps.weapon == WP_REPEATER) && 
00561                         (NPCInfo->scriptFlags & SCF_ALT_FIRE) )
00562                 {//shooting an explosive, but enemy too close, switch to primary fire
00563                         NPCInfo->scriptFlags &= ~SCF_ALT_FIRE;
00564                         //FIXME: we can never go back to alt-fire this way since, after this, we don't know if we were initially supposed to use alt-fire or not...
00565                 }
00566         }
00567         else if ( enemyDist > 65536 )//256 squared
00568         {
00569                 if ( NPC->client->ps.weapon == WP_DISRUPTOR )
00570                 {//sniping... should be assumed
00571                         if ( !(NPCInfo->scriptFlags&SCF_ALT_FIRE) )
00572                         {//use primary fire
00573                                 NPCInfo->scriptFlags |= SCF_ALT_FIRE;
00574                                 //reset fire-timing variables
00575                                 NPC_ChangeWeapon( WP_DISRUPTOR );
00576                                 NPC_UpdateAngles( qtrue, qtrue );
00577                                 return;
00578                         }
00579                 }
00580         }
00581 
00582         //can we see our target?
00583         if ( TIMER_Done( NPC, "nextAttackDelay" ) && TIMER_Done( NPC, "flameTime" ) )
00584         {
00585                 if ( NPC_ClearLOS4( NPC->enemy ) )
00586                 {
00587                         NPCInfo->enemyLastSeenTime = level.time;
00588                         enemyLOS = qtrue;
00589 
00590                         if ( NPC->client->ps.weapon == WP_NONE )
00591                         {
00592                                 enemyCS = qfalse;//not true, but should stop us from firing
00593                         }
00594                         else
00595                         {//can we shoot our target?
00596                                 if ( (NPC->client->ps.weapon == WP_ROCKET_LAUNCHER || (NPC->client->ps.weapon == WP_FLECHETTE && (NPCInfo->scriptFlags&SCF_ALT_FIRE))) && enemyDist < MIN_ROCKET_DIST_SQUARED )//128*128
00597                                 {
00598                                         enemyCS = qfalse;//not true, but should stop us from firing
00599                                         hitAlly = qtrue;//us!
00600                                         //FIXME: if too close, run away!
00601                                 }
00602                                 else if ( enemyInFOV )
00603                                 {//if enemy is FOV, go ahead and check for shooting
00604                                         int hit = NPC_ShotEntity( NPC->enemy, impactPos );
00605                                         gentity_t *hitEnt = &g_entities[hit];
00606 
00607                                         if ( hit == NPC->enemy->s.number 
00608                                                 || ( hitEnt && hitEnt->client && hitEnt->client->playerTeam == NPC->client->enemyTeam )
00609                                                 || ( hitEnt && hitEnt->takedamage && ((hitEnt->r.svFlags&SVF_GLASS_BRUSH)||hitEnt->health < 40||NPC->s.weapon == WP_EMPLACED_GUN) ) )
00610                                         {//can hit enemy or enemy ally or will hit glass or other minor breakable (or in emplaced gun), so shoot anyway
00611                                                 enemyCS = qtrue;
00612                                                 //NPC_AimAdjust( 2 );//adjust aim better longer we have clear shot at enemy
00613                                                 VectorCopy( NPC->enemy->r.currentOrigin, NPCInfo->enemyLastSeenLocation );
00614                                         }
00615                                         else
00616                                         {//Hmm, have to get around this bastard
00617                                                 //NPC_AimAdjust( 1 );//adjust aim better longer we can see enemy
00618                                                 if ( hitEnt && hitEnt->client && hitEnt->client->playerTeam == NPC->client->playerTeam )
00619                                                 {//would hit an ally, don't fire!!!
00620                                                         hitAlly = qtrue;
00621                                                 }
00622                                                 else
00623                                                 {//Check and see where our shot *would* hit... if it's not close to the enemy (within 256?), then don't fire
00624                                                 }
00625                                         }
00626                                 }
00627                                 else
00628                                 {
00629                                         enemyCS = qfalse;//not true, but should stop us from firing
00630                                 }
00631                         }
00632                 }
00633                 else if ( trap_InPVS( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin ) )
00634                 {
00635                         NPCInfo->enemyLastSeenTime = level.time;
00636                         faceEnemy = qtrue;
00637                         //NPC_AimAdjust( -1 );//adjust aim worse longer we cannot see enemy
00638                 }
00639 
00640                 if ( NPC->client->ps.weapon == WP_NONE )
00641                 {
00642                         faceEnemy = qfalse;
00643                         shoot = qfalse;
00644                 }
00645                 else
00646                 {
00647                         if ( enemyLOS )
00648                         {//FIXME: no need to face enemy if we're moving to some other goal and he's too far away to shoot?
00649                                 faceEnemy = qtrue;
00650                         }
00651                         if ( enemyCS )
00652                         {
00653                                 shoot = qtrue;
00654                         }
00655                 }
00656 
00657                 if ( !enemyCS )
00658                 {//if have a clear shot, always try
00659                         //See if we should continue to fire on their last position
00661                         if ( !hitAlly //we're not going to hit an ally
00662                                 && enemyInFOV //enemy is in our FOV //FIXME: or we don't have a clear LOS?
00663                                 && NPCInfo->enemyLastSeenTime > 0 )//we've seen the enemy
00664                         {
00665                                 if ( level.time - NPCInfo->enemyLastSeenTime < 10000 )//we have seem the enemy in the last 10 seconds
00666                                 {
00667                                         if ( !Q_irand( 0, 10 ) )
00668                                         {
00669                                                 //Fire on the last known position
00670                                                 vec3_t  muzzle, dir, angles;
00671                                                 qboolean tooClose = qfalse;
00672                                                 qboolean tooFar = qfalse;
00673                                                 float distThreshold;
00674                                                 float dist;
00675 
00676                                                 CalcEntitySpot( NPC, SPOT_HEAD, muzzle );
00677                                                 if ( VectorCompare( impactPos, vec3_origin ) )
00678                                                 {//never checked ShotEntity this frame, so must do a trace...
00679                                                         trace_t tr;
00680                                                         //vec3_t        mins = {-2,-2,-2}, maxs = {2,2,2};
00681                                                         vec3_t  forward, end;
00682                                                         AngleVectors( NPC->client->ps.viewangles, forward, NULL, NULL );
00683                                                         VectorMA( muzzle, 8192, forward, end );
00684                                                         trap_Trace( &tr, muzzle, vec3_origin, vec3_origin, end, NPC->s.number, MASK_SHOT );
00685                                                         VectorCopy( tr.endpos, impactPos );
00686                                                 }
00687 
00688                                                 //see if impact would be too close to me
00689                                                 distThreshold = 16384/*128*128*/;//default
00690                                                 switch ( NPC->s.weapon )
00691                                                 {
00692                                                 case WP_ROCKET_LAUNCHER:
00693                                                 case WP_FLECHETTE:
00694                                                 case WP_THERMAL:
00695                                                 case WP_TRIP_MINE:
00696                                                 case WP_DET_PACK:
00697                                                         distThreshold = 65536/*256*256*/;
00698                                                         break;
00699                                                 case WP_REPEATER:
00700                                                         if ( NPCInfo->scriptFlags&SCF_ALT_FIRE )
00701                                                         {
00702                                                                 distThreshold = 65536/*256*256*/;
00703                                                         }
00704                                                         break;
00705                                                 default:
00706                                                         break;
00707                                                 }
00708 
00709                                                 dist = DistanceSquared( impactPos, muzzle );
00710 
00711                                                 if ( dist < distThreshold )
00712                                                 {//impact would be too close to me
00713                                                         tooClose = qtrue;
00714                                                 }
00715                                                 else if ( level.time - NPCInfo->enemyLastSeenTime > 5000 ||
00716                                                         (NPCInfo->group && level.time - NPCInfo->group->lastSeenEnemyTime > 5000 ))
00717                                                 {//we've haven't seen them in the last 5 seconds
00718                                                         //see if it's too far from where he is
00719                                                         distThreshold = 65536/*256*256*/;//default
00720                                                         switch ( NPC->s.weapon )
00721                                                         {
00722                                                         case WP_ROCKET_LAUNCHER:
00723                                                         case WP_FLECHETTE:
00724                                                         case WP_THERMAL:
00725                                                         case WP_TRIP_MINE:
00726                                                         case WP_DET_PACK:
00727                                                                 distThreshold = 262144/*512*512*/;
00728                                                                 break;
00729                                                         case WP_REPEATER:
00730                                                                 if ( NPCInfo->scriptFlags&SCF_ALT_FIRE )
00731                                                                 {
00732                                                                         distThreshold = 262144/*512*512*/;
00733                                                                 }
00734                                                                 break;
00735                                                         default:
00736                                                                 break;
00737                                                         }
00738                                                         dist = DistanceSquared( impactPos, NPCInfo->enemyLastSeenLocation );
00739                                                         if ( dist > distThreshold )
00740                                                         {//impact would be too far from enemy
00741                                                                 tooFar = qtrue;
00742                                                         }
00743                                                 }
00744 
00745                                                 if ( !tooClose && !tooFar )
00746                                                 {//okay too shoot at last pos
00747                                                         VectorSubtract( NPCInfo->enemyLastSeenLocation, muzzle, dir );
00748                                                         VectorNormalize( dir );
00749                                                         vectoangles( dir, angles );
00750 
00751                                                         NPCInfo->desiredYaw             = angles[YAW];
00752                                                         NPCInfo->desiredPitch   = angles[PITCH];
00753 
00754                                                         shoot = qtrue;
00755                                                         faceEnemy = qfalse;
00756                                                 }
00757                                         }
00758                                 }
00759                         }
00760                 }
00761 
00762                 //FIXME: don't shoot right away!
00763                 if ( NPC->client->ps.weaponTime > 0 )
00764                 {
00765                         if ( NPC->s.weapon == WP_ROCKET_LAUNCHER )
00766                         {
00767                                 if ( !enemyLOS || !enemyCS )
00768                                 {//cancel it
00769                                         NPC->client->ps.weaponTime = 0;
00770                                 }
00771                                 else
00772                                 {//delay our next attempt
00773                                         TIMER_Set( NPC, "nextAttackDelay", Q_irand( 500, 1000 ) );
00774                                 }
00775                         }
00776                 }
00777                 else if ( shoot )
00778                 {//try to shoot if it's time
00779                         if ( TIMER_Done( NPC, "nextAttackDelay" ) )
00780                         {
00781                                 if( !(NPCInfo->scriptFlags & SCF_FIRE_WEAPON) ) // we've already fired, no need to do it again here
00782                                 {
00783                                         WeaponThink( qtrue );
00784                                 }
00785                                 //NASTY
00786                                 if ( NPC->s.weapon == WP_ROCKET_LAUNCHER 
00787                                         && (ucmd.buttons&BUTTON_ATTACK) 
00788                                         && !Q_irand( 0, 3 ) )
00789                                 {//every now and then, shoot a homing rocket
00790                                         ucmd.buttons &= ~BUTTON_ATTACK;
00791                                         ucmd.buttons |= BUTTON_ALT_ATTACK;
00792                                         NPC->client->ps.weaponTime = Q_irand( 500, 1500 );
00793                                 }
00794                         }
00795                 }
00796         }
00797 }

void Boba_FireFlameThrower gentity_t self  ) 
 

Definition at line 391 of file NPC_AI_Jedi.c.

References gentity_s::client, entityShared_t::currentAngles, entityShared_t::currentOrigin, DAMAGE_IGNORE_TEAM, DAMAGE_NO_ARMOR, DAMAGE_NO_KNOCKBACK, trace_t::endpos, trace_t::entityNum, ENTITYNUM_WORLD, G_Damage(), g_entities, gentity_t, gentity_s::ghoul2, renderInfo_s::handLBolt, level, MASK_SHOT, MOD_LAVA, gentity_s::modelScale, NEGATIVE_Y, NULL, entityState_s::number, ORIGIN, Q_irand(), gentity_s::r, gclient_s::renderInfo, gentity_s::s, gentity_s::takedamage, level_locals_t::time, trap_G2API_GetBoltMatrix(), trap_Trace(), vec3_t, and VectorMA.

Referenced by Boba_DoFlameThrower().

00392 {
00393         int             damage  = Q_irand( 20, 30 );
00394         trace_t         tr;
00395         gentity_t       *traceEnt = NULL;
00396         mdxaBone_t      boltMatrix;
00397         vec3_t          start, end, dir, traceMins = {-4, -4, -4}, traceMaxs = {4, 4, 4};
00398 
00399         trap_G2API_GetBoltMatrix( self->ghoul2, 0, self->client->renderInfo.handLBolt,
00400                         &boltMatrix, self->r.currentAngles, self->r.currentOrigin, level.time,
00401                         NULL, self->modelScale );
00402 
00403         BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, start );
00404         BG_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_Y, dir );
00405         //G_PlayEffect( "boba/fthrw", start, dir );
00406         VectorMA( start, 128, dir, end );
00407 
00408         trap_Trace( &tr, start, traceMins, traceMaxs, end, self->s.number, MASK_SHOT );
00409 
00410         traceEnt = &g_entities[tr.entityNum];
00411         if ( tr.entityNum < ENTITYNUM_WORLD && traceEnt->takedamage )
00412         {
00413                 G_Damage( traceEnt, self, self, dir, tr.endpos, damage, DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK|/*DAMAGE_NO_HIT_LOC|*/DAMAGE_IGNORE_TEAM, MOD_LAVA );
00414                 //rwwFIXMEFIXME: add DAMAGE_NO_HIT_LOC?
00415         }
00416 }

qboolean Boba_Flying gentity_t self  ) 
 

Definition at line 386 of file NPC_AI_Jedi.c.

References gentity_s::client, EF2_FLYING, playerState_s::eFlags2, gentity_t, gclient_s::ps, and qboolean.

Referenced by NPC_RunBehavior().

00387 {
00388         return ((qboolean)(self->client->ps.eFlags2&EF2_FLYING));//moveType==MT_FLYSWIM));
00389 }

void Boba_FlyStart gentity_t self  ) 
 

Definition at line 345 of file NPC_AI_Jedi.c.

References gNPC_t::aiFlags, CHAN_ITEM, gentity_s::client, gentity_s::count, EF2_FLYING, playerState_s::eFlags2, G_SoundIndex(), G_SoundOnEnt(), gentity_t, playerState_s::gravity, gclient_s::jetPackTime, level, entityState_s::loopSound, gentity_s::NPC, NPCAI_CUSTOM_GRAVITY, gclient_s::ps, Q3_INFINITE, Q_irand(), gentity_s::s, level_locals_t::time, and TIMER_Done().

Referenced by Boba_FireDecide().

00346 {//switch to seeker AI for a while
00347         if ( TIMER_Done( self, "jetRecharge" ) )
00348         {
00349                 self->client->ps.gravity = 0;
00350                 if ( self->NPC )
00351                 {
00352                         self->NPC->aiFlags |= NPCAI_CUSTOM_GRAVITY;
00353                 }
00354                 self->client->ps.eFlags2 |= EF2_FLYING;//moveType = MT_FLYSWIM;
00355                 self->client->jetPackTime = level.time + Q_irand( 3000, 10000 );
00356                 //take-off sound
00357                 G_SoundOnEnt( self, CHAN_ITEM, "sound/boba/jeton.wav" );
00358                 //jet loop sound
00359                 self->s.loopSound = G_SoundIndex( "sound/boba/jethover.wav" );
00360                 if ( self->NPC )
00361                 {
00362                         self->count = Q3_INFINITE; // SEEKER shot ammo count
00363                 }
00364         }
00365 }

void Boba_FlyStop gentity_t self  ) 
 

Definition at line 367 of file NPC_AI_Jedi.c.

References gNPC_t::aiFlags, gentity_s::client, gentity_s::count, EF2_FLYING, playerState_s::eFlags2, g_gravity, gentity_t, playerState_s::gravity, gclient_s::jetPackTime, entityState_s::loopSound, gentity_s::NPC, NPCAI_CUSTOM_GRAVITY, gclient_s::ps, Q_irand(), gentity_s::s, TIMER_Set(), and vmCvar_t::value.

Referenced by player_die().

00368 {
00369         self->client->ps.gravity = g_gravity.value;
00370         if ( self->NPC )
00371         {
00372                 self->NPC->aiFlags &= ~NPCAI_CUSTOM_GRAVITY;
00373         }
00374         self->client->ps.eFlags2 &= ~EF2_FLYING;
00375         self->client->jetPackTime = 0;
00376         //stop jet loop sound
00377         self->s.loopSound = 0;
00378         if ( self->NPC )
00379         {
00380                 self->count = 0; // SEEKER shot ammo count
00381                 TIMER_Set( self, "jetRecharge", Q_irand( 1000, 5000 ) );
00382                 TIMER_Set( self, "jumpChaseDebounce", Q_irand( 500, 2000 ) );
00383         }
00384 }

void Boba_Precache void   ) 
 

Definition at line 182 of file NPC_AI_Jedi.c.

References G_EffectIndex(), and G_SoundIndex().

Referenced by NPC_SetMiscDefaultData().

00183 {
00184         G_SoundIndex( "sound/boba/jeton.wav" );
00185         G_SoundIndex( "sound/boba/jethover.wav" );
00186         G_SoundIndex( "sound/effects/combustfire.mp3" );
00187         G_EffectIndex( "boba/jet" );
00188         G_EffectIndex( "boba/fthrw" );
00189 }

void Boba_StartFlameThrower gentity_t self  ) 
 

Definition at line 419 of file NPC_AI_Jedi.c.

References CHAN_WEAPON, gentity_s::client, entityShared_t::currentAngles, entityShared_t::currentOrigin, G_EffectIndex(), G_PlayEffectID(), G_SoundOnEnt(), gentity_t, gentity_s::ghoul2, renderInfo_s::handRBolt, level, gentity_s::modelScale, NEGATIVE_Y, NPC, gentity_s::NPC, NULL, ORIGIN, gclient_s::ps, gentity_s::r, gclient_s::renderInfo, level_locals_t::time, TIMER_Set(), playerState_s::torsoTimer, trap_G2API_GetBoltMatrix(), and vec3_t.

Referenced by Boba_DoFlameThrower().

00420 {
00421         int     flameTime = 4000;//Q_irand( 1000, 3000 );
00422         mdxaBone_t      boltMatrix;
00423         vec3_t          org, dir;
00424 
00425         self->client->ps.torsoTimer = flameTime;//+1000;
00426         if ( self->NPC )
00427         {
00428                 TIMER_Set( self, "nextAttackDelay", flameTime );
00429                 TIMER_Set( self, "walking", 0 );
00430         }
00431         TIMER_Set( self, "flameTime", flameTime );
00432         /*
00433         gentity_t *fire = G_Spawn();
00434         if ( fire != NULL )
00435         {
00436                 mdxaBone_t      boltMatrix;
00437                 vec3_t          org, dir, ang;
00438                 gi.G2API_GetBoltMatrix( NPC->ghoul2, NPC->playerModel, NPC->handRBolt,
00439                                 &boltMatrix, NPC->r.currentAngles, NPC->r.currentOrigin, (cg.time?cg.time:level.time),
00440                                 NULL, NPC->s.modelScale );
00441 
00442                 gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, org );
00443                 gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, dir );
00444                 vectoangles( dir, ang );
00445 
00446                 VectorCopy( org, fire->s.origin );
00447                 VectorCopy( ang, fire->s.angles );
00448 
00449                 fire->targetname = "bobafire";
00450                 SP_fx_explosion_trail( fire );
00451                 fire->damage = 1;
00452                 fire->radius = 10;
00453                 fire->speed = 200;
00454                 fire->fxID = G_EffectIndex( "boba/fthrw" );//"env/exp_fire_trail" );//"env/small_fire"
00455                 fx_explosion_trail_link( fire );
00456                 fx_explosion_trail_use( fire, NPC, NPC );
00457 
00458         }
00459         */
00460         G_SoundOnEnt( self, CHAN_WEAPON, "sound/effects/combustfire.mp3" );
00461 
00462         trap_G2API_GetBoltMatrix(NPC->ghoul2, 0, NPC->client->renderInfo.handRBolt, &boltMatrix, NPC->r.currentAngles,
00463                 NPC->r.currentOrigin, level.time, NULL, NPC->modelScale);
00464 
00465         BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, org );
00466         BG_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_Y, dir );
00467 
00468         G_PlayEffectID( G_EffectIndex("boba/fthrw"), org, dir);
00469 }

qboolean Boba_StopKnockdown gentity_t self,
gentity_t pusher,
vec3_t  pushDir,
qboolean  forceKnockdown
 

Definition at line 272 of file NPC_AI_Jedi.c.

References AngleVectors(), CLASS_BOBAFETT, gentity_s::client, entityShared_t::currentAngles, DotProduct, EF2_FLYING, playerState_s::eFlags2, EV_JUMP, playerState_s::fd, ForceJump(), forcedata_s::forceJumpCharge, usercmd_s::forwardmove, G_AddEvent(), gentity_t, gclient_s::NPC_class, NULL, gentity_s::painDebounceTime, gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, usercmd_s::rightmove, TIMER_Set(), usercmd_t, vec3_t, VectorNormalize2(), VectorSet, WP_ResistForcePush(), and YAW.

00273 {
00274         vec3_t  pDir, fwd, right, ang;
00275         float   fDot, rDot;
00276         int             strafeTime;
00277 
00278         if ( self->client->NPC_class != CLASS_BOBAFETT )
00279         {
00280                 return qfalse;
00281         }
00282 
00283         if ( (self->client->ps.eFlags2&EF2_FLYING) )//moveType == MT_FLYSWIM )
00284         {//can't knock me down when I'm flying
00285                 return qtrue;
00286         }
00287 
00288         VectorSet(ang, 0, self->r.currentAngles[YAW], 0);
00289         strafeTime = Q_irand( 1000, 2000 );
00290 
00291         AngleVectors( ang, fwd, right, NULL );
00292         VectorNormalize2( pushDir, pDir );
00293         fDot = DotProduct( pDir, fwd );
00294         rDot = DotProduct( pDir, right );
00295 
00296         if ( Q_irand( 0, 2 ) )
00297         {//flip or roll with it
00298                 usercmd_t       tempCmd;
00299                 if ( fDot >= 0.4f )
00300                 {
00301                         tempCmd.forwardmove = 127;
00302                         TIMER_Set( self, "moveforward", strafeTime );
00303                 }
00304                 else if ( fDot <= -0.4f )
00305                 {
00306                         tempCmd.forwardmove = -127;
00307                         TIMER_Set( self, "moveback", strafeTime );
00308                 }
00309                 else if ( rDot > 0 )
00310                 {
00311                         tempCmd.rightmove = 127;
00312                         TIMER_Set( self, "strafeRight", strafeTime );
00313                         TIMER_Set( self, "strafeLeft", -1 );
00314                 }
00315                 else
00316                 {
00317                         tempCmd.rightmove = -127;
00318                         TIMER_Set( self, "strafeLeft", strafeTime );
00319                         TIMER_Set( self, "strafeRight", -1 );
00320                 }
00321                 G_AddEvent( self, EV_JUMP, 0 );
00322                 if ( !Q_irand( 0, 1 ) )
00323                 {//flip
00324                         self->client->ps.fd.forceJumpCharge = 280;//FIXME: calc this intelligently?
00325                         ForceJump( self, &tempCmd );
00326                 }
00327                 else
00328                 {//roll
00329                         TIMER_Set( self, "duck", strafeTime );
00330                 }
00331                 self->painDebounceTime = 0;//so we do something
00332         }
00333         else if ( !Q_irand( 0, 1 ) && forceKnockdown )
00334         {//resist
00335                 WP_ResistForcePush( self, pusher, qtrue );
00336         }
00337         else
00338         {//fall down
00339                 return qfalse;
00340         }
00341 
00342         return qtrue;
00343 }

void CG_DrawAlert vec3_t  origin,
float  rating
 

void ChangeWeapon gentity_t ent,
int  newWeapon
 

void ForceAbsorb gentity_t self  ) 
 

Definition at line 1694 of file w_force.c.

References absorbLoopSound, gentity_s::client, playerState_s::fd, playerState_s::forceAllowDeactivateTime, forcedata_s::forcePowersActive, FP_ABSORB, FP_PROTECT, FP_RAGE, G_PreDefSound(), G_Sound(), gentity_t, gentity_s::health, level, playerState_s::origin, PDSOUND_ABSORB, gclient_s::ps, level_locals_t::time, TRACK_CHANNEL_3, WP_ForcePowerStart(), WP_ForcePowerStop(), and WP_ForcePowerUsable().

Referenced by ClientThink_real(), and WP_DoSpecificPower().

01695 {
01696         if ( self->health <= 0 )
01697         {
01698                 return;
01699         }
01700 
01701         if (self->client->ps.forceAllowDeactivateTime < level.time &&
01702                 (self->client->ps.fd.forcePowersActive & (1 << FP_ABSORB)) )
01703         {
01704                 WP_ForcePowerStop( self, FP_ABSORB );
01705                 return;
01706         }
01707 
01708         if ( !WP_ForcePowerUsable( self, FP_ABSORB ) )
01709         {
01710                 return;
01711         }
01712 
01713         // Make sure to turn off Force Rage and Force Protection.
01714         if (self->client->ps.fd.forcePowersActive & (1 << FP_RAGE) )
01715         {
01716                 WP_ForcePowerStop( self, FP_RAGE );
01717         }
01718         if (self->client->ps.fd.forcePowersActive & (1 << FP_PROTECT) )
01719         {
01720                 WP_ForcePowerStop( self, FP_PROTECT );
01721         }
01722 
01723         self->client->ps.forceAllowDeactivateTime = level.time + 1500;
01724 
01725         WP_ForcePowerStart( self, FP_ABSORB, 0 );
01726         G_PreDefSound(self->client->ps.origin, PDSOUND_ABSORB);
01727         G_Sound( self, TRACK_CHANNEL_3, absorbLoopSound );
01728 }

void ForceHeal gentity_t self  ) 
 

Definition at line 1236 of file w_force.c.

References BG_ForcePowerDrain(), CHAN_ITEM, gentity_s::client, playerState_s::fd, FORCE_LEVEL_2, FORCE_LEVEL_3, forcedata_s::forcePowerLevel, FP_HEAL, G_Sound(), G_SoundIndex(), gentity_t, gentity_s::health, gclient_s::ps, STAT_MAX_HEALTH, playerState_s::stats, and WP_ForcePowerUsable().

Referenced by ClientThink_real(), and WP_DoSpecificPower().

01237 {
01238         if ( self->health <= 0 )
01239         {
01240                 return;
01241         }
01242 
01243         if ( !WP_ForcePowerUsable( self, FP_HEAL ) )
01244         {
01245                 return;
01246         }
01247 
01248         if ( self->health >= self->client->ps.stats[STAT_MAX_HEALTH])
01249         {
01250                 return;
01251         }
01252 
01253         if (self->client->ps.fd.forcePowerLevel[FP_HEAL] == FORCE_LEVEL_3)
01254         {
01255                 self->health += 25; //This was 50, but that angered the Balance God.
01256                 
01257                 if (self->health > self->client->ps.stats[STAT_MAX_HEALTH])
01258                 {
01259                         self->health = self->client->ps.stats[STAT_MAX_HEALTH];
01260                 }
01261                 BG_ForcePowerDrain( &self->client->ps, FP_HEAL, 0 );
01262         }
01263         else if (self->client->ps.fd.forcePowerLevel[FP_HEAL] == FORCE_LEVEL_2)
01264         {
01265                 self->health += 10;
01266                 
01267                 if (self->health > self->client->ps.stats[STAT_MAX_HEALTH])
01268                 {
01269                         self->health = self->client->ps.stats[STAT_MAX_HEALTH];
01270                 }
01271                 BG_ForcePowerDrain( &self->client->ps, FP_HEAL, 0 );
01272         }
01273         else
01274         {
01275                 self->health += 5;
01276                 
01277                 if (self->health > self->client->ps.stats[STAT_MAX_HEALTH])
01278                 {
01279                         self->health = self->client->ps.stats[STAT_MAX_HEALTH];
01280                 }
01281                 BG_ForcePowerDrain( &self->client->ps, FP_HEAL, 0 );
01282         }
01283         /*
01284         else
01285         {
01286                 WP_ForcePowerStart( self, FP_HEAL, 0 );
01287         }
01288         */
01289         //NOTE: Decided to make all levels instant.
01290 
01291         G_Sound( self, CHAN_ITEM, G_SoundIndex("sound/weapons/force/heal.wav") );
01292 }

void ForceJump gentity_t self,
usercmd_t ucmd
 

Definition at line 2462 of file w_force.c.

References gentity_s::client, ENTITYNUM_NONE, playerState_s::fd, gclient_s::fjDidJump, FORCE_JUMP_CHARGE_TIME, forcedata_s::forceJumpCharge, playerState_s::forceJumpFlip, forceJumpStrength, forcedata_s::forceJumpZStart, forcedata_s::forcePowerDuration, forcedata_s::forcePowerLevel, forcePowerNeeded, FP_LEVITATION, FRAMETIME, gentity_t, entityState_s::groundEntityNum, gentity_s::health, level, playerState_s::origin, gclient_s::ps, qtrue, gentity_s::s, level_locals_t::time, ucmd, usercmd_t, vec3_t, VectorCopy, playerState_s::velocity, WP_ForcePowerStart(), WP_ForcePowerUsable(), and WP_GetVelocityForForceJump().

Referenced by Boba_StopKnockdown(), and WP_DoSpecificPower().

02463 {
02464         float forceJumpChargeInterval;
02465         vec3_t  jumpVel;
02466 
02467         if ( self->client->ps.fd.forcePowerDuration[FP_LEVITATION] > level.time )
02468         {
02469                 return;
02470         }
02471         if ( !WP_ForcePowerUsable( self, FP_LEVITATION ) )
02472         {
02473                 return;
02474         }
02475         if ( self->s.groundEntityNum == ENTITYNUM_NONE )
02476         {
02477                 return;
02478         }
02479         if ( self->health <= 0 )
02480         {
02481                 return;
02482         }
02483 
02484         self->client->fjDidJump = qtrue;
02485 
02486         forceJumpChargeInterval = forceJumpStrength[self->client->ps.fd.forcePowerLevel[FP_LEVITATION]]/(FORCE_JUMP_CHARGE_TIME/FRAMETIME);
02487 
02488         WP_GetVelocityForForceJump( self, jumpVel, ucmd );
02489 
02490         //FIXME: sound effect
02491         self->client->ps.fd.forceJumpZStart = self->client->ps.origin[2];//remember this for when we land
02492         VectorCopy( jumpVel, self->client->ps.velocity );
02493         //wasn't allowing them to attack when jumping, but that was annoying
02494         //self->client->ps.weaponTime = self->client->ps.torsoAnimTimer;
02495 
02496         WP_ForcePowerStart( self, FP_LEVITATION, self->client->ps.fd.forceJumpCharge/forceJumpChargeInterval/(FORCE_JUMP_CHARGE_TIME/FRAMETIME)*forcePowerNeeded[self->client->ps.fd.forcePowerLevel[FP_LEVITATION]][FP_LEVITATION] );
02497         //self->client->ps.fd.forcePowerDuration[FP_LEVITATION] = level.time + self->client->ps.weaponTime;
02498         self->client->ps.fd.forceJumpCharge = 0;
02499         self->client->ps.forceJumpFlip = qtrue;
02500 }

void ForceLightning gentity_t self  ) 
 

Definition at line 1777 of file w_force.c.

References CHAN_BODY, gentity_s::client, playerState_s::fd, playerState_s::forceHandExtend, playerState_s::forceHandExtendTime, forcedata_s::forcePower, forcedata_s::forcePowerDebounce, FP_LIGHTNING, G_Sound(), G_SoundIndex(), gentity_t, HANDEXTEND_FORCE_HOLD, HANDEXTEND_NONE, gentity_s::health, level, gclient_s::ps, level_locals_t::time, playerState_s::weaponTime, WP_ForcePowerStart(), and WP_ForcePowerUsable().

Referenced by WP_DoSpecificPower().

01778 {
01779         if ( self->health <= 0 )
01780         {
01781                 return;
01782         }
01783         if ( self->client->ps.fd.forcePower < 25 || !WP_ForcePowerUsable( self, FP_LIGHTNING ) )
01784         {
01785                 return;
01786         }
01787         if ( self->client->ps.fd.forcePowerDebounce[FP_LIGHTNING] > level.time )
01788         {//stops it while using it and also after using it, up to 3 second delay
01789                 return;
01790         }
01791 
01792         if (self->client->ps.forceHandExtend != HANDEXTEND_NONE)
01793         {
01794                 return;
01795         }
01796 
01797         if (self->client->ps.weaponTime > 0)
01798         {
01799                 return;
01800         }
01801 
01802         //Shoot lightning from hand
01803         //using grip anim now, to extend the burst time
01804         self->client->ps.forceHandExtend = HANDEXTEND_FORCE_HOLD;
01805         self->client->ps.forceHandExtendTime = level.time + 20000;
01806 
01807         G_Sound( self, CHAN_BODY, G_SoundIndex("sound/weapons/force/lightning") );
01808         
01809         WP_ForcePowerStart( self, FP_LIGHTNING, 500 );
01810 }

void ForceProtect gentity_t self  ) 
 

Definition at line 1658 of file w_force.c.

References gentity_s::client, playerState_s::fd, playerState_s::forceAllowDeactivateTime, forcedata_s::forcePowersActive, FP_ABSORB, FP_PROTECT, FP_RAGE, G_PreDefSound(), G_Sound(), gentity_t, gentity_s::health, level, playerState_s::origin, PDSOUND_PROTECT, protectLoopSound, gclient_s::ps, level_locals_t::time, TRACK_CHANNEL_3, WP_ForcePowerStart(), WP_ForcePowerStop(), and WP_ForcePowerUsable().

Referenced by ClientThink_real(), and WP_DoSpecificPower().

01659 {
01660         if ( self->health <= 0 )
01661         {
01662                 return;
01663         }
01664 
01665         if (self->client->ps.forceAllowDeactivateTime < level.time &&
01666                 (self->client->ps.fd.forcePowersActive & (1 << FP_PROTECT)) )
01667         {
01668                 WP_ForcePowerStop( self, FP_PROTECT );
01669                 return;
01670         }
01671 
01672         if ( !WP_ForcePowerUsable( self, FP_PROTECT ) )
01673         {
01674                 return;
01675         }
01676 
01677         // Make sure to turn off Force Rage and Force Absorb.
01678         if (self->client->ps.fd.forcePowersActive & (1 << FP_RAGE) )
01679         {
01680                 WP_ForcePowerStop( self, FP_RAGE );
01681         }
01682         if (self->client->ps.fd.forcePowersActive & (1 << FP_ABSORB) )
01683         {
01684                 WP_ForcePowerStop( self, FP_ABSORB );
01685         }
01686 
01687         self->client->ps.forceAllowDeactivateTime = level.time + 1500;
01688 
01689         WP_ForcePowerStart( self, FP_PROTECT, 0 );
01690         G_PreDefSound(self->client->ps.origin, PDSOUND_PROTECT);
01691         G_Sound( self, TRACK_CHANNEL_3, protectLoopSound );
01692 }

void ForceRage gentity_t self  ) 
 

Definition at line 1730 of file w_force.c.

References gentity_s::client, playerState_s::fd, playerState_s::forceAllowDeactivateTime, forcedata_s::forcePowersActive, forcedata_s::forceRageRecoveryTime, FP_ABSORB, FP_PROTECT, FP_RAGE, G_Sound(), G_SoundIndex(), gentity_t, gentity_s::health, level, gclient_s::ps, rageLoopSound, level_locals_t::time, TRACK_CHANNEL_3, TRACK_CHANNEL_4, WP_ForcePowerStart(), WP_ForcePowerStop(), and WP_ForcePowerUsable().

Referenced by ClientThink_real(), and WP_DoSpecificPower().

01731 {
01732         if ( self->health <= 0 )
01733         {
01734                 return;
01735         }
01736 
01737         if (self->client->ps.forceAllowDeactivateTime < level.time &&
01738                 (self->client->ps.fd.forcePowersActive & (1 << FP_RAGE)) )
01739         {
01740                 WP_ForcePowerStop( self, FP_RAGE );
01741                 return;
01742         }
01743 
01744         if ( !WP_ForcePowerUsable( self, FP_RAGE ) )
01745         {
01746                 return;
01747         }
01748 
01749         if (self->client->ps.fd.forceRageRecoveryTime >= level.time)
01750         {
01751                 return;
01752         }
01753 
01754         if (self->health < 10)
01755         {
01756                 return;
01757         }
01758 
01759         // Make sure to turn off Force Protection and Force Absorb.
01760         if (self->client->ps.fd.forcePowersActive & (1 << FP_PROTECT) )
01761         {
01762                 WP_ForcePowerStop( self, FP_PROTECT );
01763         }
01764         if (self->client->ps.fd.forcePowersActive & (1 << FP_ABSORB) )
01765         {
01766                 WP_ForcePowerStop( self, FP_ABSORB );
01767         }
01768 
01769         self->client->ps.forceAllowDeactivateTime = level.time + 1500;
01770 
01771         WP_ForcePowerStart( self, FP_RAGE, 0 );
01772 
01773         G_Sound( self, TRACK_CHANNEL_4, G_SoundIndex("sound/weapons/force/rage.wav") );
01774         G_Sound( self, TRACK_CHANNEL_3, rageLoopSound );
01775 }

void ForceThrow gentity_t self,
qboolean  pull
 

Definition at line 3054 of file w_force.c.

References entityShared_t::absmax, entityShared_t::absmin, trace_t::allsolid, AngleVectors(), BG_KnockDownable(), bgEntity_t, entityShared_t::bmodel, CanCounterThrow(), CHAN_BODY, CLASS_ATST, CLASS_GALAKMECH, CLASS_RANCOR, gentity_s::classname, gentity_s::client, client, gclient_s::dangerTime, DotProduct, EF_INVULNERABLE, EF_MISSILE_STICK, EF_NODRAW, entityState_s::eFlags, playerState_s::eFlags, vehicleInfo_t::Eject, trace_t::entityNum, ENTITYNUM_NONE, ET_ITEM, ET_MISSILE, ET_NPC, entityState_s::eType, playerState_s::fd, FORCE_LEVEL_1, FORCE_LEVEL_2, FORCE_LEVEL_3, playerState_s::forceDodgeAnim, forcedata_s::forceGripBeingGripped, playerState_s::forceHandExtend, playerState_s::forceHandExtendTime, forcedata_s::forcePowerLevel, forcePowerNeeded, ForcePowerUsableOn(), FP_ABSORB, FP_GRIP, FP_PULL, FP_PUSH, trace_t::fraction, g_debugMelee, g_entities, g_gametype, G_InGetUpAnim(), G_LetGoOfWall(), G_ReflectMissile(), G_Sound(), G_SoundIndex(), g_useWhileThrowing, entityState_s::genericenemyindex, gentity_t, GEntity_UseFunc(), GT_SIEGE, HANDEXTEND_FORCEPULL, HANDEXTEND_FORCEPUSH, HANDEXTEND_KNOCKDOWN, HANDEXTEND_NONE, gentity_s::health, InFieldOfVision(), vmCvar_t::integer, gentity_s::inuse, gclient_s::invulnerableTimer, level, playerState_s::m_iVehicleNum, gentity_s::m_pVehicle, Vehicle_s::m_pVehicleInfo, MASK_PLAYERSOLID, MASK_SHOT, MAX_CLIENTS, MAX_GENTITIES, MOVER_POS1, MOVER_POS2, gentity_s::moverState, gclient_s::NPC_class, NULL, entityState_s::number, OnSameTeam(), playerState_s::origin, PMF_STUCK_TO_WALL, entityState_s::pos, playerState_s::powerups, gclient_s::ps, PW_DISINT_4, PW_PULL, Q_irand(), Q_stricmp(), qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, playerState_s::saberInFlight, playerState_s::saberLockFrame, playerState_s::saberLockHits, playerState_s::saberLockTime, gentity_s::spawnflags, SPF_BUTTON_FPUSHABLE, trace_t::startsolid, level_locals_t::time, TossClientWeapon(), Touch_Button(), TR_INTERPOLATE, TR_STATIONARY, trap_EntitiesInBox(), trap_InPVS(), trap_Trace(), trajectory_t::trBase, trajectory_t::trType, vehicleInfo_t::type, vec3_origin, vec3_t, vectoangles(), VectorAdd, VectorCopy, VectorMA, VectorNormalize(), VectorSubtract, VH_ANIMAL, VH_SPEEDER, playerState_s::viewangles, playerState_s::viewheight, playerState_s::weapon, entityState_s::weapon, playerState_s::weaponTime, WP_AbsorbConversion(), WP_ForcePowerStart(), WP_ForcePowerStop(), WP_ForcePowerUsable(), WP_SABER, and WP_THERMAL.

Referenced by ClientThink_real(), WP_DoSpecificPower(), and WP_SaberStartMissileBlockCheck().

03055 {
03056         //shove things in front of you away
03057         float           dist;
03058         gentity_t       *ent;
03059         int                     entityList[MAX_GENTITIES];
03060         gentity_t       *push_list[MAX_GENTITIES];
03061         int                     numListedEntities;
03062         vec3_t          mins, maxs;
03063         vec3_t          v;
03064         int                     i, e;
03065         int                     ent_count = 0;
03066         int                     radius = 1024; //since it's view-based now. //350;
03067         int                     powerLevel;
03068         int                     visionArc;
03069         int                     pushPower;
03070         int                     pushPowerMod;
03071         vec3_t          center, ent_org, size, forward, right, end, dir, fwdangles = {0};
03072         float           dot1;
03073         trace_t         tr;
03074         int                     x;
03075         vec3_t          pushDir;
03076         vec3_t          thispush_org;
03077         vec3_t          tfrom, tto, fwd, a;
03078         float           knockback = pull?0:200;
03079         int                     powerUse = 0;
03080 
03081         visionArc = 0;
03082 
03083         if (self->client->ps.forceHandExtend != HANDEXTEND_NONE && (self->client->ps.forceHandExtend != HANDEXTEND_KNOCKDOWN || !G_InGetUpAnim(&self->client->ps)))
03084         {
03085                 return;
03086         }
03087 
03088         if (!g_useWhileThrowing.integer && self->client->ps.saberInFlight)
03089         {
03090                 return;
03091         }
03092 
03093         if (self->client->ps.weaponTime > 0)
03094         {
03095                 return;
03096         }
03097 
03098         if ( self->health <= 0 )
03099         {
03100                 return;
03101         }
03102         if ( self->client->ps.powerups[PW_DISINT_4] > level.time )
03103         {
03104                 return;
03105         }
03106         if (pull)
03107         {
03108                 powerUse = FP_PULL;
03109         }
03110         else
03111         {
03112                 powerUse = FP_PUSH;
03113         }
03114 
03115         if ( !WP_ForcePowerUsable( self, powerUse ) )
03116         {
03117                 return;
03118         }
03119 
03120         if (!pull && self->client->ps.saberLockTime > level.time && self->client->ps.saberLockFrame)
03121         {
03122                 G_Sound( self, CHAN_BODY, G_SoundIndex( "sound/weapons/force/push.wav" ) );
03123                 self->client->ps.powerups[PW_DISINT_4] = level.time + 1500;
03124 
03125                 self->client->ps.saberLockHits += self->client->ps.fd.forcePowerLevel[FP_PUSH]*2;
03126 
03127                 WP_ForcePowerStart( self, FP_PUSH, 0 );
03128                 return;
03129         }
03130 
03131         WP_ForcePowerStart( self, powerUse, 0 );
03132 
03133         //make sure this plays and that you cannot press fire for about 1 second after this
03134         if ( pull )
03135         {
03136                 G_Sound( self, CHAN_BODY, G_SoundIndex( "sound/weapons/force/pull.wav" ) );
03137                 if (self->client->ps.forceHandExtend == HANDEXTEND_NONE)
03138                 {
03139                         self->client->ps.forceHandExtend = HANDEXTEND_FORCEPULL;
03140                         if ( g_gametype.integer == GT_SIEGE && self->client->ps.weapon == WP_SABER )
03141                         {//hold less so can attack right after a pull
03142                                 self->client->ps.forceHandExtendTime = level.time + 200;
03143                         }
03144                         else
03145                         {
03146                                 self->client->ps.forceHandExtendTime = level.time + 400;
03147                         }
03148                 }
03149                 self->client->ps.powerups[PW_DISINT_4] = self->client->ps.forceHandExtendTime + 200;
03150                 self->client->ps.powerups[PW_PULL] = self->client->ps.powerups[PW_DISINT_4];
03151         }
03152         else
03153         {
03154                 G_Sound( self, CHAN_BODY, G_SoundIndex( "sound/weapons/force/push.wav" ) );
03155                 if (self->client->ps.forceHandExtend == HANDEXTEND_NONE)
03156                 {
03157                         self->client->ps.forceHandExtend = HANDEXTEND_FORCEPUSH;
03158                         self->client->ps.forceHandExtendTime = level.time + 1000;
03159                 }
03160                 else if (self->client->ps.forceHandExtend == HANDEXTEND_KNOCKDOWN && G_InGetUpAnim(&self->client->ps))
03161                 {
03162                         if (self->client->ps.forceDodgeAnim > 4)
03163                         {
03164                                 self->client->ps.forceDodgeAnim -= 8;
03165                         }
03166                         self->client->ps.forceDodgeAnim += 8; //special case, play push on upper torso, but keep playing current knockdown anim on legs
03167                 }
03168                 self->client->ps.powerups[PW_DISINT_4] = level.time + 1100;
03169                 self->client->ps.powerups[PW_PULL] = 0;
03170         }
03171 
03172         VectorCopy( self->client->ps.viewangles, fwdangles );
03173         AngleVectors( fwdangles, forward, right, NULL );
03174         VectorCopy( self->client->ps.origin, center );
03175 
03176         for ( i = 0 ; i < 3 ; i++ ) 
03177         {
03178                 mins[i] = center[i] - radius;
03179                 maxs[i] = center[i] + radius;
03180         }
03181 
03182 
03183         if (pull)
03184         {
03185                 powerLevel = self->client->ps.fd.forcePowerLevel[FP_PULL];
03186                 pushPower = 256*self->client->ps.fd.forcePowerLevel[FP_PULL];
03187         }
03188         else
03189         {
03190                 powerLevel = self->client->ps.fd.forcePowerLevel[FP_PUSH];
03191                 pushPower = 256*self->client->ps.fd.forcePowerLevel[FP_PUSH];
03192         }
03193 
03194         if (!powerLevel)
03195         { //Shouldn't have made it here..
03196                 return;
03197         }
03198 
03199         if (powerLevel == FORCE_LEVEL_2)
03200         {
03201                 visionArc = 60;
03202         }
03203         else if (powerLevel == FORCE_LEVEL_3)
03204         {
03205                 visionArc = 180;
03206         }
03207 
03208         if (powerLevel == FORCE_LEVEL_1)
03209         { //can only push/pull targeted things at level 1
03210                 VectorCopy(self->client->ps.origin, tfrom);
03211                 tfrom[2] += self->client->ps.viewheight;
03212                 AngleVectors(self->client->ps.viewangles, fwd, NULL, NULL);
03213                 tto[0] = tfrom[0] + fwd[0]*radius/2;
03214                 tto[1] = tfrom[1] + fwd[1]*radius/2;
03215                 tto[2] = tfrom[2] + fwd[2]*radius/2;
03216 
03217                 trap_Trace(&tr, tfrom, NULL, NULL, tto, self->s.number, MASK_PLAYERSOLID);
03218 
03219                 if (tr.fraction != 1.0 &&
03220                         tr.entityNum != ENTITYNUM_NONE)
03221                 {
03222                         if (!g_entities[tr.entityNum].client && g_entities[tr.entityNum].s.eType == ET_NPC)
03223                         { //g2animent
03224                                 if (g_entities[tr.entityNum].s.genericenemyindex < level.time)
03225                                 {
03226                                         g_entities[tr.entityNum].s.genericenemyindex = level.time + 2000;
03227                                 }
03228                         }
03229 
03230                         numListedEntities = 0;
03231                         entityList[numListedEntities] = tr.entityNum;
03232 
03233                         if (pull)
03234                         {
03235                                 if (!ForcePowerUsableOn(self, &g_entities[tr.entityNum], FP_PULL))
03236                                 {
03237                                         return;
03238                                 }
03239                         }
03240                         else
03241                         {
03242                                 if (!ForcePowerUsableOn(self, &g_entities[tr.entityNum], FP_PUSH))
03243                                 {
03244                                         return;
03245                                 }
03246                         }
03247                         numListedEntities++;
03248                 }
03249                 else
03250                 {
03251                         //didn't get anything, so just
03252                         return;
03253                 }
03254         }
03255         else
03256         {
03257                 numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
03258 
03259                 e = 0;
03260 
03261                 while (e < numListedEntities)
03262                 {
03263                         ent = &g_entities[entityList[e]];
03264 
03265                         if (!ent->client && ent->s.eType == ET_NPC)
03266                         { //g2animent
03267                                 if (ent->s.genericenemyindex < level.time)
03268                                 {
03269                                         ent->s.genericenemyindex = level.time + 2000;
03270                                 }
03271                         }
03272 
03273                         if (ent)
03274                         {
03275                                 if (ent->client)
03276                                 {
03277                                         VectorCopy(ent->client->ps.origin, thispush_org);
03278                                 }
03279                                 else
03280                                 {
03281                                         VectorCopy(ent->s.pos.trBase, thispush_org);
03282                                 }
03283                         }
03284 
03285                         if (ent)
03286                         { //not in the arc, don't consider it
03287                                 VectorCopy(self->client->ps.origin, tto);
03288                                 tto[2] += self->client->ps.viewheight;
03289                                 VectorSubtract(thispush_org, tto, a);
03290                                 vectoangles(a, a);
03291 
03292                                 if (ent->client && !InFieldOfVision(self->client->ps.viewangles, visionArc, a) &&
03293                                         ForcePowerUsableOn(self, ent, powerUse))
03294                                 { //only bother with arc rules if the victim is a client
03295                                         entityList[e] = ENTITYNUM_NONE;
03296                                 }
03297                                 else if (ent->client)
03298                                 {
03299                                         if (pull)
03300                                         {
03301                                                 if (!ForcePowerUsableOn(self, ent, FP_PULL))
03302                                                 {
03303                                                         entityList[e] = ENTITYNUM_NONE;
03304                                                 }
03305                                         }
03306                                         else
03307                                         {
03308                                                 if (!ForcePowerUsableOn(self, ent, FP_PUSH))
03309                                                 {
03310                                                         entityList[e] = ENTITYNUM_NONE;
03311                                                 }
03312                                         }
03313                                 }
03314                         }
03315                         e++;
03316                 }
03317         }
03318 
03319         for ( e = 0 ; e < numListedEntities ; e++ ) 
03320         {
03321                 if (entityList[e] != ENTITYNUM_NONE &&
03322                         entityList[e] >= 0 &&
03323                         entityList[e] < MAX_GENTITIES)
03324                 {
03325                         ent = &g_entities[entityList[e]];
03326                 }
03327                 else
03328                 {
03329                         ent = NULL;
03330                 }
03331 
03332                 if (!ent)
03333                         continue;
03334                 if (ent == self)
03335                         continue;
03336                 if (ent->client && OnSameTeam(ent, self))
03337                 {
03338                         continue;
03339                 }
03340                 if ( !(ent->inuse) )
03341                         continue;
03342                 if ( ent->s.eType != ET_MISSILE )
03343                 {
03344                         if ( ent->s.eType != ET_ITEM )
03345                         {
03346                                 //FIXME: need pushable objects
03347                                 if ( Q_stricmp( "func_button", ent->classname ) == 0 )
03348                                 {//we might push it
03349                                         if ( pull || !(ent->spawnflags&SPF_BUTTON_FPUSHABLE) )
03350                                         {//not force-pushable, never pullable
03351                                                 continue;
03352                                         }
03353                                 }
03354                                 else
03355                                 {
03356                                         if ( ent->s.eFlags & EF_NODRAW )
03357                                         {
03358                                                 continue;
03359                                         }
03360                                         if ( !ent->client )
03361                                         {
03362                                                 if ( Q_stricmp( "lightsaber", ent->classname ) != 0 )
03363                                                 {//not a lightsaber 
03364                                                         if ( Q_stricmp( "func_door", ent->classname ) != 0 || !(ent->spawnflags & 2/*MOVER_FORCE_ACTIVATE*/) )
03365                                                         {//not a force-usable door
03366                                                                 if ( Q_stricmp( "func_static", ent->classname ) != 0 || (!(ent->spawnflags&1/*F_PUSH*/)&&!(ent->spawnflags&2/*F_PULL*/)) )
03367                                                                 {//not a force-usable func_static
03368                                                                         if ( Q_stricmp( "limb", ent->classname ) )
03369                                                                         {//not a limb
03370                                                                                 continue;
03371                                                                         }
03372                                                                 }
03373                                                         }
03374                                                         else if ( ent->moverState != MOVER_POS1 && ent->moverState != MOVER_POS2 )
03375                                                         {//not at rest
03376                                                                 continue;
03377                                                         }
03378                                                 }
03379                                         }
03380                                         else if ( ent->client->NPC_class == CLASS_GALAKMECH 
03381                                                 || ent->client->NPC_class == CLASS_ATST
03382                                                 || ent->client->NPC_class == CLASS_RANCOR )
03383                                         {//can't push ATST or Galak or Rancor
03384                                                 continue;
03385                                         }
03386                                 }
03387                         }
03388                 }
03389                 else
03390                 {
03391                         if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags&EF_MISSILE_STICK) )
03392                         {//can't force-push/pull stuck missiles (detpacks, tripmines)
03393                                 continue;
03394                         }
03395                         if ( ent->s.pos.trType == TR_STATIONARY && ent->s.weapon != WP_THERMAL )
03396                         {//only thermal detonators can be pushed once stopped
03397                                 continue;
03398                         }
03399                 }
03400 
03401                 //this is all to see if we need to start a saber attack, if it's in flight, this doesn't matter
03402                 // find the distance from the edge of the bounding box
03403                 for ( i = 0 ; i < 3 ; i++ ) 
03404                 {
03405                         if ( center[i] < ent->r.absmin[i] ) 
03406                         {
03407                                 v[i] = ent->r.absmin[i] - center[i];
03408                         } else if ( center[i] > ent->r.absmax[i] ) 
03409                         {
03410                                 v[i] = center[i] - ent->r.absmax[i];
03411                         } else 
03412                         {
03413                                 v[i] = 0;
03414                         }
03415                 }
03416 
03417                 VectorSubtract( ent->r.absmax, ent->r.absmin, size );
03418                 VectorMA( ent->r.absmin, 0.5, size, ent_org );
03419 
03420                 VectorSubtract( ent_org, center, dir );
03421                 VectorNormalize( dir );
03422                 if ( (dot1 = DotProduct( dir, forward )) < 0.6 )
03423                         continue;
03424 
03425                 dist = VectorLength( v );
03426 
03427                 //Now check and see if we can actually deflect it
03428                 //method1
03429                 //if within a certain range, deflect it
03430                 if ( dist >= radius ) 
03431                 {
03432                         continue;
03433                 }
03434         
03435                 //in PVS?
03436                 if ( !ent->r.bmodel && !trap_InPVS( ent_org, self->client->ps.origin ) )
03437                 {//must be in PVS
03438                         continue;
03439                 }
03440 
03441                 //really should have a clear LOS to this thing...
03442                 trap_Trace( &tr, self->client->ps.origin, vec3_origin, vec3_origin, ent_org, self->s.number, MASK_SHOT );
03443                 if ( tr.fraction < 1.0f && tr.entityNum != ent->s.number )
03444                 {//must have clear LOS
03445                         //try from eyes too before you give up
03446                         vec3_t eyePoint;
03447                         VectorCopy(self->client->ps.origin, eyePoint);
03448                         eyePoint[2] += self->client->ps.viewheight;
03449                         trap_Trace( &tr, eyePoint, vec3_origin, vec3_origin, ent_org, self->s.number, MASK_SHOT );
03450 
03451                         if ( tr.fraction < 1.0f && tr.entityNum != ent->s.number )
03452                         {
03453                                 continue;
03454                         }
03455                 }
03456 
03457                 // ok, we are within the radius, add us to the incoming list
03458                 push_list[ent_count] = ent;
03459                 ent_count++;
03460         }
03461 
03462         if ( ent_count )
03463         {
03464                 //method1:
03465                 for ( x = 0; x < ent_count; x++ )
03466                 {
03467                         int modPowerLevel = powerLevel;
03468 
03469         
03470                         if (push_list[x]->client)
03471                         {
03472                                 modPowerLevel = WP_AbsorbConversion(push_list[x], push_list[x]->client->ps.fd.forcePowerLevel[FP_ABSORB], self, powerUse, powerLevel, forcePowerNeeded[self->client->ps.fd.forcePowerLevel[powerUse]][powerUse]);
03473                                 if (modPowerLevel == -1)
03474                                 {
03475                                         modPowerLevel = powerLevel;
03476                                 }
03477                         }
03478 
03479                         pushPower = 256*modPowerLevel;
03480 
03481                         if (push_list[x]->client)
03482                         {
03483                                 VectorCopy(push_list[x]->client->ps.origin, thispush_org);
03484                         }
03485                         else
03486                         {
03487                                 VectorCopy(push_list[x]->s.origin, thispush_org);
03488                         }
03489 
03490                         if ( push_list[x]->client )
03491                         {//FIXME: make enemy jedi able to hunker down and resist this?
03492                                 int otherPushPower = push_list[x]->client->ps.fd.forcePowerLevel[powerUse];
03493                                 qboolean canPullWeapon = qtrue;
03494                                 float dirLen = 0;
03495 
03496                                 if ( g_debugMelee.integer )
03497                                 {
03498                                         if ( (push_list[x]->client->ps.pm_flags&PMF_STUCK_TO_WALL) )
03499                                         {//no resistance if stuck to wall
03500                                                 //push/pull them off the wall
03501                                                 otherPushPower = 0;
03502                                                 G_LetGoOfWall( push_list[x] );
03503                                         }
03504                                 }
03505 
03506                                 knockback = pull?0:200;
03507 
03508                                 pushPowerMod = pushPower;
03509 
03510                                 if (push_list[x]->client->pers.cmd.forwardmove ||
03511                                         push_list[x]->client->pers.cmd.rightmove)
03512                                 { //if you are moving, you get one less level of defense
03513                                         otherPushPower--;
03514 
03515                                         if (otherPushPower < 0)
03516                                         {
03517                                                 otherPushPower = 0;
03518                                         }
03519                                 }
03520 
03521                                 if (otherPushPower && CanCounterThrow(push_list[x], self, pull))
03522                                 {
03523                                         if ( pull )
03524                                         {
03525                                                 G_Sound( push_list[x], CHAN_BODY, G_SoundIndex( "sound/weapons/force/pull.wav" ) );
03526                                                 push_list[x]->client->ps.forceHandExtend = HANDEXTEND_FORCEPULL;
03527                                                 push_list[x]->client->ps.forceHandExtendTime = level.time + 400;
03528                                         }
03529                                         else
03530                                         {
03531                                                 G_Sound( push_list[x], CHAN_BODY, G_SoundIndex( "sound/weapons/force/push.wav" ) );
03532                                                 push_list[x]->client->ps.forceHandExtend = HANDEXTEND_FORCEPUSH;
03533                                                 push_list[x]->client->ps.forceHandExtendTime = level.time + 1000;
03534                                         }
03535                                         push_list[x]->client->ps.powerups[PW_DISINT_4] = push_list[x]->client->ps.forceHandExtendTime + 200;
03536 
03537                                         if (pull)
03538                                         {
03539                                                 push_list[x]->client->ps.powerups[PW_PULL] = push_list[x]->client->ps.powerups[PW_DISINT_4];
03540                                         }
03541                                         else
03542                                         {
03543                                                 push_list[x]->client->ps.powerups[PW_PULL] = 0;
03544                                         }
03545 
03546                                         //Make a counter-throw effect
03547 
03548                                         if (otherPushPower >= modPowerLevel)
03549                                         {
03550                                                 pushPowerMod = 0;
03551                                                 canPullWeapon = qfalse;
03552                                         }
03553                                         else
03554                                         {
03555                                                 int powerDif = (modPowerLevel - otherPushPower);
03556 
03557                                                 if (powerDif >= 3)
03558                                                 {
03559                                                         pushPowerMod -= pushPowerMod*0.2;
03560                                                 }
03561                                                 else if (powerDif == 2)
03562                                                 {
03563                                                         pushPowerMod -= pushPowerMod*0.4;
03564                                                 }
03565                                                 else if (powerDif == 1)
03566                                                 {
03567                                                         pushPowerMod -= pushPowerMod*0.8;
03568                                                 }
03569 
03570                                                 if (pushPowerMod < 0)
03571                                                 {
03572                                                         pushPowerMod = 0;
03573                                                 }
03574                                         }
03575                                 }
03576 
03577                                 //shove them
03578                                 if ( pull )
03579                                 {
03580                                         VectorSubtract( self->client->ps.origin, thispush_org, pushDir );
03581 
03582                                         if (push_list[x]->client && VectorLength(pushDir) <= 256)
03583                                         {
03584                                                 int randfact = 0;
03585 
03586                                                 if (modPowerLevel == FORCE_LEVEL_1)
03587                                                 {
03588                                                         randfact = 3;
03589                                                 }
03590                                                 else if (modPowerLevel == FORCE_LEVEL_2)
03591                                                 {
03592                                                         randfact = 7;
03593                                                 }
03594                                                 else if (modPowerLevel == FORCE_LEVEL_3)
03595                                                 {
03596                                                         randfact = 10;
03597                                                 }
03598 
03599                                                 if (!OnSameTeam(self, push_list[x]) && Q_irand(1, 10) <= randfact && canPullWeapon)
03600                                                 {
03601                                                         vec3_t uorg, vecnorm;
03602 
03603                                                         VectorCopy(self->client->ps.origin, uorg);
03604                                                         uorg[2] += 64;
03605 
03606                                                         VectorSubtract(uorg, thispush_org, vecnorm);
03607                                                         VectorNormalize(vecnorm);
03608 
03609                                                         TossClientWeapon(push_list[x], vecnorm, 500);
03610                                                 }
03611                                         }
03612                                 }
03613                                 else
03614                                 {
03615                                         VectorSubtract( thispush_org, self->client->ps.origin, pushDir );
03616                                 }
03617 
03618                                 if ((modPowerLevel > otherPushPower || push_list[x]->client->ps.m_iVehicleNum) && push_list[x]->client)
03619                                 {
03620                                         if (modPowerLevel == FORCE_LEVEL_3 &&
03621                                                 push_list[x]->client->ps.forceHandExtend != HANDEXTEND_KNOCKDOWN)
03622                                         {
03623                                                 dirLen = VectorLength(pushDir);
03624 
03625                                                 if (BG_KnockDownable(&push_list[x]->client->ps) &&
03626                                                         dirLen <= (64*((modPowerLevel - otherPushPower)-1)))
03627                                                 { //can only do a knockdown if fairly close
03628                                                         push_list[x]->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
03629                                                         push_list[x]->client->ps.forceHandExtendTime = level.time + 700;
03630                                                         push_list[x]->client->ps.forceDodgeAnim = 0; //this toggles between 1 and 0, when it's 1 we should play the get up anim
03631                                                         push_list[x]->client->ps.quickerGetup = qtrue;
03632                                                 }
03633                                                 else if (push_list[x]->s.number < MAX_CLIENTS && push_list[x]->client->ps.m_iVehicleNum &&
03634                                                         dirLen <= 128.0f )
03635                                                 { //a player on a vehicle
03636                                                         gentity_t *vehEnt = &g_entities[push_list[x]->client->ps.m_iVehicleNum];
03637                                                         if (vehEnt->inuse && vehEnt->client && vehEnt->m_pVehicle)
03638                                                         {
03639                                                                 if (vehEnt->m_pVehicle->m_pVehicleInfo->type == VH_SPEEDER ||
03640                                                                         vehEnt->m_pVehicle->m_pVehicleInfo->type == VH_ANIMAL)
03641                                                                 { //push the guy off
03642                                                                         vehEnt->m_pVehicle->m_pVehicleInfo->Eject(vehEnt->m_pVehicle, (bgEntity_t *)push_list[x], qfalse);
03643                                                                 }
03644                                                         }
03645                                                 }
03646                                         }
03647                                 }
03648 
03649                                 if (!dirLen)
03650                                 {
03651                                         dirLen = VectorLength(pushDir);
03652                                 }
03653 
03654                                 VectorNormalize(pushDir);
03655 
03656                                 if (push_list[x]->client)
03657                                 {
03658                                         //escape a force grip if we're in one
03659                                         if (self->client->ps.fd.forceGripBeingGripped > level.time)
03660                                         { //force the enemy to stop gripping me if I managed to push him
03661                                                 if (push_list[x]->client->ps.fd.forceGripEntityNum == self->s.number)
03662                                                 {
03663                                                         if (modPowerLevel >= push_list[x]->client->ps.fd.forcePowerLevel[FP_GRIP])
03664                                                         { //only break the grip if our push/pull level is >= their grip level
03665                                                                 WP_ForcePowerStop(push_list[x], FP_GRIP);
03666                                                                 self->client->ps.fd.forceGripBeingGripped = 0;
03667                                                                 push_list[x]->client->ps.fd.forceGripUseTime = level.time + 1000; //since we just broke out of it..
03668                                                         }
03669                                                 }
03670                                         }
03671 
03672                                         push_list[x]->client->ps.otherKiller = self->s.number;
03673                                         push_list[x]->client->ps.otherKillerTime = level.time + 5000;
03674                                         push_list[x]->client->ps.otherKillerDebounceTime = level.time + 100;
03675 
03676                                         pushPowerMod -= (dirLen*0.7);
03677                                         if (pushPowerMod < 16)
03678                                         {
03679                                                 pushPowerMod = 16;
03680                                         }
03681 
03682                                         //fullbody push effect
03683                                         push_list[x]->client->pushEffectTime = level.time + 600;
03684 
03685                                         push_list[x]->client->ps.velocity[0] = pushDir[0]*pushPowerMod;
03686                                         push_list[x]->client->ps.velocity[1] = pushDir[1]*pushPowerMod;
03687 
03688                                         if ((int)push_list[x]->client->ps.velocity[2] == 0)
03689                                         { //if not going anywhere vertically, boost them up a bit
03690                                                 push_list[x]->client->ps.velocity[2] = pushDir[2]*pushPowerMod;
03691 
03692                                                 if (push_list[x]->client->ps.velocity[2] < 128)
03693                                                 {
03694                                                         push_list[x]->client->ps.velocity[2] = 128;
03695                                                 }
03696                                         }
03697                                         else
03698                                         {
03699                                                 push_list[x]->client->ps.velocity[2] = pushDir[2]*pushPowerMod;
03700                                         }
03701                                 }
03702                         }
03703                         else if ( push_list[x]->s.eType == ET_MISSILE && push_list[x]->s.pos.trType != TR_STATIONARY && (push_list[x]->s.pos.trType != TR_INTERPOLATE||push_list[x]->s.weapon != WP_THERMAL) )//rolling and stationary thermal detonators are dealt with below
03704                         {
03705                                 if ( pull )
03706                                 {//deflect rather than reflect?
03707                                 }
03708                                 else 
03709                                 {
03710                                         G_ReflectMissile( self, push_list[x], forward );
03711                                 }
03712                         }
03713                         else if ( !Q_stricmp( "func_static", push_list[x]->classname ) )
03714                         {//force-usable func_static
03715                                 if ( !pull && (push_list[x]->spawnflags&1/*F_PUSH*/) )
03716                                 {
03717                                         GEntity_UseFunc( push_list[x], self, self );
03718                                 }
03719                                 else if ( pull && (push_list[x]->spawnflags&2/*F_PULL*/) )
03720                                 {
03721                                         GEntity_UseFunc( push_list[x], self, self );
03722                                 }
03723                         }
03724                         else if ( !Q_stricmp( "func_door", push_list[x]->classname ) && (push_list[x]->spawnflags&2) )
03725                         {//push/pull the door
03726                                 vec3_t  pos1, pos2;
03727                                 vec3_t  trFrom;
03728 
03729                                 VectorCopy(self->client->ps.origin, trFrom);
03730                                 trFrom[2] += self->client->ps.viewheight;
03731 
03732                                 AngleVectors( self->client->ps.viewangles, forward, NULL, NULL );
03733                                 VectorNormalize( forward );
03734                                 VectorMA( trFrom, radius, forward, end );
03735                                 trap_Trace( &tr, trFrom, vec3_origin, vec3_origin, end, self->s.number, MASK_SHOT );
03736                                 if ( tr.entityNum != push_list[x]->s.number || tr.fraction == 1.0 || tr.allsolid || tr.startsolid )
03737                                 {//must be pointing right at it
03738                                         continue;
03739                                 }
03740 
03741                                 if ( VectorCompare( vec3_origin, push_list[x]->s.origin ) )
03742                                 {//does not have an origin brush, so pos1 & pos2 are relative to world origin, need to calc center
03743                                         VectorSubtract( push_list[x]->r.absmax, push_list[x]->r.absmin, size );
03744                                         VectorMA( push_list[x]->r.absmin, 0.5, size, center );
03745                                         if ( (push_list[x]->spawnflags&1) && push_list[x]->moverState == MOVER_POS1 )
03746                                         {//if at pos1 and started open, make sure we get the center where it *started* because we're going to add back in the relative values pos1 and pos2
03747                                                 VectorSubtract( center, push_list[x]->pos1, center );
03748                                         }
03749                                         else if ( !(push_list[x]->spawnflags&1) && push_list[x]->moverState == MOVER_POS2 )
03750                                         {//if at pos2, make sure we get the center where it *started* because we're going to add back in the relative values pos1 and pos2
03751                                                 VectorSubtract( center, push_list[x]->pos2, center );
03752                                         }
03753                                         VectorAdd( center, push_list[x]->pos1, pos1 );
03754                                         VectorAdd( center, push_list[x]->pos2, pos2 );
03755                                 }
03756                                 else
03757                                 {//actually has an origin, pos1 and pos2 are absolute
03758                                         VectorCopy( push_list[x]->r.currentOrigin, center );
03759                                         VectorCopy( push_list[x]->pos1, pos1 );
03760                                         VectorCopy( push_list[x]->pos2, pos2 );
03761                                 }
03762 
03763                                 if ( Distance( pos1, trFrom ) < Distance( pos2, trFrom ) )
03764                                 {//pos1 is closer
03765                                         if ( push_list[x]->moverState == MOVER_POS1 )
03766                                         {//at the closest pos
03767                                                 if ( pull )
03768                                                 {//trying to pull, but already at closest point, so screw it
03769                                                         continue;
03770                                                 }
03771                                         }
03772                                         else if ( push_list[x]->moverState == MOVER_POS2 )
03773                                         {//at farthest pos
03774                                                 if ( !pull )
03775                                                 {//trying to push, but already at farthest point, so screw it
03776                                                         continue;
03777                                                 }
03778                                         }
03779                                 }
03780                                 else
03781                                 {//pos2 is closer
03782                                         if ( push_list[x]->moverState == MOVER_POS1 )
03783                                         {//at the farthest pos
03784                                                 if ( !pull )
03785                                                 {//trying to push, but already at farthest point, so screw it
03786                                                         continue;
03787                                                 }
03788                                         }
03789                                         else if ( push_list[x]->moverState == MOVER_POS2 )
03790                                         {//at closest pos
03791                                                 if ( pull )
03792                                                 {//trying to pull, but already at closest point, so screw it
03793                                                         continue;
03794                                                 }
03795                                         }
03796                                 }
03797                                 GEntity_UseFunc( push_list[x], self, self );
03798                         }
03799                         else if ( Q_stricmp( "func_button", push_list[x]->classname ) == 0 )
03800                         {//pretend you pushed it
03801                                 Touch_Button( push_list[x], self, NULL );
03802                                 continue;
03803                         }
03804                 }
03805         }
03806 
03807         //attempt to break any leftover grips
03808         //if we're still in a current grip that wasn't broken by the push, it will still remain
03809         self->client->dangerTime = level.time;
03810         self->client->ps.eFlags &= ~EF_INVULNERABLE;
03811         self->client->invulnerableTimer = 0;
03812 
03813         if (self->client->ps.fd.forceGripBeingGripped > level.time)
03814         {
03815                 self->client->ps.fd.forceGripBeingGripped = 0;
03816         }
03817 }

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 }

void G_CreateG2AttachedWeaponModel gentity_t ent,
const char *  weaponModel,
int  boltNum,
int  weaponNum
 

qboolean G_ExpandPointToBBox vec3_t  point,
const vec3_t  mins,
const vec3_t  maxs,
int  ignore,
int  clipmask
 

Definition at line 2087 of file g_utils.c.

02088 {
02089         trace_t tr;
02090         vec3_t  start, end;
02091         int i;
02092 
02093         VectorCopy( point, start );
02094         
02095         for ( i = 0; i < 3; i++ )
02096         {
02097                 VectorCopy( start, end );
02098                 end[i] += mins[i];
02099                 trap_Trace( &tr, start, vec3_origin, vec3_origin, end, ignore, clipmask );
02100                 if ( tr.allsolid || tr.startsolid )
02101                 {
02102                         return qfalse;
02103                 }
02104                 if ( tr.fraction < 1.0 )
02105                 {
02106                         VectorCopy( start, end );
02107                         end[i] += maxs[i]-(mins[i]*tr.fraction);
02108                         trap_Trace( &tr, start, vec3_origin, vec3_origin, end, ignore, clipmask );
02109                         if ( tr.allsolid || tr.startsolid )
02110                         {
02111                                 return qfalse;
02112                         }
02113                         if ( tr.fraction < 1.0 )
02114                         {
02115                                 return qfalse;
02116                         }
02117                         VectorCopy( end, start );
02118                 }
02119         }
02120         //expanded it, now see if it's all clear
02121         trap_Trace( &tr, start, mins, maxs, start, ignore, clipmask );
02122         if ( tr.allsolid || tr.startsolid )
02123         {
02124                 return qfalse;
02125         }
02126         VectorCopy( start, point );
02127         return qtrue;
02128 }

qboolean G_FindClosestPointOnLineSegment const vec3_t  start,
const vec3_t  end,
const vec3_t  from,
vec3_t  result
 

Definition at line 1524 of file q_math.c.

References cos(), DEG2RAD, DotProductNormalize(), qboolean, qfalse, qtrue, vec3_t, VectorCopy, VectorMA, VectorNormalize(), and VectorSubtract.

Referenced by NAV_MoveToGoal(), and ShortestLineSegBewteen2LineSegs().

01525 {
01526         vec3_t  vecStart2From, vecStart2End, vecEnd2Start, vecEnd2From;
01527         float   distEnd2From, distEnd2Result, theta, cos_theta, dot;
01528 
01529         //Find the perpendicular vector to vec from start to end
01530         VectorSubtract( from, start, vecStart2From);
01531         VectorSubtract( end, start, vecStart2End);
01532 
01533         dot = DotProductNormalize( vecStart2From, vecStart2End );
01534 
01535         if ( dot <= 0 )
01536         {
01537                 //The perpendicular would be beyond or through the start point
01538                 VectorCopy( start, result );
01539                 return qfalse;
01540         }
01541 
01542         if ( dot == 1 )
01543         {
01544                 //parallel, closer of 2 points will be the target
01545                 if( (VectorLengthSquared( vecStart2From )) < (VectorLengthSquared( vecStart2End )) )
01546                 {
01547                         VectorCopy( from, result );
01548                 }
01549                 else
01550                 {
01551                         VectorCopy( end, result );
01552                 }
01553                 return qfalse;
01554         }
01555 
01556         //Try other end
01557         VectorSubtract( from, end, vecEnd2From);
01558         VectorSubtract( start, end, vecEnd2Start);
01559 
01560         dot = DotProductNormalize( vecEnd2From, vecEnd2Start );
01561 
01562         if ( dot <= 0 )
01563         {//The perpendicular would be beyond or through the start point
01564                 VectorCopy( end, result );
01565                 return qfalse;
01566         }
01567 
01568         if ( dot == 1 )
01569         {//parallel, closer of 2 points will be the target
01570                 if( (VectorLengthSquared( vecEnd2From )) < (VectorLengthSquared( vecEnd2Start )))
01571                 {
01572                         VectorCopy( from, result );
01573                 }
01574                 else
01575                 {
01576                         VectorCopy( end, result );
01577                 }
01578                 return qfalse;
01579         }
01580 
01581         //                    /|
01582         //                c  / |
01583         //                  /  |a
01584         //      theta  /)__|    
01585         //                    b
01586         //cos(theta) = b / c
01587         //solve for b
01588         //b = cos(theta) * c
01589 
01590         //angle between vecs end2from and end2start, should be between 0 and 90
01591         theta = 90 * (1 - dot);//theta
01592         
01593         //Get length of side from End2Result using sine of theta
01594         distEnd2From = VectorLength( vecEnd2From );//c
01595         cos_theta = cos(DEG2RAD(theta));//cos(theta)
01596         distEnd2Result = cos_theta * distEnd2From;//b
01597 
01598         //Extrapolate to find result
01599         VectorNormalize( vecEnd2Start );
01600         VectorMA( end, distEnd2Result, vecEnd2Start, result );
01601         
01602         //perpendicular intersection is between the 2 endpoints
01603         return qtrue;
01604 }

qboolean G_GetHitLocFromSurfName gentity_t ent,
const char *  surfName,
int *  hitLoc,
vec3_t  point,
vec3_t  dir,
vec3_t  bladeDir,
int  mod
 

Definition at line 3632 of file g_combat.c.

References AngleVectors(), renderInfo_s::boltValidityTime, CLASS_ATST, CLASS_GALAKMECH, CLASS_GONK, CLASS_INTERROGATOR, CLASS_MARK1, CLASS_MARK2, CLASS_MOUSE, CLASS_PROBE, CLASS_PROTOCOL, CLASS_R2D2, CLASS_SENTRY, gentity_s::client, entityShared_t::currentAngles, entityShared_t::currentOrigin, DotProduct, g_dismember, gentity_t, gentity_s::ghoul2, HL_ARM_LT, HL_ARM_RT, HL_BACK, HL_BACK_LT, HL_BACK_RT, HL_CHEST, HL_CHEST_LT, HL_CHEST_RT, HL_FOOT_LT, HL_FOOT_RT, HL_GENERIC1, HL_GENERIC2, HL_GENERIC3, HL_GENERIC4, HL_GENERIC5, HL_GENERIC6, HL_HAND_LT, HL_HAND_RT, HL_HEAD, HL_LEG_LT, HL_LEG_RT, HL_NONE, HL_WAIST, vmCvar_t::integer, level, gentity_s::localAnimIndex, MOD_SABER, gentity_s::modelScale, NEGATIVE_Y, gclient_s::NPC_class, NULL, playerState_s::origin, ORIGIN, gclient_s::ps, Q_stricmp(), Q_strncmp(), qboolean, qfalse, qtrue, gentity_s::r, gclient_s::renderInfo, level_locals_t::time, renderInfo_s::torsoAngles, renderInfo_s::torsoPoint, trap_G2API_AddBolt(), trap_G2API_GetBoltMatrix(), UpdateClientRenderBolts(), vec3_t, VectorSet, VectorSubtract, playerState_s::viewangles, and YAW.

Referenced by G_CheckForDismemberment(), G_Damage(), and G_LocationBasedDamageModifier().

03633 {
03634         qboolean dismember = qfalse;
03635         int actualTime;
03636         int kneeLBolt = -1;
03637         int kneeRBolt = -1;
03638         int handRBolt = -1;
03639         int handLBolt = -1;
03640         int footRBolt = -1;
03641         int footLBolt = -1;
03642 
03643         *hitLoc = HL_NONE;
03644 
03645         if ( !surfName || !surfName[0] )
03646         {
03647                 return qfalse;
03648         }
03649 
03650         if( !ent->client )
03651         {
03652                 return qfalse;
03653         }
03654 
03655         if (!point)
03656         {
03657                 return qfalse;
03658         }
03659 
03660         if ( ent->client 
03661                 && ( ent->client->NPC_class == CLASS_R2D2 
03662                         || ent->client->NPC_class == CLASS_R2D2 
03663                         || ent->client->NPC_class == CLASS_GONK
03664                         || ent->client->NPC_class == CLASS_MOUSE
03665                         || ent->client->NPC_class == CLASS_SENTRY
03666                         || ent->client->NPC_class == CLASS_INTERROGATOR
03667                         || ent->client->NPC_class == CLASS_SENTRY
03668                         || ent->client->NPC_class == CLASS_PROBE ) )
03669         {//we don't care about per-surface hit-locations or dismemberment for these guys 
03670                 return qfalse;
03671         }
03672 
03673         if (ent->localAnimIndex <= 1)
03674         { //humanoid
03675                 handLBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*l_hand");
03676                 handRBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*r_hand");
03677                 kneeLBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*hips_l_knee");
03678                 kneeRBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*hips_r_knee");
03679                 footLBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*l_leg_foot");
03680                 footRBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*r_leg_foot");
03681         }
03682 
03683         if ( ent->client && (ent->client->NPC_class == CLASS_ATST) )
03684         {
03685                 //FIXME: almost impossible to hit these... perhaps we should
03686                 //              check for splashDamage and do radius damage to these parts?
03687                 //              Or, if we ever get bbox G2 traces, that may fix it, too
03688                 if (!Q_stricmp("head_light_blaster_cann",surfName))
03689                 {
03690                         *hitLoc = HL_ARM_LT;
03691                 }
03692                 else if (!Q_stricmp("head_concussion_charger",surfName))
03693                 {
03694                         *hitLoc = HL_ARM_RT;
03695                 }
03696                 return(qfalse);
03697         }
03698         else if ( ent->client && (ent->client->NPC_class == CLASS_MARK1) )
03699         {
03700                 if (!Q_stricmp("l_arm",surfName))
03701                 {
03702                         *hitLoc = HL_ARM_LT;
03703                 }
03704                 else if (!Q_stricmp("r_arm",surfName))
03705                 {
03706                         *hitLoc = HL_ARM_RT;
03707                 }
03708                 else if (!Q_stricmp("torso_front",surfName))
03709                 {
03710                         *hitLoc = HL_CHEST;
03711                 }
03712                 else if (!Q_stricmp("torso_tube1",surfName))
03713                 {
03714                         *hitLoc = HL_GENERIC1;
03715                 }
03716                 else if (!Q_stricmp("torso_tube2",surfName))
03717                 {
03718                         *hitLoc = HL_GENERIC2;
03719                 }
03720                 else if (!Q_stricmp("torso_tube3",surfName))
03721                 {
03722                         *hitLoc = HL_GENERIC3;
03723                 }
03724                 else if (!Q_stricmp("torso_tube4",surfName))
03725                 {
03726                         *hitLoc = HL_GENERIC4;
03727                 }
03728                 else if (!Q_stricmp("torso_tube5",surfName))
03729                 {
03730                         *hitLoc = HL_GENERIC5;
03731                 }
03732                 else if (!Q_stricmp("torso_tube6",surfName))
03733                 {
03734                         *hitLoc = HL_GENERIC6;
03735                 }
03736                 return(qfalse);
03737         }
03738         else if ( ent->client && (ent->client->NPC_class == CLASS_MARK2) )
03739         {
03740                 if (!Q_stricmp("torso_canister1",surfName))
03741                 {
03742                         *hitLoc = HL_GENERIC1;
03743                 }
03744                 else if (!Q_stricmp("torso_canister2",surfName))
03745                 {
03746                         *hitLoc = HL_GENERIC2;
03747                 }
03748                 else if (!Q_stricmp("torso_canister3",surfName))
03749                 {
03750                         *hitLoc = HL_GENERIC3;
03751                 }
03752                 return(qfalse);
03753         }
03754         else if ( ent->client && (ent->client->NPC_class == CLASS_GALAKMECH) )
03755         {
03756                 if (!Q_stricmp("torso_antenna",surfName)||!Q_stricmp("torso_antenna_base",surfName))
03757                 {
03758                         *hitLoc = HL_GENERIC1;
03759                 }
03760                 else if (!Q_stricmp("torso_shield",surfName))
03761                 {
03762                         *hitLoc = HL_GENERIC2;
03763                 }
03764                 else
03765                 {
03766                         *hitLoc = HL_CHEST;
03767                 }
03768                 return(qfalse);
03769         }
03770 
03771         //FIXME: check the hitLoc and hitDir against the cap tag for the place 
03772         //where the split will be- if the hit dir is roughly perpendicular to 
03773         //the direction of the cap, then the split is allowed, otherwise we
03774         //hit it at the wrong angle and should not dismember...
03775         actualTime = level.time;
03776         if ( !Q_strncmp( "hips", surfName, 4 ) )
03777         {//FIXME: test properly for legs
03778                 *hitLoc = HL_WAIST;
03779                 if ( ent->client != NULL && ent->ghoul2 )
03780                 {
03781                         mdxaBone_t      boltMatrix;
03782                         vec3_t  tagOrg, angles;
03783 
03784                         VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03785                         if (kneeLBolt>=0)
03786                         {
03787                                 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, kneeLBolt, 
03788                                                                 &boltMatrix, angles, ent->r.currentOrigin,
03789                                                                 actualTime, NULL, ent->modelScale );
03790                                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03791                                 if ( DistanceSquared( point, tagOrg ) < 100 )
03792                                 {//actually hit the knee
03793                                         *hitLoc = HL_LEG_LT;
03794                                 }
03795                         }
03796                         if (*hitLoc == HL_WAIST)
03797                         {
03798                                 if (kneeRBolt>=0)
03799                                 {
03800                                         trap_G2API_GetBoltMatrix( ent->ghoul2, 0, kneeRBolt, 
03801                                                                         &boltMatrix, angles, ent->r.currentOrigin,
03802                                                                         actualTime, NULL, ent->modelScale );
03803                                         BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03804                                         if ( DistanceSquared( point, tagOrg ) < 100 )
03805                                         {//actually hit the knee
03806                                                 *hitLoc = HL_LEG_RT;
03807                                         }
03808                                 }
03809                         }
03810                 }
03811         }
03812         else if ( !Q_strncmp( "torso", surfName, 5 ) )
03813         {
03814                 if ( !ent->client )
03815                 {
03816                         *hitLoc = HL_CHEST;
03817                 }
03818                 else
03819                 {
03820                         vec3_t  t_fwd, t_rt, t_up, dirToImpact;
03821                         float frontSide, rightSide, upSide;
03822                         AngleVectors( ent->client->renderInfo.torsoAngles, t_fwd, t_rt, t_up );
03823 
03824                         if (ent->client->renderInfo.boltValidityTime != level.time)
03825                         {
03826                                 vec3_t renderAng;
03827 
03828                                 renderAng[0] = 0;
03829                                 renderAng[1] = ent->client->ps.viewangles[YAW];
03830                                 renderAng[2] = 0;
03831 
03832                                 UpdateClientRenderBolts(ent, ent->client->ps.origin, renderAng);
03833                         }
03834 
03835                         VectorSubtract( point, ent->client->renderInfo.torsoPoint, dirToImpact );
03836                         frontSide = DotProduct( t_fwd, dirToImpact );
03837                         rightSide = DotProduct( t_rt, dirToImpact );
03838                         upSide = DotProduct( t_up, dirToImpact );
03839                         if ( upSide < -10 )
03840                         {//hit at waist
03841                                 *hitLoc = HL_WAIST;
03842                         }
03843                         else
03844                         {//hit on upper torso
03845                                 if ( rightSide > 4 )
03846                                 {
03847                                         *hitLoc = HL_ARM_RT;
03848                                 }
03849                                 else if ( rightSide < -4 )
03850                                 {
03851                                         *hitLoc = HL_ARM_LT;
03852                                 }
03853                                 else if ( rightSide > 2 )
03854                                 {
03855                                         if ( frontSide > 0 )
03856                                         {
03857                                                 *hitLoc = HL_CHEST_RT;
03858                                         }
03859                                         else
03860                                         {
03861                                                 *hitLoc = HL_BACK_RT;
03862                                         }
03863                                 }
03864                                 else if ( rightSide < -2 )
03865                                 {
03866                                         if ( frontSide > 0 )
03867                                         {
03868                                                 *hitLoc = HL_CHEST_LT;
03869                                         }
03870                                         else
03871                                         {
03872                                                 *hitLoc = HL_BACK_LT;
03873                                         }
03874                                 }
03875                                 else if ( upSide > -3 && mod == MOD_SABER )
03876                                 {
03877                                         *hitLoc = HL_HEAD;
03878                                 }
03879                                 else if ( frontSide > 0 )
03880                                 {
03881                                         *hitLoc = HL_CHEST;
03882                                 }
03883                                 else
03884                                 {
03885                                         *hitLoc = HL_BACK;
03886                                 }
03887                         }
03888                 }
03889         }
03890         else if ( !Q_strncmp( "head", surfName, 4 ) )
03891         {
03892                 *hitLoc = HL_HEAD;
03893         }
03894         else if ( !Q_strncmp( "r_arm", surfName, 5 ) )
03895         {
03896                 *hitLoc = HL_ARM_RT;
03897                 if ( ent->client != NULL && ent->ghoul2 )
03898                 {
03899                         mdxaBone_t      boltMatrix;
03900                         vec3_t  tagOrg, angles;
03901 
03902                         VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03903                         if (handRBolt>=0)
03904                         {
03905                                 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, handRBolt, 
03906                                                                 &boltMatrix, angles, ent->r.currentOrigin,
03907                                                                 actualTime, NULL, ent->modelScale );
03908                                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03909                                 if ( DistanceSquared( point, tagOrg ) < 256 )
03910                                 {//actually hit the hand
03911                                         *hitLoc = HL_HAND_RT;
03912                                 }
03913                         }
03914                 }
03915         }
03916         else if ( !Q_strncmp( "l_arm", surfName, 5 ) )
03917         {
03918                 *hitLoc = HL_ARM_LT;
03919                 if ( ent->client != NULL && ent->ghoul2 )
03920                 {
03921                         mdxaBone_t      boltMatrix;
03922                         vec3_t  tagOrg, angles;
03923 
03924                         VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03925                         if (handLBolt>=0)
03926                         {
03927                                 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, handLBolt, 
03928                                                                 &boltMatrix, angles, ent->r.currentOrigin,
03929                                                                 actualTime, NULL, ent->modelScale );
03930                                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03931                                 if ( DistanceSquared( point, tagOrg ) < 256 )
03932                                 {//actually hit the hand
03933                                         *hitLoc = HL_HAND_LT;
03934                                 }
03935                         }
03936                 }
03937         }
03938         else if ( !Q_strncmp( "r_leg", surfName, 5 ) )
03939         {
03940                 *hitLoc = HL_LEG_RT;
03941                 if ( ent->client != NULL && ent->ghoul2 )
03942                 {
03943                         mdxaBone_t      boltMatrix;
03944                         vec3_t  tagOrg, angles;
03945 
03946                         VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03947                         if (footRBolt>=0)
03948                         {
03949                                 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, footRBolt, 
03950                                                                 &boltMatrix, angles, ent->r.currentOrigin,
03951                                                                 actualTime, NULL, ent->modelScale );
03952                                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03953                                 if ( DistanceSquared( point, tagOrg ) < 100 )
03954                                 {//actually hit the foot
03955                                         *hitLoc = HL_FOOT_RT;
03956                                 }
03957                         }
03958                 }
03959         }
03960         else if ( !Q_strncmp( "l_leg", surfName, 5 ) )
03961         {
03962                 *hitLoc = HL_LEG_LT;
03963                 if ( ent->client != NULL && ent->ghoul2 )
03964                 {
03965                         mdxaBone_t      boltMatrix;
03966                         vec3_t  tagOrg, angles;
03967 
03968                         VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03969                         if (footLBolt>=0)
03970                         {
03971                                 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, footLBolt, 
03972                                                                 &boltMatrix, angles, ent->r.currentOrigin,
03973                                                                 actualTime, NULL, ent->modelScale );
03974                                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03975                                 if ( DistanceSquared( point, tagOrg ) < 100 )
03976                                 {//actually hit the foot
03977                                         *hitLoc = HL_FOOT_LT;
03978                                 }
03979                         }
03980                 }
03981         }
03982         else if ( !Q_strncmp( "r_hand", surfName, 6 ) || !Q_strncmp( "w_", surfName, 2 ) )
03983         {//right hand or weapon
03984                 *hitLoc = HL_HAND_RT;
03985         }
03986         else if ( !Q_strncmp( "l_hand", surfName, 6 ) )
03987         {
03988                 *hitLoc = HL_HAND_LT;
03989         }
03990         /*
03991 #ifdef _DEBUG
03992         else
03993         {
03994                 Com_Printf( "ERROR: surface %s does not belong to any hitLocation!!!\n", surfName );
03995         }
03996 #endif //_DEBUG
03997         */
03998 
03999         //if ( g_dismemberment->integer >= 11381138 || !ent->client->dismembered )
04000         if (g_dismember.integer == 100)
04001         { //full probability...
04002                 if ( ent->client && ent->client->NPC_class == CLASS_PROTOCOL )
04003                 {
04004                         dismember = qtrue;
04005                 }
04006                 else if ( dir && (dir[0] || dir[1] || dir[2]) &&
04007                         bladeDir && (bladeDir[0] || bladeDir[1] || bladeDir[2]) )
04008                 {//we care about direction (presumably for dismemberment)
04009                         //if ( g_dismemberProbabilities->value<=0.0f||G_Dismemberable( ent, *hitLoc ) )
04010                         if (1) //Fix me?
04011                         {//either we don't care about probabilties or the probability let us continue
04012                                 char *tagName = NULL;
04013                                 float   aoa = 0.5f;
04014                                 //dir must be roughly perpendicular to the hitLoc's cap bolt
04015                                 switch ( *hitLoc )
04016                                 {
04017                                         case HL_LEG_RT:
04018                                                 tagName = "*hips_cap_r_leg";
04019                                                 break;
04020                                         case HL_LEG_LT:
04021                                                 tagName = "*hips_cap_l_leg";
04022                                                 break;
04023                                         case HL_WAIST:
04024                                                 tagName = "*hips_cap_torso";
04025                                                 aoa = 0.25f;
04026                                                 break;
04027                                         case HL_CHEST_RT:
04028                                         case HL_ARM_RT:
04029                                         case HL_BACK_LT:
04030                                                 tagName = "*torso_cap_r_arm";
04031                                                 break;
04032                                         case HL_CHEST_LT:
04033                                         case HL_ARM_LT:
04034                                         case HL_BACK_RT:
04035                                                 tagName = "*torso_cap_l_arm";
04036                                                 break;
04037                                         case HL_HAND_RT:
04038                                                 tagName = "*r_arm_cap_r_hand";
04039                                                 break;
04040                                         case HL_HAND_LT:
04041                                                 tagName = "*l_arm_cap_l_hand";
04042                                                 break;
04043                                         case HL_HEAD:
04044                                                 tagName = "*torso_cap_head";
04045                                                 aoa = 0.25f;
04046                                                 break;
04047                                         case HL_CHEST:
04048                                         case HL_BACK:
04049                                         case HL_FOOT_RT:
04050                                         case HL_FOOT_LT:
04051                                         default:
04052                                                 //no dismemberment possible with these, so no checks needed
04053                                                 break;
04054                                 }
04055                                 if ( tagName )
04056                                 {
04057                                         int tagBolt = trap_G2API_AddBolt( ent->ghoul2, 0, tagName );
04058                                         if ( tagBolt != -1 )
04059                                         {
04060                                                 mdxaBone_t      boltMatrix;
04061                                                 vec3_t  tagOrg, tagDir, angles;
04062 
04063                                                 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
04064                                                 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, tagBolt, 
04065                                                                                 &boltMatrix, angles, ent->r.currentOrigin,
04066                                                                                 actualTime, NULL, ent->modelScale );
04067                                                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
04068                                                 BG_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_Y, tagDir );
04069                                                 if ( DistanceSquared( point, tagOrg ) < 256 )
04070                                                 {//hit close
04071                                                         float dot = DotProduct( dir, tagDir );
04072                                                         if ( dot < aoa && dot > -aoa )
04073                                                         {//hit roughly perpendicular
04074                                                                 dot = DotProduct( bladeDir, tagDir );
04075                                                                 if ( dot < aoa && dot > -aoa )
04076                                                                 {//blade was roughly perpendicular
04077                                                                         dismember = qtrue;
04078                                                                 }
04079                                                         }
04080                                                 }
04081                                         }
04082                                 }
04083                         }
04084                 }
04085                 else
04086                 { //hmm, no direction supplied.
04087                         dismember = qtrue;
04088                 }
04089         }
04090         return dismember;
04091 }

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

void G_StartMatrixEffect gentity_t ent  ) 
 

Definition at line 16 of file NPC_AI_Jedi.c.

References gentity_t.

00017 { //perhaps write this at some point?
00018 
00019 }

void G_TestLine vec3_t  start,
vec3_t  end,
int  color,
int  time
 

Definition at line 212 of file ai_wpnav.c.

00213 {
00214         gentity_t *te;
00215 
00216         te = G_TempEntity( start, EV_TESTLINE );
00217         VectorCopy(start, te->s.origin);
00218         VectorCopy(end, te->s.origin2);
00219         te->s.time2 = time;
00220         te->s.weapon = color;
00221         te->r.svFlags |= SVF_BROADCAST;
00222 }

void G_UcmdMoveForDir gentity_t self,
usercmd_t cmd,
vec3_t  dir
 

Definition at line 324 of file NPC_move.c.

References AngleVectors(), gentity_s::client, entityShared_t::currentAngles, DotProduct, floor(), usercmd_s::forwardmove, gentity_t, playerState_s::moveDir, NULL, gclient_s::ps, gentity_s::r, usercmd_s::rightmove, usercmd_t, vec3_t, VectorCopy, and VectorNormalize().

Referenced by NPC_MoveToGoal().

00325 {
00326         vec3_t  forward, right;
00327         float   fDot, rDot;
00328 
00329         AngleVectors( self->r.currentAngles, forward, right, NULL );
00330 
00331         dir[2] = 0;
00332         VectorNormalize( dir );
00333         //NPCs cheat and store this directly because converting movement into a ucmd loses precision
00334         VectorCopy( dir, self->client->ps.moveDir );
00335 
00336         fDot = DotProduct( forward, dir ) * 127.0f;
00337         rDot = DotProduct( right, dir ) * 127.0f;
00338         //Must clamp this because DotProduct is not guaranteed to return a number within -1 to 1, and that would be bad when we're shoving this into a signed byte
00339         if ( fDot > 127.0f )
00340         {
00341                 fDot = 127.0f;
00342         }
00343         if ( fDot < -127.0f )
00344         {
00345                 fDot = -127.0f;
00346         }
00347         if ( rDot > 127.0f )
00348         {
00349                 rDot = 127.0f;
00350         }
00351         if ( rDot < -127.0f )
00352         {
00353                 rDot = -127.0f;
00354         }
00355         cmd->forwardmove = floor(fDot);
00356         cmd->rightmove = floor(rDot);
00357 
00358         /*
00359         vec3_t  wishvel;
00360         for ( int i = 0 ; i < 3 ; i++ ) 
00361         {
00362                 wishvel[i] = forward[i]*cmd->forwardmove + right[i]*cmd->rightmove;
00363         }
00364         VectorNormalize( wishvel );
00365         if ( !VectorCompare( wishvel, dir ) )
00366         {
00367                 Com_Printf( "PRECISION LOSS: %s != %s\n", vtos(wishvel), vtos(dir) );
00368         }
00369         */
00370 }

void Jedi_Ambush gentity_t self  ) 
 

Definition at line 5547 of file NPC_AI_Jedi.c.

References BOTH_CEILING_DROP, CLASS_BOBAFETT, gentity_s::client, EV_ANGER1, EV_ANGER3, G_AddVoiceEvent(), gentity_t, Jedi_Decloak(), gclient_s::noclip, gclient_s::NPC_class, NPC_SetAnim(), gclient_s::ps, Q_irand(), qfalse, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, playerState_s::torsoTimer, playerState_s::weaponTime, and WP_ActivateSaber().

Referenced by NPC_BSJedi_Default(), NPC_Use(), and WP_SaberStartMissileBlockCheck().

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_CanPullBackSaber gentity_t self  ) 
 

Definition at line 5730 of file NPC_AI_Jedi.c.

References BLOCKED_PARRY_BROKEN, CLASS_DESANN, CLASS_LUKE, CLASS_SHADOWTROOPER, CLASS_TAVION, gentity_s::client, gentity_t, level, gclient_s::NPC_class, gentity_s::NPC_type, gentity_s::painDebounceTime, gclient_s::ps, Q_stricmp(), qboolean, qfalse, qtrue, playerState_s::saberBlocked, level_locals_t::time, and TIMER_Done().

Referenced by NPC_BSJedi_FollowLeader().

05731 {
05732         if ( self->client->ps.saberBlocked == BLOCKED_PARRY_BROKEN && !TIMER_Done( self, "parryTime" ) )
05733         {
05734                 return qfalse;
05735         }
05736 
05737         if ( self->client->NPC_class == CLASS_SHADOWTROOPER
05738                 || self->client->NPC_class == CLASS_TAVION
05739                 || self->client->NPC_class == CLASS_LUKE
05740                 || self->client->NPC_class == CLASS_DESANN 
05741                 || !Q_stricmp( "Yoda", self->NPC_type ) )
05742         {
05743                 return qtrue;
05744         }
05745 
05746         if ( self->painDebounceTime > level.time )//|| self->client->ps.weaponTime > 0 )
05747         {
05748                 return qfalse;
05749         }
05750 
05751         return qtrue;
05752 }

qboolean Jedi_CheckAmbushPlayer void   ) 
 

Definition at line 5465 of file NPC_AI_Jedi.c.

References gentity_s::client, entityShared_t::currentOrigin, DistanceHorizontalSquared(), gNPC_t::enemyLastSeenTime, g_entities, G_SetEnemy(), gentity_t, InFOV(), level, MAX_CLIENTS, NPC, NPC_ClearLOS4(), NPC_SetLookTarget(), NPC_SomeoneLookingAtMe(), NPC_ValidEnemy(), NPCInfo, playerState_s::powerups, gclient_s::ps, PW_CLOAKED, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, level_locals_t::time, TIMER_Set(), and trap_InPVS().

05466 {
05467         int i = 0;
05468         gentity_t *player;
05469         float target_dist;
05470         float zDiff;
05471 
05472         for ( i = 0; i < MAX_CLIENTS; i++ )
05473         {
05474                 player = &g_entities[i];
05475 
05476                 if ( !player || !player->client )
05477                 {
05478                         continue;
05479                 }
05480 
05481                 if ( !NPC_ValidEnemy( player ) )
05482                 {
05483                         continue;
05484                 }
05485 
05486 //              if ( NPC->client->ps.powerups[PW_CLOAKED] || g_crosshairEntNum != NPC->s.number )
05487                 if (NPC->client->ps.powerups[PW_CLOAKED] || !NPC_SomeoneLookingAtMe(NPC)) //rwwFIXMEFIXME: Need to pay attention to who is under crosshair for each player or something.
05488                 {//if I'm not cloaked and the player's crosshair is on me, I will wake up, otherwise do this stuff down here...
05489                         if ( !trap_InPVS( player->r.currentOrigin, NPC->r.currentOrigin ) )
05490                         {//must be in same room
05491                                 continue;
05492                         }
05493                         else
05494                         {
05495                                 if ( !NPC->client->ps.powerups[PW_CLOAKED] )
05496                                 {
05497                                         NPC_SetLookTarget( NPC, 0, 0 );
05498                                 }
05499                         }
05500                         zDiff = NPC->r.currentOrigin[2]-player->r.currentOrigin[2];
05501                         if ( zDiff <= 0 || zDiff > 512 )
05502                         {//never ambush if they're above me or way way below me
05503                                 continue;
05504                         }
05505 
05506                         //If the target is this close, then wake up regardless
05507                         if ( (target_dist = DistanceHorizontalSquared( player->r.currentOrigin, NPC->r.currentOrigin )) > 4096 )
05508                         {//closer than 64 - always ambush
05509                                 if ( target_dist > 147456 )
05510                                 {//> 384, not close enough to ambush
05511                                         continue;
05512                                 }
05513                                 //Check FOV first
05514                                 if ( NPC->client->ps.powerups[PW_CLOAKED] )
05515                                 {
05516                                         if ( InFOV( player, NPC, 30, 90 ) == qfalse )
05517                                         {
05518                                                 continue;
05519                                         }
05520                                 }
05521                                 else
05522                                 {
05523                                         if ( InFOV( player, NPC, 45, 90 ) == qfalse )
05524                                         {
05525                                                 continue;
05526                                         }
05527                                 }
05528                         }
05529 
05530                         if ( !NPC_ClearLOS4( player ) )
05531                         {
05532                                 continue;
05533                         }
05534                 }
05535 
05536                 //Got him, return true;
05537                 G_SetEnemy( NPC, player );
05538                 NPCInfo->enemyLastSeenTime = level.time;
05539                 TIMER_Set( NPC, "attackDelay", Q_irand( 500, 2500 ) );
05540                 return qtrue;
05541         }
05542 
05543         //Didn't get anyone.
05544         return qfalse;
05545 }

void Jedi_CheckCloak void   ) 
 

Definition at line 835 of file NPC_AI_Jedi.c.

References CLASS_SHADOWTROOPER, gentity_s::client, gentity_s::health, Jedi_Cloak(), Jedi_Decloak(), level, NPC, gclient_s::NPC_class, gentity_s::painDebounceTime, gclient_s::ps, playerState_s::saberHolstered, playerState_s::saberInFlight, and level_locals_t::time.

Referenced by NPC_BSJedi_Default().

00836 {
00837         if ( NPC && NPC->client && NPC->client->NPC_class == CLASS_SHADOWTROOPER )
00838         {
00839                 if ( !NPC->client->ps.saberHolstered ||
00840                         NPC->health <= 0 || 
00841                         NPC->client->ps.saberInFlight ||
00842                 //      (NPC->client->ps.eFlags&EF_FORCE_GRIPPED) ||
00843                 //      (NPC->client->ps.eFlags&EF_FORCE_DRAINED) ||
00844                         NPC->painDebounceTime > level.time )
00845                 {//can't be cloaked if saber is on, or dead or saber in flight or taking pain or being gripped
00846                         Jedi_Decloak( NPC );
00847                 }
00848                 else if ( NPC->health > 0 
00849                         && !NPC->client->ps.saberInFlight 
00850                 //      && !(NPC->client->ps.eFlags&EF_FORCE_GRIPPED) 
00851                 //      && !(NPC->client->ps.eFlags&EF_FORCE_DRAINED) 
00852                         && NPC->painDebounceTime < level.time )
00853                 {//still alive, have saber in hand, not taking pain and not being gripped
00854                         Jedi_Cloak( NPC );
00855                 }
00856         }
00857 }

qboolean Jedi_CheckDanger void   ) 
 

Definition at line 5446 of file NPC_AI_Jedi.c.

References AEL_DANGER, AEL_MINOR, level_locals_t::alertEvents, gentity_s::client, gNPC_t::enemyLastSeenTime, G_SetEnemy(), alertEvent_s::level, level, NPC, NPC_CheckAlertEvents(), NPCInfo, alertEvent_s::owner, gclient_s::playerTeam, Q_irand(), qboolean, qfalse, qtrue, level_locals_t::time, and TIMER_Set().

05447 {
05448         int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_MINOR );
05449         if ( level.alertEvents[alertEvent].level >= AEL_DANGER )
05450         {//run away!
05451                 if ( !level.alertEvents[alertEvent].owner 
05452                         || !level.alertEvents[alertEvent].owner->client 
05453                         || (level.alertEvents[alertEvent].owner!=NPC&&level.alertEvents[alertEvent].owner->client->playerTeam!=NPC->client->playerTeam) )
05454                 {//no owner
05455                         return qfalse;
05456                 }
05457                 G_SetEnemy( NPC, level.alertEvents[alertEvent].owner );
05458                 NPCInfo->enemyLastSeenTime = level.time;
05459                 TIMER_Set( NPC, "attackDelay", Q_irand( 500, 2500 ) );
05460                 return qtrue;
05461         }
05462         return qfalse;
05463 }

evasionType_t Jedi_CheckFlipEvasions gentity_t self,
float  rightdot,
float  zdiff
 

Definition at line 1969 of file NPC_AI_Jedi.c.

References AngleVectors(), animNumber_t, BG_AnimLength(), BG_InRoll(), BG_SaberInAttack(), BG_SaberInSpecialAttack(), BOTH_ARIAL_LEFT, BOTH_ARIAL_RIGHT, BOTH_CARTWHEEL_LEFT, BOTH_CARTWHEEL_RIGHT, BOTH_WALL_FLIP_LEFT, BOTH_WALL_FLIP_RIGHT, BOTH_WALL_RUN_LEFT, BOTH_WALL_RUN_LEFT_FLIP, BOTH_WALL_RUN_RIGHT, BOTH_WALL_RUN_RIGHT_FLIP, CHAN_BODY, CLASS_BOBAFETT, CLASS_DESANN, gentity_s::client, trace_t::contents, CONTENTS_BOTCLIP, CONTENTS_MONSTERCLIP, CONTENTS_SOLID, entityShared_t::currentOrigin, DotProduct, trace_t::entityNum, ENTITYNUM_WORLD, EV_JUMP, EVASION_CARTWHEEL, EVASION_NONE, EVASION_OTHER, evasionType_t, playerState_s::fd, FORCE_LEVEL_2, forcedata_s::forceJumpCharge, forceJumpStrength, forcedata_s::forceJumpZStart, forcedata_s::forcePowersActive, forcedata_s::forceRageRecoveryTime, FP_RAGE, trace_t::fraction, G_AddEvent(), g_entities, G_SoundOnEnt(), gentity_t, playerState_s::legsAnim, playerState_s::legsTimer, level, gentity_s::localAnimIndex, entityShared_t::maxs, entityShared_t::mins, saberInfo_t::model, cplane_s::normal, gentity_s::NPC, gclient_s::NPC_class, NPC_SetAnim(), NULL, entityState_s::number, PITCH, trace_t::plane, PM_InKnockDown(), PM_SaberInStart(), gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, gNPC_t::rank, RANK_CREWMAN, RANK_LT, ROLL, gentity_s::s, gclient_s::saber, saberInfo_t::saberFlags, playerState_s::saberMove, SCF_NO_ACROBATICS, gNPC_t::scriptFlags, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, SETANIM_LEGS, SFL_NO_CARTWHEELS, SFL_NO_WALL_FLIPS, SFL_NO_WALL_RUNS, entityState_s::solid, SOLID_BMODEL, level_locals_t::time, playerState_s::torsoAnim, trap_Trace(), vec3_t, VectorCopy, VectorMA, VectorNormalize(), VectorScale, VectorSet, VectorSubtract, playerState_s::velocity, playerState_s::viewangles, playerState_s::weapon, playerState_s::weaponTime, WP_SABER, and YAW.

Referenced by Jedi_SaberBlockGo().

01970 {
01971         if ( self->NPC && (self->NPC->scriptFlags&SCF_NO_ACROBATICS) )
01972         {
01973                 return EVASION_NONE;
01974         }
01975         if ( self->client 
01976                 && (self->client->ps.fd.forceRageRecoveryTime > level.time      || (self->client->ps.fd.forcePowersActive&(1<<FP_RAGE))) )
01977         {//no fancy dodges when raging
01978                 return EVASION_NONE;
01979         }
01980         //Check for:
01981         //ARIALS/CARTWHEELS
01982         //WALL-RUNS
01983         //WALL-FLIPS
01984         //FIXME: if facing a wall, do forward wall-walk-backflip
01985         if ( self->client->ps.legsAnim == BOTH_WALL_RUN_LEFT || self->client->ps.legsAnim == BOTH_WALL_RUN_RIGHT )
01986         {//already running on a wall
01987                 vec3_t right, fwdAngles;
01988                 int             anim = -1;
01989                 float animLength;
01990 
01991                 VectorSet(fwdAngles, 0, self->client->ps.viewangles[YAW], 0);
01992 
01993                 AngleVectors( fwdAngles, NULL, right, NULL );
01994 
01995                 animLength = BG_AnimLength( self->localAnimIndex, (animNumber_t)self->client->ps.legsAnim );
01996                 if ( self->client->ps.legsAnim == BOTH_WALL_RUN_LEFT && rightdot < 0 )
01997                 {//I'm running on a wall to my left and the attack is on the left
01998                         if ( animLength - self->client->ps.legsTimer > 400
01999                                 && self->client->ps.legsTimer > 400 )
02000                         {//not at the beginning or end of the anim
02001                                 anim = BOTH_WALL_RUN_LEFT_FLIP;
02002                         }
02003                 }
02004                 else if ( self->client->ps.legsAnim == BOTH_WALL_RUN_RIGHT && rightdot > 0 )
02005                 {//I'm running on a wall to my right and the attack is on the right
02006                         if ( animLength - self->client->ps.legsTimer > 400
02007                                 && self->client->ps.legsTimer > 400 )
02008                         {//not at the beginning or end of the anim
02009                                 anim = BOTH_WALL_RUN_RIGHT_FLIP;
02010                         }
02011                 }
02012                 if ( anim != -1 )
02013                 {//flip off the wall!
02014                         int parts;
02015                         //FIXME: check the direction we will flip towards for do-not-enter/walls/drops?
02016                         //NOTE: we presume there is still a wall there!
02017                         if ( anim == BOTH_WALL_RUN_LEFT_FLIP )
02018                         {
02019                                 self->client->ps.velocity[0] *= 0.5f;
02020                                 self->client->ps.velocity[1] *= 0.5f;
02021                                 VectorMA( self->client->ps.velocity, 150, right, self->client->ps.velocity );
02022                         }
02023                         else if ( anim == BOTH_WALL_RUN_RIGHT_FLIP )
02024                         {
02025                                 self->client->ps.velocity[0] *= 0.5f;
02026                                 self->client->ps.velocity[1] *= 0.5f;
02027                                 VectorMA( self->client->ps.velocity, -150, right, self->client->ps.velocity );
02028                         }
02029                         parts = SETANIM_LEGS;
02030                         if ( !self->client->ps.weaponTime )
02031                         {
02032                                 parts = SETANIM_BOTH;
02033                         }
02034                         NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
02035                         //self->client->ps.pm_flags |= (PMF_JUMPING|PMF_SLOW_MO_FALL);
02036                         //rwwFIXMEFIXME: Add these pm flags?
02037                         G_AddEvent( self, EV_JUMP, 0 );
02038                         return EVASION_OTHER;
02039                 }
02040         }
02041         else if ( self->client->NPC_class != CLASS_DESANN //desann doesn't do these kind of frilly acrobatics
02042                 && (self->NPC->rank == RANK_CREWMAN || self->NPC->rank >= RANK_LT) 
02043                 && Q_irand( 0, 1 ) 
02044                 && !BG_InRoll( &self->client->ps, self->client->ps.legsAnim )
02045                 && !PM_InKnockDown( &self->client->ps )
02046                 && !BG_SaberInSpecialAttack( self->client->ps.torsoAnim ) )
02047         {
02048                 vec3_t fwd, right, traceto, mins, maxs, fwdAngles;
02049                 trace_t trace;
02050                 int parts, anim;
02051                 float   speed, checkDist;
02052                 qboolean allowCartWheels = qtrue;
02053                 qboolean allowWallFlips = qtrue;
02054 
02055                 if ( self->client->ps.weapon == WP_SABER )
02056                 {
02057                         if ( self->client->saber[0].model
02058                                 && self->client->saber[0].model[0]
02059                                 && (self->client->saber[0].saberFlags&SFL_NO_CARTWHEELS) )
02060                         {
02061                                 allowCartWheels = qfalse;
02062                         }
02063                         else if ( self->client->saber[1].model
02064                                 && self->client->saber[1].model[0]
02065                                 && (self->client->saber[1].saberFlags&SFL_NO_CARTWHEELS) )
02066                         {
02067                                 allowCartWheels = qfalse;
02068                         }
02069                         if ( self->client->saber[0].model
02070                                 && self->client->saber[0].model[0]
02071                                 && (self->client->saber[0].saberFlags&SFL_NO_WALL_FLIPS) )
02072                         {
02073                                 allowWallFlips = qfalse;
02074                         }
02075                         else if ( self->client->saber[1].model
02076                                 && self->client->saber[1].model[0]
02077                                 && (self->client->saber[1].saberFlags&SFL_NO_WALL_FLIPS) )
02078                         {
02079                                 allowWallFlips = qfalse;
02080                         }
02081                 }
02082 
02083                 VectorSet(mins, self->r.mins[0],self->r.mins[1],0);
02084                 VectorSet(maxs, self->r.maxs[0],self->r.maxs[1],24);
02085                 VectorSet(fwdAngles, 0, self->client->ps.viewangles[YAW], 0);
02086 
02087                 AngleVectors( fwdAngles, fwd, right, NULL );
02088 
02089                 parts = SETANIM_BOTH;
02090 
02091                 if ( BG_SaberInAttack( self->client->ps.saberMove )
02092                         || PM_SaberInStart( self->client->ps.saberMove ) )
02093                 {
02094                         parts = SETANIM_LEGS;
02095                 }
02096                 if ( rightdot >= 0 )
02097                 {
02098                         if ( Q_irand( 0, 1 ) )
02099                         {
02100                                 anim = BOTH_ARIAL_LEFT;
02101                         }
02102                         else
02103                         {
02104                                 anim = BOTH_CARTWHEEL_LEFT;
02105                         }
02106                         checkDist = -128;
02107                         speed = -200;
02108                 }
02109                 else
02110                 {
02111                         if ( Q_irand( 0, 1 ) )
02112                         {
02113                                 anim = BOTH_ARIAL_RIGHT;
02114                         }
02115                         else
02116                         {
02117                                 anim = BOTH_CARTWHEEL_RIGHT;
02118                         }
02119                         checkDist = 128;
02120                         speed = 200;
02121                 }
02122                 //trace in the dir that we want to go
02123                 VectorMA( self->r.currentOrigin, checkDist, right, traceto );
02124                 trap_Trace( &trace, self->r.currentOrigin, mins, maxs, traceto, self->s.number, CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP );
02125                 if ( trace.fraction >= 1.0f && allowCartWheels )
02126                 {//it's clear, let's do it
02127                         //FIXME: check for drops?
02128                         vec3_t fwdAngles, jumpRt;
02129 
02130                         NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
02131                         self->client->ps.weaponTime = self->client->ps.legsTimer;//don't attack again until this anim is done
02132                         VectorCopy( self->client->ps.viewangles, fwdAngles );
02133                         fwdAngles[PITCH] = fwdAngles[ROLL] = 0;
02134                         //do the flip
02135                         AngleVectors( fwdAngles, NULL, jumpRt, NULL );
02136                         VectorScale( jumpRt, speed, self->client->ps.velocity );
02137                         self->client->ps.fd.forceJumpCharge = 0;//so we don't play the force flip anim
02138                         self->client->ps.velocity[2] = 200;
02139                         self->client->ps.fd.forceJumpZStart = self->r.currentOrigin[2];//so we don't take damage if we land at same height
02140                         //self->client->ps.pm_flags |= PMF_JUMPING;
02141                         if ( self->client->NPC_class == CLASS_BOBAFETT )
02142                         {
02143                                 G_AddEvent( self, EV_JUMP, 0 );
02144                         }
02145                         else
02146                         {
02147                                 G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/jump.wav" );
02148                         }
02149                         //ucmd.upmove = 0;
02150                         return EVASION_CARTWHEEL;
02151                 }
02152                 else if ( !(trace.contents&CONTENTS_BOTCLIP) )
02153                 {//hit a wall, not a do-not-enter brush
02154                         //FIXME: before we check any of these jump-type evasions, we should check for headroom, right?
02155                         //Okay, see if we can flip *off* the wall and go the other way
02156                         vec3_t  idealNormal;
02157                         gentity_t *traceEnt;
02158 
02159                         VectorSubtract( self->r.currentOrigin, traceto, idealNormal );
02160                         VectorNormalize( idealNormal );
02161                         traceEnt = &g_entities[trace.entityNum];
02162                         if ( (trace.entityNum<ENTITYNUM_WORLD&&traceEnt&&traceEnt->s.solid!=SOLID_BMODEL) || DotProduct( trace.plane.normal, idealNormal ) > 0.7f )
02163                         {//it's a ent of some sort or it's a wall roughly facing us
02164                                 float bestCheckDist = 0;
02165                                 //hmm, see if we're moving forward
02166                                 if ( DotProduct( self->client->ps.velocity, fwd ) < 200 )
02167                                 {//not running forward very fast
02168                                         //check to see if it's okay to move the other way
02169                                         if ( (trace.fraction*checkDist) <= 32 )
02170                                         {//wall on that side is close enough to wall-flip off of or wall-run on
02171                                                 bestCheckDist = checkDist;
02172                                                 checkDist *= -1.0f;
02173                                                 VectorMA( self->r.currentOrigin, checkDist, right, traceto );
02174                                                 //trace in the dir that we want to go
02175                                                 trap_Trace( &trace, self->r.currentOrigin, mins, maxs, traceto, self->s.number, CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP );
02176                                                 if ( trace.fraction >= 1.0f )
02177                                                 {//it's clear, let's do it
02178                                                         if ( allowWallFlips )
02179                                                         {//okay to do wall-flips with this saber
02180                                                                 int parts;
02181 
02182                                                                 //FIXME: check for drops?
02183                                                                 //turn the cartwheel into a wallflip in the other dir
02184                                                                 if ( rightdot > 0 )
02185                                                                 {
02186                                                                         anim = BOTH_WALL_FLIP_LEFT;
02187                                                                         self->client->ps.velocity[0] = self->client->ps.velocity[1] = 0;
02188                                                                         VectorMA( self->client->ps.velocity, 150, right, self->client->ps.velocity );
02189                                                                 }
02190                                                                 else
02191                                                                 {
02192                                                                         anim = BOTH_WALL_FLIP_RIGHT;
02193                                                                         self->client->ps.velocity[0] = self->client->ps.velocity[1] = 0;
02194                                                                         VectorMA( self->client->ps.velocity, -150, right, self->client->ps.velocity );
02195                                                                 }
02196                                                                 self->client->ps.velocity[2] = forceJumpStrength[FORCE_LEVEL_2]/2.25f;
02197                                                                 //animate me
02198                                                                 parts = SETANIM_LEGS;
02199                                                                 if ( !self->client->ps.weaponTime )
02200                                                                 {
02201                                                                         parts = SETANIM_BOTH;
02202                                                                 }
02203                                                                 NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
02204                                                                 self->client->ps.fd.forceJumpZStart = self->r.currentOrigin[2];//so we don't take damage if we land at same height
02205                                                                 //self->client->ps.pm_flags |= (PMF_JUMPING|PMF_SLOW_MO_FALL);
02206                                                                 if ( self->client->NPC_class == CLASS_BOBAFETT )
02207                                                                 {
02208                                                                         G_AddEvent( self, EV_JUMP, 0 );
02209                                                                 }
02210                                                                 else
02211                                                                 {
02212                                                                         G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/jump.wav" );
02213                                                                 }
02214                                                                 return EVASION_OTHER;
02215                                                                 }
02216                                                 }
02217                                                 else 
02218                                                 {//boxed in on both sides
02219                                                         if ( DotProduct( self->client->ps.velocity, fwd ) < 0 )
02220                                                         {//moving backwards
02221                                                                 return EVASION_NONE;
02222                                                         }
02223                                                         if ( (trace.fraction*checkDist) <= 32 && (trace.fraction*checkDist) < bestCheckDist )
02224                                                         {
02225                                                                 bestCheckDist = checkDist;
02226                                                         }
02227                                                 }
02228                                         }
02229                                         else
02230                                         {//too far from that wall to flip or run off it, check other side
02231                                                 checkDist *= -1.0f;
02232                                                 VectorMA( self->r.currentOrigin, checkDist, right, traceto );
02233                                                 //trace in the dir that we want to go
02234                                                 trap_Trace( &trace, self->r.currentOrigin, mins, maxs, traceto, self->s.number, CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP );
02235                                                 if ( (trace.fraction*checkDist) <= 32 )
02236                                                 {//wall on this side is close enough
02237                                                         bestCheckDist = checkDist;
02238                                                 }
02239                                                 else
02240                                                 {//neither side has a wall within 32
02241                                                         return EVASION_NONE;
02242                                                 }
02243                                         }
02244                                 }
02245                                 //Try wall run?
02246                                 if ( bestCheckDist )
02247                                 {//one of the walls was close enough to wall-run on
02248                                         qboolean allowWallRuns = qtrue;
02249                                         if ( self->client->ps.weapon == WP_SABER )
02250                                         {
02251                                                 if ( self->client->saber[0].model
02252                                                         && self->client->saber[0].model[0] 
02253                                                         && (self->client->saber[0].saberFlags&SFL_NO_WALL_RUNS) )
02254                                                 {
02255                                                         allowWallRuns = qfalse;
02256                                                 }
02257                                                 else if ( self->client->saber[1].model
02258                                                         && self->client->saber[1].model[0]
02259                                                         && (self->client->saber[1].saberFlags&SFL_NO_WALL_RUNS) )
02260                                                 {
02261                                                         allowWallRuns = qfalse;
02262                                                 }
02263                                         }
02264                                         if ( allowWallRuns )
02265                                         {//okay to do wallruns with this saber
02266                                                 int parts;
02267 
02268                                                 //FIXME: check for long enough wall and a drop at the end?
02269                                                 if ( bestCheckDist > 0 )
02270                                                 {//it was to the right
02271                                                         anim = BOTH_WALL_RUN_RIGHT;
02272                                                 }
02273                                                 else
02274                                                 {//it was to the left
02275                                                         anim = BOTH_WALL_RUN_LEFT;
02276                                                 }
02277                                                 self->client->ps.velocity[2] = forceJumpStrength[FORCE_LEVEL_2]/2.25f;
02278                                                 //animate me
02279                                                 parts = SETANIM_LEGS;
02280                                                 if ( !self->client->ps.weaponTime )
02281                                                 {
02282                                                         parts = SETANIM_BOTH;
02283                                                 }
02284                                                 NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
02285                                                 self->client->ps.fd.forceJumpZStart = self->r.currentOrigin[2];//so we don't take damage if we land at same height
02286                                                 //self->client->ps.pm_flags |= (PMF_JUMPING|PMF_SLOW_MO_FALL);
02287                                                 if ( self->client->NPC_class == CLASS_BOBAFETT )
02288                                                 {
02289                                                         G_AddEvent( self, EV_JUMP, 0 );
02290                                                 }
02291                                                 else
02292                                                 {
02293                                                         G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/jump.wav" );
02294                                                 }
02295                                                 return EVASION_OTHER;
02296                                         }
02297                                 }
02298                                 //else check for wall in front, do backflip off wall
02299                         }
02300                 }
02301         }
02302         return EVASION_NONE;
02303 }

void Jedi_ClearTimers gentity_t ent  ) 
 

Definition at line 110 of file NPC_AI_Jedi.c.

References gentity_t, and TIMER_Set().

Referenced by NPC_SetMiscDefaultData().

00111 {
00112         TIMER_Set( ent, "roamTime", 0 );
00113         TIMER_Set( ent, "chatter", 0 );
00114         TIMER_Set( ent, "strafeLeft", 0 );
00115         TIMER_Set( ent, "strafeRight", 0 );
00116         TIMER_Set( ent, "noStrafe", 0 );
00117         TIMER_Set( ent, "walking", 0 );
00118         TIMER_Set( ent, "taunting", 0 );
00119         TIMER_Set( ent, "parryTime", 0 );
00120         TIMER_Set( ent, "parryReCalcTime", 0 );
00121         TIMER_Set( ent, "forceJumpChasing", 0 );
00122         TIMER_Set( ent, "jumpChaseDebounce", 0 );
00123         TIMER_Set( ent, "moveforward", 0 );
00124         TIMER_Set( ent, "moveback", 0 );
00125         TIMER_Set( ent, "movenone", 0 );
00126         TIMER_Set( ent, "moveright", 0 );
00127         TIMER_Set( ent, "moveleft", 0 );
00128         TIMER_Set( ent, "movecenter", 0 );
00129         TIMER_Set( ent, "saberLevelDebounce", 0 );
00130         TIMER_Set( ent, "noRetreat", 0 );
00131         TIMER_Set( ent, "holdLightning", 0 );
00132         TIMER_Set( ent, "gripping", 0 );
00133         TIMER_Set( ent, "draining", 0 );
00134         TIMER_Set( ent, "noturn", 0 );
00135 }

void Jedi_Cloak gentity_t self  ) 
 

Definition at line 799 of file NPC_AI_Jedi.c.

References CHAN_ITEM, gentity_s::client, FL_NOTARGET, gentity_s::flags, G_Sound(), G_SoundIndex(), gentity_t, playerState_s::powerups, gclient_s::ps, PW_CLOAKED, and Q3_INFINITE.

Referenced by ClientThink_real(), ItemUse_UseCloak(), Jedi_CheckCloak(), and NPC_SetMiscDefaultData().

00800 {
00801         if ( self )
00802         {
00803                 self->flags |= FL_NOTARGET;
00804                 if ( self->client )
00805                 {
00806                         if ( !self->client->ps.powerups[PW_CLOAKED] )
00807                         {//cloak
00808                                 self->client->ps.powerups[PW_CLOAKED] = Q3_INFINITE;
00809 
00810                                 //FIXME: debounce attacks?
00811                                 //FIXME: temp sound
00812                                 G_Sound( self, CHAN_ITEM, G_SoundIndex("sound/chars/shadowtrooper/cloak.wav") );
00813                         }
00814                 }
00815         }
00816 }

void Jedi_Decloak gentity_t self  ) 
 

Definition at line 818 of file NPC_AI_Jedi.c.

References CHAN_ITEM, gentity_s::client, FL_NOTARGET, gentity_s::flags, G_Sound(), G_SoundIndex(), gentity_t, playerState_s::powerups, gclient_s::ps, and PW_CLOAKED.

Referenced by ClientThink_real(), DEMP2_AltRadiusDamage(), ForceLightningDamage(), G_MissileImpact(), G_RunFrame(), ItemUse_UseCloak(), Jedi_Ambush(), and Jedi_CheckCloak().

00819 {
00820         if ( self )
00821         {
00822                 self->flags &= ~FL_NOTARGET;
00823                 if ( self->client )
00824                 {
00825                         if ( self->client->ps.powerups[PW_CLOAKED] )
00826                         {//Uncloak
00827                                 self->client->ps.powerups[PW_CLOAKED] = 0;
00828 
00829                                 G_Sound( self, CHAN_ITEM, G_SoundIndex("sound/chars/shadowtrooper/decloak.wav") );
00830                         }
00831                 }
00832         }
00833 }

gentity_t* Jedi_FindEnemyInCone gentity_t self,
gentity_t fallback,
float  minDot
 

Definition at line 3686 of file NPC_AI_Jedi.c.

References AngleVectors(), gentity_s::client, entityShared_t::currentOrigin, DotProduct, gclient_s::enemyTeam, trace_t::entityNum, trace_t::fraction, g_entities, gentity_t, gentity_s::health, gentity_s::inuse, MASK_SHOT, MAX_GENTITIES, NULL, entityState_s::number, gclient_s::playerTeam, gclient_s::ps, Q3_INFINITE, gentity_s::r, gentity_s::s, trap_EntitiesInBox(), trap_InPVS(), trap_Trace(), vec3_origin, vec3_t, VectorNormalize(), VectorSubtract, and playerState_s::viewangles.

03687 {
03688         vec3_t forward, mins, maxs, dir;
03689         float   dist, bestDist = Q3_INFINITE;
03690         gentity_t       *enemy = fallback;
03691         gentity_t       *check = NULL;
03692         int                     entityList[MAX_GENTITIES];
03693         int                     e, numListedEntities;
03694         trace_t         tr;
03695 
03696         if ( !self->client )
03697         {
03698                 return enemy;
03699         }
03700 
03701         AngleVectors( self->client->ps.viewangles, forward, NULL, NULL );
03702 
03703         for ( e = 0 ; e < 3 ; e++ ) 
03704         {
03705                 mins[e] = self->r.currentOrigin[e] - 1024;
03706                 maxs[e] = self->r.currentOrigin[e] + 1024;
03707         }
03708         numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
03709 
03710         for ( e = 0 ; e < numListedEntities ; e++ ) 
03711         {
03712                 check = &g_entities[entityList[e]];
03713                 if ( check == self )
03714                 {//me
03715                         continue;
03716                 }
03717                 if ( !(check->inuse) )
03718                 {//freed
03719                         continue;
03720                 }
03721                 if ( !check->client )
03722                 {//not a client - FIXME: what about turrets?
03723                         continue;
03724                 }
03725                 if ( check->client->playerTeam != self->client->enemyTeam )
03726                 {//not an enemy - FIXME: what about turrets?
03727                         continue;
03728                 }
03729                 if ( check->health <= 0 )
03730                 {//dead
03731                         continue;
03732                 }
03733 
03734                 if ( !trap_InPVS( check->r.currentOrigin, self->r.currentOrigin ) )
03735                 {//can't potentially see them
03736                         continue;
03737                 }
03738 
03739                 VectorSubtract( check->r.currentOrigin, self->r.currentOrigin, dir );
03740                 dist = VectorNormalize( dir );
03741 
03742                 if ( DotProduct( dir, forward ) < minDot )
03743                 {//not in front
03744                         continue;
03745                 }
03746 
03747                 //really should have a clear LOS to this thing...
03748                 trap_Trace( &tr, self->r.currentOrigin, vec3_origin, vec3_origin, check->r.currentOrigin, self->s.number, MASK_SHOT );
03749                 if ( tr.fraction < 1.0f && tr.entityNum != check->s.number )
03750                 {//must have clear shot
03751                         continue;
03752                 }
03753 
03754                 if ( dist < bestDist )
03755                 {//closer than our last best one
03756                         dist = bestDist;
03757                         enemy = check;
03758                 }
03759         }
03760         return enemy;
03761 }

void Jedi_PlayBlockedPushSound gentity_t self  ) 
 

Definition at line 137 of file NPC_AI_Jedi.c.

References gNPC_t::blockedSpeechDebounceTime, EV_PUSHFAIL, G_AddVoiceEvent(), gentity_t, gentity_s::health, level, gentity_s::NPC, entityState_s::number, gentity_s::s, and level_locals_t::time.

Referenced by WP_ResistForcePush().

00138 {
00139         if ( !self->s.number )
00140         {
00141                 G_AddVoiceEvent( self, EV_PUSHFAIL, 3000 );
00142         }
00143         else if ( self->health > 0 && self->NPC && self->NPC->blockedSpeechDebounceTime < level.time )
00144         {
00145                 G_AddVoiceEvent( self, EV_PUSHFAIL, 3000 );
00146                 self->NPC->blockedSpeechDebounceTime = level.time + 3000;
00147         }
00148 }

void Jedi_PlayDeflectSound gentity_t self  ) 
 

Definition at line 150 of file NPC_AI_Jedi.c.

References gNPC_t::blockedSpeechDebounceTime, EV_DEFLECT1, EV_DEFLECT3, G_AddVoiceEvent(), gentity_t, gentity_s::health, level, gentity_s::NPC, entityState_s::number, Q_irand(), gentity_s::s, and level_locals_t::time.

00151 {
00152         if ( !self->s.number )
00153         {
00154                 G_AddVoiceEvent( self, Q_irand( EV_DEFLECT1, EV_DEFLECT3 ), 3000 );
00155         }
00156         else if ( self->health > 0 && self->NPC && self->NPC->blockedSpeechDebounceTime < level.time )
00157         {
00158                 G_AddVoiceEvent( self, Q_irand( EV_DEFLECT1, EV_DEFLECT3 ), 3000 );
00159                 self->NPC->blockedSpeechDebounceTime = level.time + 3000;
00160         }
00161 }

qboolean Jedi_QuickReactions gentity_t self  ) 
 

Definition at line 2443 of file NPC_AI_Jedi.c.

References CLASS_JEDI, CLASS_TAVION, gentity_s::client, playerState_s::fd, FORCE_LEVEL_1, FORCE_LEVEL_2, forcedata_s::forcePowerLevel, FP_SABER_DEFENSE, g_spskill, gentity_t, vmCvar_t::integer, gclient_s::NPC_class, NPCInfo, gclient_s::ps, qboolean, qfalse, qtrue, gNPC_t::rank, and RANK_COMMANDER.

Referenced by Jedi_SaberBlockGo().

02444 {
02445         if ( ( self->client->NPC_class == CLASS_JEDI && NPCInfo->rank == RANK_COMMANDER ) ||
02446                 self->client->NPC_class == CLASS_TAVION ||
02447                 (self->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE]>FORCE_LEVEL_1&&g_spskill.integer>1) ||
02448                 (self->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE]>FORCE_LEVEL_2&&g_spskill.integer>0) )
02449         {
02450                 return qtrue;
02451         }
02452         return qfalse;
02453 }

void Jedi_RageStop gentity_t self  ) 
 

Definition at line 966 of file NPC_AI_Jedi.c.

References gentity_t, gentity_s::NPC, Q_irand(), and TIMER_Set().

00967 {
00968         if ( self->NPC )
00969         {//calm down and back off
00970                 TIMER_Set( self, "roamTime", 0 );
00971                 Jedi_Aggression( self, Q_irand( -5, 0 ) );
00972         }
00973 }

int Jedi_ReCalcParryTime gentity_t self,
evasionType_t  evasionType
 

Definition at line 2305 of file NPC_AI_Jedi.c.

References bg_parryDebounce, ceil(), CLASS_TAVION, gentity_s::client, EVASION_CARTWHEEL, EVASION_DODGE, EVASION_DUCK, EVASION_DUCK_PARRY, EVASION_FJUMP, EVASION_JUMP, EVASION_JUMP_PARRY, EVASION_OTHER, EVASION_PARRY, playerState_s::fd, forcedata_s::forcePowerLevel, FP_SABER_DEFENSE, g_saberRealisticCombat, g_spskill, gentity_t, vmCvar_t::integer, gentity_s::NPC, gclient_s::NPC_class, entityState_s::number, gclient_s::ps, Q_irand(), gNPC_t::rank, RANK_CIVILIAN, RANK_CREWMAN, RANK_LT_JG, gentity_s::s, playerState_s::saberInFlight, and playerState_s::torsoTimer.

Referenced by Jedi_SaberBlockGo().

02306 {
02307         if ( !self->client )
02308         {
02309                 return 0;
02310         }
02311         if ( !self->s.number )
02312         {//player 
02313                 return bg_parryDebounce[self->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE]];
02314         }
02315         else if ( self->NPC )
02316         {
02317                 if ( !g_saberRealisticCombat.integer 
02318                         && ( g_spskill.integer == 2 || (g_spskill.integer == 1 && self->client->NPC_class == CLASS_TAVION) ) )
02319                 {
02320                         if ( self->client->NPC_class == CLASS_TAVION )
02321                         {
02322                                 return 0;
02323                         }
02324                         else
02325                         {
02326                                 return Q_irand( 0, 150 );
02327                         }
02328                 }
02329                 else
02330                 {
02331                         int     baseTime;
02332                         if ( evasionType == EVASION_DODGE )
02333                         {
02334                                 baseTime = self->client->ps.torsoTimer;
02335                         }
02336                         else if ( evasionType == EVASION_CARTWHEEL )
02337                         {
02338                                 baseTime = self->client->ps.torsoTimer;
02339                         }
02340                         else if ( self->client->ps.saberInFlight )
02341                         {
02342                                 baseTime = Q_irand( 1, 3 ) * 50;
02343                         }
02344                         else
02345                         {
02346                                 if ( g_saberRealisticCombat.integer )
02347                                 {
02348                                         baseTime = 500;
02349 
02350                                         switch ( g_spskill.integer )
02351                                         {
02352                                         case 0:
02353                                                 baseTime = 500;
02354                                                 break;
02355                                         case 1:
02356                                                 baseTime = 300;
02357                                                 break;
02358                                         case 2:
02359                                         default:
02360                                                 baseTime = 100;
02361                                                 break;
02362                                         }
02363                                 }
02364                                 else
02365                                 {
02366                                         baseTime = 150;//500;
02367 
02368                                         switch ( g_spskill.integer )
02369                                         {
02370                                         case 0:
02371                                                 baseTime = 200;//500;
02372                                                 break;
02373                                         case 1:
02374                                                 baseTime = 100;//300;
02375                                                 break;
02376                                         case 2:
02377                                         default:
02378                                                 baseTime = 50;//100;
02379                                                 break;
02380                                         }
02381                                 }
02382 
02383                                 if ( self->client->NPC_class == CLASS_TAVION )
02384                                 {//Tavion is faster
02385                                         baseTime = ceil(baseTime/2.0f);
02386                                 }
02387                                 else if ( self->NPC->rank >= RANK_LT_JG )
02388                                 {//fencers, bosses, shadowtroopers, luke, desann, et al use the norm
02389                                         if ( Q_irand( 0, 2 ) )
02390                                         {//medium speed parry
02391                                                 baseTime = baseTime;
02392                                         }
02393                                         else
02394                                         {//with the occasional fast parry
02395                                                 baseTime = ceil(baseTime/2.0f);
02396                                         }
02397                                 }
02398                                 else if ( self->NPC->rank == RANK_CIVILIAN )
02399                                 {//grunts are slowest
02400                                         baseTime = baseTime*Q_irand(1,3);
02401                                 }
02402                                 else if ( self->NPC->rank == RANK_CREWMAN )
02403                                 {//acrobats aren't so bad
02404                                         if ( evasionType == EVASION_PARRY
02405                                                 || evasionType == EVASION_DUCK_PARRY
02406                                                 || evasionType == EVASION_JUMP_PARRY )
02407                                         {//slower with parries
02408                                                 baseTime = baseTime*Q_irand(1,2);
02409                                         }
02410                                         else
02411                                         {//faster with acrobatics
02412                                                 //baseTime = baseTime;
02413                                         }
02414                                 }
02415                                 else
02416                                 {//force users are kinda slow
02417                                         baseTime = baseTime*Q_irand(1,2);
02418                                 }
02419                                 if ( evasionType == EVASION_DUCK || evasionType == EVASION_DUCK_PARRY )
02420                                 {
02421                                         baseTime += 100;
02422                                 }
02423                                 else if ( evasionType == EVASION_JUMP || evasionType == EVASION_JUMP_PARRY )
02424                                 {
02425                                         baseTime += 50;
02426                                 }
02427                                 else if ( evasionType == EVASION_OTHER )
02428                                 {
02429                                         baseTime += 100;
02430                                 }
02431                                 else if ( evasionType == EVASION_FJUMP )
02432                                 {
02433                                         baseTime += 100;
02434                                 }
02435                         }
02436                         
02437                         return baseTime;
02438                 }
02439         }
02440         return 0;
02441 }

evasionType_t Jedi_SaberBlockGo gentity_t self,
usercmd_t cmd,
vec3_t  pHitloc,
vec3_t  phitDir,
gentity_t incoming,
float  dist
 

Definition at line 2485 of file NPC_AI_Jedi.c.

References entityShared_t::absmin, AngleVectors(), BG_InRoll(), BG_SaberInAttack(), BG_SaberInSpecialAttack(), BG_SabersOff(), BG_SpinningSaberAnim(), BLOCKED_LOWER_LEFT, BLOCKED_LOWER_RIGHT, BLOCKED_TOP, BLOCKED_UPPER_LEFT, BLOCKED_UPPER_RIGHT, BOTH_BUTTERFLY_LEFT, BOTH_BUTTERFLY_RIGHT, BOTH_DODGE_BL, BOTH_DODGE_BR, BOTH_DODGE_FL, BOTH_DODGE_FR, BOTH_DODGE_L, BOTH_DODGE_R, CHAN_BODY, CLASS_BOBAFETT, CLASS_TAVION, gentity_s::client, Com_Printf(), entityShared_t::currentOrigin, d_JediAI, d_slowmodeath, DotProduct, gentity_s::enemy, ENTITYNUM_NONE, EV_JUMP, EVASION_CARTWHEEL, EVASION_DODGE, EVASION_DUCK, EVASION_DUCK_PARRY, EVASION_FJUMP, EVASION_JUMP, EVASION_JUMP_PARRY, EVASION_NONE, EVASION_PARRY, evasionType_t, renderInfo_s::eyePoint, fabs(), playerState_s::fd, forcedata_s::forceJumpCharge, forcedata_s::forceJumpZStart, forcedata_s::forcePowerDebounce, forcedata_s::forcePowersActive, forcedata_s::forceRageRecoveryTime, usercmd_s::forwardmove, FP_DRAIN, FP_GRIP, FP_RAGE, FP_SABER_DEFENSE, G_AddEvent(), G_Sound(), G_SoundIndex(), G_StartMatrixEffect(), gentity_t, playerState_s::groundEntityNum, vmCvar_t::integer, Jedi_CheckFlipEvasions(), Jedi_QuickReactions(), Jedi_ReCalcParryTime(), Jedi_SaberBusy(), JUMP_VELOCITY, playerState_s::legsAnim, level, gentity_s::NPC, NPC, gclient_s::NPC_class, NPC_SetAnim(), NULL, entityState_s::number, playerState_s::pm_flags, PM_InKnockDown(), PM_SaberInStart(), playerState_s::pm_time, PMF_DUCKED, PMF_TIME_KNOCKBACK, entityState_s::pos, gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, gNPC_t::rank, RANK_CREWMAN, RANK_LT_JG, gclient_s::renderInfo, usercmd_s::rightmove, gentity_s::s, playerState_s::saberBlocked, playerState_s::saberInFlight, playerState_s::saberMove, SCF_NO_ACROBATICS, gNPC_t::scriptFlags, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, level_locals_t::time, TIMER_Done(), TIMER_Set(), TIMER_Start(), playerState_s::torsoAnim, playerState_s::torsoTimer, trajectory_t::trDelta, usercmd_s::upmove, usercmd_t, vec3_t, VectorCopy, VectorNormalize2(), VectorSubtract, playerState_s::velocity, playerState_s::viewangles, entityState_s::weapon, playerState_s::weaponTime, WP_ForcePowerStop(), WP_MissileBlockForBlock(), and WP_SABER.

Referenced by WP_SaberStartMissileBlockCheck().

02486 {
02487         vec3_t hitloc, hitdir, diff, fwdangles={0,0,0}, right;
02488         float rightdot;
02489         float zdiff;
02490         int       duckChance = 0;
02491         int       dodgeAnim = -1;
02492         qboolean        saberBusy = qfalse, evaded = qfalse, doDodge = qfalse;
02493         evasionType_t   evasionType = EVASION_NONE;
02494 
02495         //FIXME: if we don't have our saber in hand, pick the force throw option or a jump or strafe!
02496         //FIXME: reborn don't block enough anymore
02497         if ( !incoming )
02498         {
02499                 VectorCopy( pHitloc, hitloc );
02500                 VectorCopy( phitDir, hitdir );
02501                 //FIXME: maybe base this on rank some?  And/or g_spskill?
02502                 if ( self->client->ps.saberInFlight )
02503                 {//DOH!  do non-saber evasion!
02504                         saberBusy = qtrue;
02505                 }
02506                 else if ( Jedi_QuickReactions( self ) )
02507                 {//jedi trainer and tavion are must faster at parrying and can do it whenever they like
02508                         //Also, on medium, all level 3 people can parry any time and on hard, all level 2 or 3 people can parry any time
02509                 }
02510                 else
02511                 {
02512                         saberBusy = Jedi_SaberBusy( self );
02513                 }
02514         }
02515         else
02516         {       
02517                 if ( incoming->s.weapon == WP_SABER )
02518                 {//flying lightsaber, face it!
02519                         //FIXME: for this to actually work, we'd need to call update angles too?
02520                         //Jedi_FaceEntity( self, incoming, qtrue );
02521                 }
02522                 VectorCopy( incoming->r.currentOrigin, hitloc );
02523                 VectorNormalize2( incoming->s.pos.trDelta, hitdir );
02524         }
02525         if ( self->client && self->client->NPC_class == CLASS_BOBAFETT )
02526         {
02527                 saberBusy = qtrue;
02528         }
02529 
02530         VectorSubtract( hitloc, self->client->renderInfo.eyePoint, diff );
02531         diff[2] = 0;
02532         //VectorNormalize( diff );
02533         fwdangles[1] = self->client->ps.viewangles[1];
02534         // Ultimately we might care if the shot was ahead or behind, but for now, just quadrant is fine.
02535         AngleVectors( fwdangles, NULL, right, NULL );
02536 
02537         rightdot = DotProduct(right, diff);// + flrand(-0.10f,0.10f);
02538         //totalHeight = self->client->renderInfo.eyePoint[2] - self->r.absmin[2];
02539         zdiff = hitloc[2] - self->client->renderInfo.eyePoint[2];// + Q_irand(-6,6);
02540         
02541         //see if we can dodge if need-be
02542         if ( (dist>16&&(Q_irand( 0, 2 )||saberBusy)) 
02543                 || self->client->ps.saberInFlight 
02544                 || BG_SabersOff( &self->client->ps )
02545                 || self->client->NPC_class == CLASS_BOBAFETT )
02546         {//either it will miss by a bit (and 25% chance) OR our saber is not in-hand OR saber is off
02547                 if ( self->NPC && (self->NPC->rank == RANK_CREWMAN || self->NPC->rank >= RANK_LT_JG) )
02548                 {//acrobat or fencer or above
02549                         if ( self->client->ps.groundEntityNum != ENTITYNUM_NONE &&//on the ground
02550                                 !(self->client->ps.pm_flags&PMF_DUCKED)&&cmd->upmove>=0&&TIMER_Done( self, "duck" )//not ducking
02551                                 && !BG_InRoll( &self->client->ps, self->client->ps.legsAnim )//not rolling
02552                                 && !PM_InKnockDown( &self->client->ps )//not knocked down
02553                                 && ( self->client->ps.saberInFlight ||
02554                                         self->client->NPC_class == CLASS_BOBAFETT ||
02555                                         (!BG_SaberInAttack( self->client->ps.saberMove )//not attacking
02556                                         && !PM_SaberInStart( self->client->ps.saberMove )//not starting an attack
02557                                         && !BG_SpinningSaberAnim( self->client->ps.torsoAnim )//not in a saber spin
02558                                         && !BG_SaberInSpecialAttack( self->client->ps.torsoAnim ))//not in a special attack
02559                                         )
02560                                 )
02561                         {//need to check all these because it overrides both torso and legs with the dodge
02562                                 doDodge = qtrue;
02563                         }
02564                 }
02565         }
02566         // Figure out what quadrant the block was in.
02567         if ( d_JediAI.integer )
02568         {
02569                 Com_Printf( "(%d) evading attack from height %4.2f, zdiff: %4.2f, rightdot: %4.2f\n", level.time, hitloc[2]-self->r.absmin[2],zdiff,rightdot);
02570         }
02571 
02572         //UL = > -1//-6
02573         //UR = > -6//-9
02574         //TOP = > +6//+4
02575         //FIXME: take FP_SABER_DEFENSE into account here somehow?
02576         if ( zdiff >= -5 )//was 0
02577         {
02578                 if ( incoming || !saberBusy )
02579                 {
02580                         if ( rightdot > 12 
02581                                 || (rightdot > 3 && zdiff < 5) 
02582                                 || (!incoming&&fabs(hitdir[2])<0.25f) )//was normalized, 0.3
02583                         {//coming from right
02584                                 if ( doDodge )
02585                                 {
02586                                         if ( self->client->NPC_class == CLASS_BOBAFETT && !Q_irand( 0, 2 ) )
02587                                         {//roll!
02588                                                 TIMER_Start( self, "duck", Q_irand( 500, 1500 ) );
02589                                                 TIMER_Start( self, "strafeLeft", Q_irand( 500, 1500 ) );
02590                                                 TIMER_Set( self, "strafeRight", 0 );
02591                                                 evasionType = EVASION_DUCK;
02592                                                 evaded = qtrue;
02593                                         }
02594                                         else if ( Q_irand( 0, 1 ) )
02595                                         {
02596                                                 dodgeAnim = BOTH_DODGE_FL;
02597                                         }
02598                                         else
02599                                         {
02600                                                 dodgeAnim = BOTH_DODGE_BL;
02601                                         }
02602                                 }
02603                                 else
02604                                 {
02605                                         self->client->ps.saberBlocked = BLOCKED_UPPER_RIGHT;
02606                                         evasionType = EVASION_PARRY;
02607                                         if ( self->client->ps.groundEntityNum != ENTITYNUM_NONE )
02608                                         {
02609                                                 if ( zdiff > 5 )
02610                                                 {
02611                                                         TIMER_Start( self, "duck", Q_irand( 500, 1500 ) );
02612                                                         evasionType = EVASION_DUCK_PARRY;
02613                                                         evaded = qtrue;
02614                                                         if ( d_JediAI.integer )
02615                                                         {
02616                                                                 Com_Printf( "duck " );
02617                                                         }
02618                                                 }
02619                                                 else
02620                                                 {
02621                                                         duckChance = 6;
02622                                                 }
02623                                         }
02624                                 }
02625                                 if ( d_JediAI.integer )
02626                                 {
02627                                         Com_Printf( "UR block\n" );
02628                                 }
02629                         }
02630                         else if ( rightdot < -12 
02631                                 || (rightdot < -3 && zdiff < 5) 
02632                                 || (!incoming&&fabs(hitdir[2])<0.25f) )//was normalized, -0.3
02633                         {//coming from left
02634                                 if ( doDodge )
02635                                 {
02636                                         if ( self->client->NPC_class == CLASS_BOBAFETT && !Q_irand( 0, 2 ) )
02637                                         {//roll!
02638                                                 TIMER_Start( self, "duck", Q_irand( 500, 1500 ) );
02639                                                 TIMER_Start( self, "strafeRight", Q_irand( 500, 1500 ) );
02640                                                 TIMER_Set( self, "strafeLeft", 0 );
02641                                                 evasionType = EVASION_DUCK;
02642                                                 evaded = qtrue;
02643                                         }
02644                                         else if ( Q_irand( 0, 1 ) )
02645                                         {
02646                                                 dodgeAnim = BOTH_DODGE_FR;
02647                                         }
02648                                         else
02649                                         {
02650                                                 dodgeAnim = BOTH_DODGE_BR;
02651                                         }
02652                                 }
02653                                 else
02654                                 {
02655                                         self->client->ps.saberBlocked = BLOCKED_UPPER_LEFT;
02656                                         evasionType = EVASION_PARRY;
02657                                         if ( self->client->ps.groundEntityNum != ENTITYNUM_NONE )
02658                                         {
02659                                                 if ( zdiff > 5 )
02660                                                 {
02661                                                         TIMER_Start( self, "duck", Q_irand( 500, 1500 ) );
02662                                                         evasionType = EVASION_DUCK_PARRY;
02663                                                         evaded = qtrue;
02664                                                         if ( d_JediAI.integer )
02665                                                         {
02666                                                                 Com_Printf( "duck " );
02667                                                         }
02668                                                 }
02669                                                 else
02670                                                 {
02671                                                         duckChance = 6;
02672                                                 }
02673                                         }
02674                                 }
02675                                 if ( d_JediAI.integer )
02676                                 {
02677                                         Com_Printf( "UL block\n" );
02678                                 }
02679                         }
02680                         else
02681                         {
02682                                 self->client->ps.saberBlocked = BLOCKED_TOP;
02683                                 evasionType = EVASION_PARRY;
02684                                 if ( self->client->ps.groundEntityNum != ENTITYNUM_NONE )
02685                                 {
02686                                         duckChance = 4;
02687                                 }
02688                                 if ( d_JediAI.integer )
02689                                 {
02690                                         Com_Printf( "TOP block\n" );
02691                                 }
02692                         }
02693                         evaded = qtrue;
02694                 }
02695                 else
02696                 {
02697                         if ( self->client->ps.groundEntityNum != ENTITYNUM_NONE )
02698                         {
02699                                 //duckChance = 2;
02700                                 TIMER_Start( self, "duck", Q_irand( 500, 1500 ) );
02701                                 evasionType = EVASION_DUCK;
02702                                 evaded = qtrue;
02703                                 if ( d_JediAI.integer )
02704                                 {
02705                                         Com_Printf( "duck " );
02706                                 }
02707                         }
02708                 }
02709         }
02710         //LL = -22//= -18 to -39
02711         //LR = -23//= -20 to -41
02712         else if ( zdiff > -22 )//was-15 )
02713         {
02714                 if ( 1 )//zdiff < -10 )
02715                 {//hmm, pretty low, but not low enough to use the low block, so we need to duck
02716                         if ( self->client->ps.groundEntityNum != ENTITYNUM_NONE )
02717                         {
02718                                 //duckChance = 2;
02719                                 TIMER_Start( self, "duck", Q_irand( 500, 1500 ) );
02720                                 evasionType = EVASION_DUCK;
02721                                 evaded = qtrue;
02722                                 if ( d_JediAI.integer )
02723                                 {
02724                                         Com_Printf( "duck " );
02725                                 }
02726                         }
02727                         else
02728                         {//in air!  Ducking does no good
02729                         }
02730                 }
02731                 if ( incoming || !saberBusy )
02732                 {
02733                         if ( rightdot > 8 || (rightdot > 3 && zdiff < -11) )//was normalized, 0.2
02734                         {
02735                                 if ( doDodge )
02736                                 {
02737                                         if ( self->client->NPC_class == CLASS_BOBAFETT && !Q_irand( 0, 2 ) )
02738                                         {//roll!
02739                                                 TIMER_Start( self, "strafeLeft", Q_irand( 500, 1500 ) );
02740                                                 TIMER_Set( self, "strafeRight", 0 );
02741                                         }
02742                                         else 
02743                                         {
02744                                                 dodgeAnim = BOTH_DODGE_L;
02745                                         }
02746                                 }
02747                                 else
02748                                 {
02749                                         self->client->ps.saberBlocked = BLOCKED_UPPER_RIGHT;
02750                                         if ( evasionType == EVASION_DUCK )
02751                                         {
02752                                                 evasionType = EVASION_DUCK_PARRY;
02753                                         }
02754                                         else
02755                                         {
02756                                                 evasionType = EVASION_PARRY;
02757                                         }
02758                                 }
02759                                 if ( d_JediAI.integer )
02760                                 {
02761                                         Com_Printf( "mid-UR block\n" );
02762                                 }
02763                         }
02764                         else if ( rightdot < -8 || (rightdot < -3 && zdiff < -11) )//was normalized, -0.2
02765                         {
02766                                 if ( doDodge )
02767                                 {
02768                                         if ( self->client->NPC_class == CLASS_BOBAFETT && !Q_irand( 0, 2 ) )
02769                                         {//roll!
02770                                                 TIMER_Start( self, "strafeLeft", Q_irand( 500, 1500 ) );
02771                                                 TIMER_Set( self, "strafeRight", 0 );
02772                                         }
02773                                         else 
02774                                         {
02775                                                 dodgeAnim = BOTH_DODGE_R;
02776                                         }
02777                                 }
02778                                 else
02779                                 {
02780                                         self->client->ps.saberBlocked = BLOCKED_UPPER_LEFT;
02781                                         if ( evasionType == EVASION_DUCK )
02782                                         {
02783                                                 evasionType = EVASION_DUCK_PARRY;
02784                                         }
02785                                         else
02786                                         {
02787                                                 evasionType = EVASION_PARRY;
02788                                         }
02789                                 }
02790                                 if ( d_JediAI.integer )
02791                                 {
02792                                         Com_Printf( "mid-UL block\n" );
02793                                 }
02794                         }
02795                         else
02796                         {
02797                                 self->client->ps.saberBlocked = BLOCKED_TOP;
02798                                 if ( evasionType == EVASION_DUCK )
02799                                 {
02800                                         evasionType = EVASION_DUCK_PARRY;
02801                                 }
02802                                 else
02803                                 {
02804                                         evasionType = EVASION_PARRY;
02805                                 }
02806                                 if ( d_JediAI.integer )
02807                                 {
02808                                         Com_Printf( "mid-TOP block\n" );
02809                                 }
02810                         }
02811                         evaded = qtrue;
02812                 }
02813         }
02814         else if ( saberBusy || (zdiff < -36 && ( zdiff < -44 || !Q_irand( 0, 2 ) ) ) )//was -30 and -40//2nd one was -46
02815         {//jump!
02816                 if ( self->client->ps.groundEntityNum == ENTITYNUM_NONE )
02817                 {//already in air, duck to pull up legs
02818                         TIMER_Start( self, "duck", Q_irand( 500, 1500 ) );
02819                         evasionType = EVASION_DUCK;
02820                         evaded = qtrue;
02821                         if ( d_JediAI.integer )
02822                         {
02823                                 Com_Printf( "legs up\n" );
02824                         }
02825                         if ( incoming || !saberBusy )
02826                         {
02827                                 //since the jump may be cleared if not safe, set a lower block too
02828                                 if ( rightdot >= 0 )
02829                                 {
02830                                         self->client->ps.saberBlocked = BLOCKED_LOWER_RIGHT;
02831                                         evasionType = EVASION_DUCK_PARRY;
02832                                         if ( d_JediAI.integer )
02833                                         {
02834                                                 Com_Printf( "LR block\n" );
02835                                         }
02836                                 }
02837                                 else
02838                                 {
02839                                         self->client->ps.saberBlocked = BLOCKED_LOWER_LEFT;
02840                                         evasionType = EVASION_DUCK_PARRY;
02841                                         if ( d_JediAI.integer )
02842                                         {
02843                                                 Com_Printf( "LL block\n" );
02844                                         }
02845                                 }
02846                                 evaded = qtrue;
02847                         }
02848                 }
02849                 else 
02850                 {//gotta jump!
02851                         if ( self->NPC && (self->NPC->rank == RANK_CREWMAN || self->NPC->rank > RANK_LT_JG ) &&
02852                                 (!Q_irand( 0, 10 ) || (!Q_irand( 0, 2 ) && (cmd->forwardmove || cmd->rightmove))) )
02853                         {//superjump
02854                                 //FIXME: check the jump, if can't, then block
02855                                 if ( self->NPC 
02856                                         && !(self->NPC->scriptFlags&SCF_NO_ACROBATICS) 
02857                                         && self->client->ps.fd.forceRageRecoveryTime < level.time
02858                                         && !(self->client->ps.fd.forcePowersActive&(1<<FP_RAGE)) 
02859                                         && !PM_InKnockDown( &self->client->ps ) )
02860                                 {
02861                                         self->client->ps.fd.forceJumpCharge = 320;//FIXME: calc this intelligently
02862                                         evasionType = EVASION_FJUMP;
02863                                         evaded = qtrue;
02864                                         if ( d_JediAI.integer )
02865                                         {
02866                                                 Com_Printf( "force jump + " );
02867                                         }
02868                                 }
02869                         }
02870                         else
02871                         {//normal jump
02872                                 //FIXME: check the jump, if can't, then block
02873                                 if ( self->NPC 
02874                                         && !(self->NPC->scriptFlags&SCF_NO_ACROBATICS) 
02875                                         && self->client->ps.fd.forceRageRecoveryTime < level.time
02876                                         && !(self->client->ps.fd.forcePowersActive&(1<<FP_RAGE)) )
02877                                 {
02878                                         if ( self->client->NPC_class == CLASS_BOBAFETT && !Q_irand( 0, 1 ) )
02879                                         {//roll!
02880                                                 if ( rightdot > 0 )
02881                                                 {
02882                                                         TIMER_Start( self, "strafeLeft", Q_irand( 500, 1500 ) );
02883                                                         TIMER_Set( self, "strafeRight", 0 );
02884                                                         TIMER_Set( self, "walking", 0 );
02885                                                 }
02886                                                 else
02887                                                 {
02888                                                         TIMER_Start( self, "strafeRight", Q_irand( 500, 1500 ) );
02889                                                         TIMER_Set( self, "strafeLeft", 0 );
02890                                                         TIMER_Set( self, "walking", 0 );
02891                                                 }
02892                                         }
02893                                         else
02894                                         {
02895                                                 if ( self == NPC )
02896                                                 {
02897                                                         cmd->upmove = 127;
02898                                                 }
02899                                                 else
02900                                                 {
02901                                                         self->client->ps.velocity[2] = JUMP_VELOCITY;
02902                                                 }
02903                                         }
02904                                         evasionType = EVASION_JUMP;
02905                                         evaded = qtrue;
02906                                         if ( d_JediAI.integer )
02907                                         {
02908                                                 Com_Printf( "jump + " );
02909                                         }
02910                                 }
02911                                 if ( self->client->NPC_class == CLASS_TAVION )
02912                                 {
02913                                         if ( !incoming 
02914                                                 && self->client->ps.groundEntityNum < ENTITYNUM_NONE 
02915                                                 && !Q_irand( 0, 2 ) )
02916                                         {
02917                                                 if ( !BG_SaberInAttack( self->client->ps.saberMove )
02918                                                         && !PM_SaberInStart( self->client->ps.saberMove ) 
02919                                                         && !BG_InRoll( &self->client->ps, self->client->ps.legsAnim )
02920                                                         && !PM_InKnockDown( &self->client->ps )
02921                                                         && !BG_SaberInSpecialAttack( self->client->ps.torsoAnim ) )
02922                                                 {//do the butterfly!
02923                                                         int butterflyAnim;
02924                                                         if ( Q_irand( 0, 1 ) )
02925                                                         {
02926                                                                 butterflyAnim = BOTH_BUTTERFLY_LEFT;
02927                                                         }
02928                                                         else
02929                                                         {
02930                                                                 butterflyAnim = BOTH_BUTTERFLY_RIGHT;
02931                                                         }
02932                                                         evasionType = EVASION_CARTWHEEL;
02933                                                         NPC_SetAnim( self, SETANIM_BOTH, butterflyAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
02934                                                         self->client->ps.velocity[2] = 225;
02935                                                         self->client->ps.fd.forceJumpZStart = self->r.currentOrigin[2];//so we don't take damage if we land at same height
02936                                                 //      self->client->ps.pm_flags |= PMF_JUMPING|PMF_SLOW_MO_FALL;
02937                                                 //      self->client->ps.SaberActivateTrail( 300 );//FIXME: reset this when done!
02938                                                         //Ah well. No hacking from the server for now.
02939                                                         if ( self->client->NPC_class == CLASS_BOBAFETT )
02940                                                         {
02941                                                                 G_AddEvent( self, EV_JUMP, 0 );
02942                                                         }
02943                                                         else
02944                                                         {
02945                                                                 G_Sound( self, CHAN_BODY, G_SoundIndex("sound/weapons/force/jump.wav") );
02946                                                         }
02947                                                         cmd->upmove = 0;
02948                                                         saberBusy = qtrue;
02949                                                         evaded = qtrue;
02950                                                 }
02951                                         }
02952                                 }
02953                         }
02954                         if ( ((evasionType = Jedi_CheckFlipEvasions( self, rightdot, zdiff ))!=EVASION_NONE) )
02955                         {
02956                                 if ( d_slowmodeath.integer > 5 && self->enemy && !self->enemy->s.number )
02957                                 {
02958                                         G_StartMatrixEffect( self );
02959                                 }
02960                                 saberBusy = qtrue;
02961                                 evaded = qtrue;
02962                         }
02963                         else if ( incoming || !saberBusy )
02964                         {
02965                                 //since the jump may be cleared if not safe, set a lower block too
02966                                 if ( rightdot >= 0 )
02967                                 {
02968                                         self->client->ps.saberBlocked = BLOCKED_LOWER_RIGHT;
02969                                         if ( evasionType == EVASION_JUMP )
02970                                         {
02971                                                 evasionType = EVASION_JUMP_PARRY;
02972                                         }
02973                                         else if ( evasionType == EVASION_NONE )
02974                                         {
02975                                                 evasionType = EVASION_PARRY;
02976                                         }
02977                                         if ( d_JediAI.integer )
02978                                         {
02979                                                 Com_Printf( "LR block\n" );
02980                                         }
02981                                 }
02982                                 else
02983                                 {
02984                                         self->client->ps.saberBlocked = BLOCKED_LOWER_LEFT;
02985                                         if ( evasionType == EVASION_JUMP )
02986                                         {
02987                                                 evasionType = EVASION_JUMP_PARRY;
02988                                         }
02989                                         else if ( evasionType == EVASION_NONE )
02990                                         {
02991                                                 evasionType = EVASION_PARRY;
02992                                         }
02993                                         if ( d_JediAI.integer )
02994                                         {
02995                                                 Com_Printf( "LL block\n" );
02996                                         }
02997                                 }
02998                                 evaded = qtrue;
02999                         }
03000                 }
03001         }
03002         else
03003         {
03004                 if ( incoming || !saberBusy )
03005                 {
03006                         if ( rightdot >= 0 )
03007                         {
03008                                 self->client->ps.saberBlocked = BLOCKED_LOWER_RIGHT;
03009                                 evasionType = EVASION_PARRY;
03010                                 if ( d_JediAI.integer )
03011                                 {
03012                                         Com_Printf( "LR block\n" );
03013                                 }
03014                         }
03015                         else
03016                         {
03017                                 self->client->ps.saberBlocked = BLOCKED_LOWER_LEFT;
03018                                 evasionType = EVASION_PARRY;
03019                                 if ( d_JediAI.integer )
03020                                 {
03021                                         Com_Printf( "LL block\n" );
03022                                 }
03023                         }
03024                         if ( incoming && incoming->s.weapon == WP_SABER )
03025                         {//thrown saber!
03026                                 if ( self->NPC && (self->NPC->rank == RANK_CREWMAN || self->NPC->rank > RANK_LT_JG ) &&
03027                                         (!Q_irand( 0, 10 ) || (!Q_irand( 0, 2 ) && (cmd->forwardmove || cmd->rightmove))) )
03028                                 {//superjump
03029                                         //FIXME: check the jump, if can't, then block
03030                                         if ( self->NPC 
03031                                                 && !(self->NPC->scriptFlags&SCF_NO_ACROBATICS) 
03032                                                 && self->client->ps.fd.forceRageRecoveryTime < level.time
03033                                                 && !(self->client->ps.fd.forcePowersActive&(1<<FP_RAGE)) 
03034                                                 && !PM_InKnockDown( &self->client->ps ) )
03035                                         {
03036                                                 self->client->ps.fd.forceJumpCharge = 320;//FIXME: calc this intelligently
03037                                                 evasionType = EVASION_FJUMP;
03038                                                 if ( d_JediAI.integer )
03039                                                 {
03040                                                         Com_Printf( "force jump + " );
03041                                                 }
03042                                         }
03043                                 }
03044                                 else
03045                                 {//normal jump
03046                                         //FIXME: check the jump, if can't, then block
03047                                         if ( self->NPC 
03048                                                 && !(self->NPC->scriptFlags&SCF_NO_ACROBATICS) 
03049                                                 && self->client->ps.fd.forceRageRecoveryTime < level.time
03050                                                 && !(self->client->ps.fd.forcePowersActive&(1<<FP_RAGE)))
03051                                         {
03052                                                 if ( self == NPC )
03053                                                 {
03054                                                         cmd->upmove = 127;
03055                                                 }
03056                                                 else
03057                                                 {
03058                                                         self->client->ps.velocity[2] = JUMP_VELOCITY;
03059                                                 }
03060                                                 evasionType = EVASION_JUMP_PARRY;
03061                                                 if ( d_JediAI.integer )
03062                                                 {
03063                                                         Com_Printf( "jump + " );
03064                                                 }
03065                                         }
03066                                 }
03067                         }
03068                         evaded = qtrue;
03069                 }
03070         }
03071 
03072         if ( evasionType == EVASION_NONE )
03073         {
03074                 return EVASION_NONE;
03075         }
03076         //stop taunting
03077         TIMER_Set( self, "taunting", 0 );
03078         //stop gripping
03079         TIMER_Set( self, "gripping", -level.time );
03080         WP_ForcePowerStop( self, FP_GRIP );
03081         //stop draining
03082         TIMER_Set( self, "draining", -level.time );
03083         WP_ForcePowerStop( self, FP_DRAIN );
03084 
03085         if ( dodgeAnim != -1 )
03086         {//dodged
03087                 evasionType = EVASION_DODGE;
03088                 NPC_SetAnim( self, SETANIM_BOTH, dodgeAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
03089                 self->client->ps.weaponTime = self->client->ps.torsoTimer;
03090                 //force them to stop moving in this case
03091                 self->client->ps.pm_time = self->client->ps.torsoTimer;
03092                 //FIXME: maybe make a sound?  Like a grunt?  EV_JUMP?
03093                 self->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
03094                 //dodged, not block
03095                 if ( d_slowmodeath.integer > 5 && self->enemy && !self->enemy->s.number )
03096                 {
03097                         G_StartMatrixEffect( self );
03098                 }
03099         }
03100         else
03101         {
03102                 if ( duckChance )
03103                 {
03104                         if ( !Q_irand( 0, duckChance ) )
03105                         {
03106                                 TIMER_Start( self, "duck", Q_irand( 500, 1500 ) );
03107                                 if ( evasionType == EVASION_PARRY )
03108                                 {
03109                                         evasionType = EVASION_DUCK_PARRY;
03110                                 }
03111                                 else
03112                                 {
03113                                         evasionType = EVASION_DUCK;
03114                                 }
03115                                 /*
03116                                 if ( d_JediAI.integer )
03117                                 {
03118                                         Com_Printf( "duck " );
03119                                 }
03120                                 */
03121                         }
03122                 }
03123 
03124                 if ( incoming )
03125                 {
03126                         self->client->ps.saberBlocked = WP_MissileBlockForBlock( self->client->ps.saberBlocked );
03127                 }
03128 
03129         }
03130         //if ( self->client->ps.saberBlocked != BLOCKED_NONE )
03131         {
03132                 int parryReCalcTime = Jedi_ReCalcParryTime( self, evasionType );
03133                 if ( self->client->ps.fd.forcePowerDebounce[FP_SABER_DEFENSE] < level.time + parryReCalcTime )
03134                 {
03135                         self->client->ps.fd.forcePowerDebounce[FP_SABER_DEFENSE] = level.time + parryReCalcTime;
03136                 }
03137         }
03138         return evasionType;
03139 }

qboolean Jedi_SaberBusy gentity_t self  ) 
 

Definition at line 2455 of file NPC_AI_Jedi.c.

References BG_FlippingAnim(), BG_SaberInAttack(), BG_SaberInSpecialAttack(), BG_SpinningSaberAnim(), gentity_s::client, playerState_s::fd, FORCE_LEVEL_3, gentity_t, PM_RollingAnim(), PM_SaberInBrokenParry(), gclient_s::ps, qboolean, qfalse, qtrue, forcedata_s::saberAnimLevel, playerState_s::saberMove, playerState_s::torsoAnim, and playerState_s::torsoTimer.

Referenced by Jedi_SaberBlockGo().

02456 {
02457         if ( self->client->ps.torsoTimer > 300 
02458         && ( (BG_SaberInAttack( self->client->ps.saberMove )&&self->client->ps.fd.saberAnimLevel==FORCE_LEVEL_3) 
02459                 || BG_SpinningSaberAnim( self->client->ps.torsoAnim ) 
02460                 || BG_SaberInSpecialAttack( self->client->ps.torsoAnim ) 
02461                 //|| PM_SaberInBounce( self->client->ps.saberMove ) 
02462                 || PM_SaberInBrokenParry( self->client->ps.saberMove ) 
02463                 //|| PM_SaberInDeflect( self->client->ps.saberMove ) 
02464                 || BG_FlippingAnim( self->client->ps.torsoAnim ) 
02465                 || PM_RollingAnim( self->client->ps.torsoAnim ) ) )
02466         {//my saber is not in a parrying position
02467                 return qtrue;
02468         }
02469         return qfalse;
02470 }

qboolean Jedi_WaitingAmbush gentity_t self  ) 
 

void NPC_BSJedi_Default void   ) 
 

Definition at line 6170 of file NPC_AI_Jedi.c.

References Boba_ChangeWeapon(), usercmd_s::buttons, CLASS_BOBAFETT, gentity_s::client, gNPC_t::confusionTime, entityShared_t::currentOrigin, gentity_s::enemy, gNPC_t::enemyCheckDebounceTime, playerState_s::fd, forcedata_s::forcePowersActive, G_SetEnemy(), gentity_t, gentity_s::health, Jedi_Ambush(), Jedi_CheckCloak(), Jedi_WaitingAmbush(), gentity_s::lastEnemy, level, clientPersistant_t::maxHealth, NPC, NPC_BSSniper_Default(), NPC_BSST_Patrol(), NPC_CheckEnemy(), gclient_s::NPC_class, NPCInfo, NULL, gclient_s::pers, gclient_s::ps, Q_irand(), qfalse, gentity_s::r, SCF_ALT_FIRE, gNPC_t::scriptFlags, level_locals_t::time, ucmd, and WP_DISRUPTOR.

Referenced by NPC_BehaviorSet_Jedi().

06171 {
06172 
06173         Jedi_CheckCloak();
06174         if( !NPC->enemy )
06175         {//don't have an enemy, look for one
06176                 if ( NPC->client->NPC_class == CLASS_BOBAFETT )
06177                 {
06178                         NPC_BSST_Patrol();
06179                 }
06180                 else
06181                 {
06182                         Jedi_Patrol();
06183                 }
06184         }
06185         else//if ( NPC->enemy )
06186         {//have an enemy
06187                 if ( Jedi_WaitingAmbush( NPC ) )
06188                 {//we were still waiting to drop down - must have had enemy set on me outside my AI
06189                         Jedi_Ambush( NPC );
06190                 }
06191                 if ( NPC->client->NPC_class == CLASS_BOBAFETT )
06192                 {
06193                         if ( NPC->enemy->enemy != NPC && NPC->health == NPC->client->pers.maxHealth && DistanceSquared( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin )>(800*800) )
06194                         {
06195                                 NPCInfo->scriptFlags |= SCF_ALT_FIRE;
06196                                 Boba_ChangeWeapon( WP_DISRUPTOR );
06197                                 NPC_BSSniper_Default();
06198                                 return;
06199                         }
06200                 }
06201                 Jedi_Attack();
06202                 //if we have multiple-jedi combat, probably need to keep checking (at certain debounce intervals) for a better (closer, more active) enemy and switch if needbe...
06203                 if ( ((!ucmd.buttons&&!NPC->client->ps.fd.forcePowersActive)||(NPC->enemy&&NPC->enemy->health<=0)) && NPCInfo->enemyCheckDebounceTime < level.time )
06204                 {//not doing anything (or walking toward a vanquished enemy - fixme: always taunt the player?), not using force powers and it's time to look again
06205                         //FIXME: build a list of all local enemies (since we have to find best anyway) for other AI factors- like when to use group attacks, determine when to change tactics, when surrounded, when blocked by another in the enemy group, etc.  Should we build this group list or let the enemies maintain their own list and we just access it?
06206                         gentity_t *sav_enemy = NPC->enemy;//FIXME: what about NPC->lastEnemy?
06207                         gentity_t *newEnemy;
06208 
06209                         NPC->enemy = NULL;
06210                         newEnemy = NPC_CheckEnemy( NPCInfo->confusionTime < level.time, qfalse, qfalse );
06211                         NPC->enemy = sav_enemy;
06212                         if ( newEnemy && newEnemy != sav_enemy )
06213                         {//picked up a new enemy!
06214                                 NPC->lastEnemy = NPC->enemy;
06215                                 G_SetEnemy( NPC, newEnemy );
06216                         }
06217                         NPCInfo->enemyCheckDebounceTime = level.time + Q_irand( 1000, 3000 );
06218                 }
06219         }
06220 }

void NPC_BSJedi_FollowLeader void   ) 
 

Definition at line 5758 of file NPC_AI_Jedi.c.

References gNPC_t::aiFlags, BLOCKED_NONE, gNPC_t::blockedDest, BUTTON_ATTACK, usercmd_s::buttons, gentity_s::client, gentity_s::clipmask, CONTENTS_BODY, CONTENTS_BOTCLIP, entityShared_t::currentOrigin, gentity_s::enemy, ENTITYNUM_NONE, fabs(), g_entities, G_FreeEntity(), G_SetOrigin(), G_Spawn(), gentity_t, gNPC_t::goalEntity, gentity_s::health, Jedi_CanPullBackSaber(), NAV_CheckAhead(), NPC, NPC_BSFollowLeader(), NPC_ClearLOS4(), NPC_FaceEntity(), NPC_MoveToGoal(), NPC_UpdateAngles(), NPCAI_BLOCKED, NPCInfo, gclient_s::ps, qtrue, gentity_s::r, playerState_s::saberBlocked, playerState_s::saberEntityNum, playerState_s::saberInFlight, TIMER_Set(), TR_STATIONARY, trap_LinkEntity(), and ucmd.

Referenced by NPC_BehaviorSet_Jedi().

05759 {
05760         NPC->client->ps.saberBlocked = BLOCKED_NONE;
05761         if ( !NPC->enemy )
05762         {
05763                 //Com_Printf( "(%d) drop agg - no enemy (follow)\n", level.time );
05764                 Jedi_AggressionErosion(-1);
05765         }
05766         
05767         //did we drop our saber?  If so, go after it!
05768         if ( NPC->client->ps.saberInFlight )
05769         {//saber is not in hand
05770                 if ( NPC->client->ps.saberEntityNum < ENTITYNUM_NONE && NPC->client->ps.saberEntityNum > 0 )//player is 0
05771                 {//
05772                         if ( g_entities[NPC->client->ps.saberEntityNum].s.pos.trType == TR_STATIONARY )
05773                         {//fell to the ground, try to pick it up... 
05774                                 if ( Jedi_CanPullBackSaber( NPC ) )
05775                                 {
05776                                         //FIXME: if it's on the ground and we just pulled it back to us, should we
05777                                         //              stand still for a bit to make sure it gets to us...?
05778                                         //              otherwise we could end up running away from it while it's on its
05779                                         //              way back to us and we could lose it again.
05780                                         NPC->client->ps.saberBlocked = BLOCKED_NONE;
05781                                         NPCInfo->goalEntity = &g_entities[NPC->client->ps.saberEntityNum];
05782                                         ucmd.buttons |= BUTTON_ATTACK;
05783                                         if ( NPC->enemy && NPC->enemy->health > 0 )
05784                                         {//get our saber back NOW!
05785                                                 if ( !NPC_MoveToGoal( qtrue ) )//Jedi_Move( NPCInfo->goalEntity, qfalse );
05786                                                 {//can't nav to it, try jumping to it
05787                                                         NPC_FaceEntity( NPCInfo->goalEntity, qtrue );
05788                                                         Jedi_TryJump( NPCInfo->goalEntity );
05789                                                 }
05790                                                 NPC_UpdateAngles( qtrue, qtrue );
05791                                                 return;
05792                                         }
05793                                 }
05794                         }
05795                 }
05796         }
05797 
05798         if ( NPCInfo->goalEntity )
05799         {
05800                 trace_t trace;
05801 
05802                 if ( Jedi_Jumping( NPCInfo->goalEntity ) )
05803                 {//in mid-jump
05804                         return;
05805                 }
05806 
05807                 if ( !NAV_CheckAhead( NPC, NPCInfo->goalEntity->r.currentOrigin, &trace, ( NPC->clipmask & ~CONTENTS_BODY )|CONTENTS_BOTCLIP ) )
05808                 {//can't get straight to him
05809                         if ( NPC_ClearLOS4( NPCInfo->goalEntity ) && NPC_FaceEntity( NPCInfo->goalEntity, qtrue ) )
05810                         {//no line of sight
05811                                 if ( Jedi_TryJump( NPCInfo->goalEntity ) )
05812                                 {//started a jump
05813                                         return;
05814                                 }
05815                         }
05816                 }
05817                 if ( NPCInfo->aiFlags & NPCAI_BLOCKED )
05818                 {//try to jump to the blockedDest
05819                         if ( fabs(NPCInfo->blockedDest[2]-NPC->r.currentOrigin[2]) > 64 )
05820                         {
05821                                 gentity_t *tempGoal = G_Spawn();//ugh, this is NOT good...?
05822                                 G_SetOrigin( tempGoal, NPCInfo->blockedDest );
05823                                 trap_LinkEntity( tempGoal );
05824                                 TIMER_Set( NPC, "jumpChaseDebounce", -1 );
05825                                 if ( Jedi_TryJump( tempGoal ) )
05826                                 {//going to jump to the dest
05827                                         G_FreeEntity( tempGoal );
05828                                         return;
05829                                 }
05830                                 G_FreeEntity( tempGoal );
05831                         }
05832                 }
05833         }
05834         //try normal movement
05835         NPC_BSFollowLeader();
05836 }

void NPC_BSSniper_Default void   ) 
 

Definition at line 854 of file NPC_AI_Sniper.c.

References gentity_s::enemy, NPC, NPC_BSSniper_Attack(), and NPC_BSSniper_Patrol().

00855 {
00856         if( !NPC->enemy )
00857         {//don't have an enemy, look for one
00858                 NPC_BSSniper_Patrol();
00859         }
00860         else//if ( NPC->enemy )
00861         {//have an enemy
00862                 NPC_BSSniper_Attack();
00863         }
00864 }

void NPC_BSST_Patrol void   ) 
 

Definition at line 1077 of file NPC_AI_Stormtrooper.c.

References AEL_MINOR, AI_GetGroup(), entityState_s::angles, BOTH_STAND4, BUTTON_WALKING, usercmd_s::buttons, ChangeWeapon(), CLASS_IMPERIAL, CLASS_IMPWORKER, gentity_s::client, gNPC_t::confusionTime, gNPC_t::desiredPitch, gNPC_t::desiredYaw, usercmd_s::forwardmove, playerState_s::legsAnim, playerState_s::legsTimer, level, NPC, NPC_CheckAlertEvents(), NPC_CheckPlayerTeamStealth(), gclient_s::NPC_class, NPC_MoveToGoal(), NPC_SetAnim(), NPC_UpdateAngles(), NPCInfo, gclient_s::ps, Q_irand(), qfalse, qtrue, usercmd_s::rightmove, gentity_s::s, SCF_IGNORE_ALERTS, SCF_LOOK_FOR_ENEMIES, SCF_RUNNING, gNPC_t::scriptFlags, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, SETANIM_TORSO, level_locals_t::time, TIMER_Done(), playerState_s::torsoAnim, playerState_s::torsoTimer, ucmd, UpdateGoal(), usercmd_s::upmove, playerState_s::weapon, WEAPON_READY, playerState_s::weaponstate, and WP_NONE.

Referenced by NPC_BSJedi_Default(), NPC_BSST_Attack(), and NPC_BSST_Default().

01078 {//FIXME: pick up on bodies of dead buddies?
01079         
01080         //get group- mainly for group speech debouncing, but may use for group scouting/investigating AI, too
01081         AI_GetGroup( NPC );
01082 
01083         if ( NPCInfo->confusionTime < level.time )
01084         {
01085                 //Look for any enemies
01086                 if ( NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES )
01087                 {
01088                         if ( NPC_CheckPlayerTeamStealth() )
01089                         {
01090                                 //NPCInfo->behaviorState = BS_HUNT_AND_KILL;//should be auto now
01091                                 //NPC_AngerSound();
01092                                 NPC_UpdateAngles( qtrue, qtrue );
01093                                 return;
01094                         }
01095                 }
01096         }
01097 
01098         if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) )
01099         {
01100                 int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_MINOR );
01101 
01102                 //There is an event to look at
01103                 if ( alertEvent >= 0 )
01104                 {
01105                         if ( NPC_ST_InvestigateEvent( alertEvent, qfalse ) )
01106                         {//actually going to investigate it
01107                                 NPC_UpdateAngles( qtrue, qtrue );
01108                                 return;
01109                         }
01110                 }
01111         }
01112 
01113         //If we have somewhere to go, then do that
01114         if ( UpdateGoal() )
01115         {
01116                 ucmd.buttons |= BUTTON_WALKING;
01117                 //ST_Move( NPCInfo->goalEntity );
01118                 NPC_MoveToGoal( qtrue );
01119         }
01120         else// if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) )
01121         {
01122                 if ( NPC->client->NPC_class != CLASS_IMPERIAL && NPC->client->NPC_class != CLASS_IMPWORKER )
01123                 {//imperials do not look around
01124                         if ( TIMER_Done( NPC, "enemyLastVisible" ) )
01125                         {//nothing suspicious, look around
01126                                 if ( !Q_irand( 0, 30 ) )
01127                                 {
01128                                         NPCInfo->desiredYaw = NPC->s.angles[1] + Q_irand( -90, 90 );
01129                                 }
01130                                 if ( !Q_irand( 0, 30 ) )
01131                                 {
01132                                         NPCInfo->desiredPitch = Q_irand( -20, 20 );
01133                                 }
01134                         }
01135                 }
01136         }
01137 
01138         NPC_UpdateAngles( qtrue, qtrue );
01139         //TEMP hack for Imperial stand anim
01140         if ( NPC->client->NPC_class == CLASS_IMPERIAL || NPC->client->NPC_class == CLASS_IMPWORKER )
01141         {//hack
01142                 if ( ucmd.forwardmove || ucmd.rightmove || ucmd.upmove )
01143                 {//moving
01144         
01145                         if( (NPC->client->ps.torsoTimer <= 0) || (NPC->client->ps.torsoAnim == BOTH_STAND4) )                   
01146                         {
01147                                 if ( (ucmd.buttons&BUTTON_WALKING) && !(NPCInfo->scriptFlags&SCF_RUNNING) )
01148                                 {//not running, only set upper anim
01149                                         //  No longer overrides scripted anims
01150                                         NPC_SetAnim( NPC, SETANIM_TORSO, BOTH_STAND4, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
01151                                         NPC->client->ps.torsoTimer = 200;
01152                                 }
01153                         }
01154                 }
01155                 else
01156                 {//standing still, set both torso and legs anim
01157                         //  No longer overrides scripted anims
01158                         if( ( NPC->client->ps.torsoTimer <= 0 || (NPC->client->ps.torsoAnim == BOTH_STAND4) ) &&
01159                                 ( NPC->client->ps.legsTimer <= 0  || (NPC->client->ps.legsAnim == BOTH_STAND4) ) )
01160                         {
01161                                 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_STAND4, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
01162                                 NPC->client->ps.torsoTimer = NPC->client->ps.legsTimer = 200;
01163                         }
01164                 }
01165                 //FIXME: this is a disgusting hack that is supposed to make the Imperials start with their weapon holstered- need a better way
01166                 if ( NPC->client->ps.weapon != WP_NONE )
01167                 {
01168                         ChangeWeapon( NPC, WP_NONE );
01169                         NPC->client->ps.weapon = WP_NONE;
01170                         NPC->client->ps.weaponstate = WEAPON_READY;
01171                         /*
01172                         if ( NPC->weaponModel[0] > 0 )
01173                         {
01174                                 gi.G2API_RemoveGhoul2Model( NPC->ghoul2, NPC->weaponModel[0] );
01175                                 NPC->weaponModel[0] = -1;
01176                         }
01177                         */
01178                         //rwwFIXMEFIXME: Do this?
01179                 }
01180         }
01181 }

qboolean NPC_CheckEnemyStealth void   ) 
 

Referenced by NPC_CheckPlayerTeamStealth().

void NPC_ClearLookTarget gentity_t self  ) 
 

Definition at line 1611 of file NPC_utils.c.

01612 {
01613         if ( !self->client )
01614         {
01615                 return;
01616         }
01617 
01618         if ( (self->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
01619         {//lookTarget is set by and to the monster that's holding you, no other operations can change that
01620                 return;
01621         }
01622 
01623         self->client->renderInfo.lookTarget = ENTITYNUM_NONE;//ENTITYNUM_WORLD;
01624         self->client->renderInfo.lookTargetClearTime = 0;
01625 }

void NPC_Jedi_Pain gentity_t self,
gentity_t attacker,
int  damage
 

Definition at line 5358 of file NPC_AI_Jedi.c.

References entityShared_t::absmin, gNPCstats_e::aggression, AngleVectors(), BOTH_CEILING_CLING, BOTH_CEILING_DROP, CLASS_DESANN, gentity_s::client, Com_Printf(), d_JediAI, DotProduct, gNPC_t::enemyCheckDebounceTime, EV_PUSHED1, EV_PUSHED3, renderInfo_s::eyePoint, playerState_s::fd, FORCE_LEVEL_1, FORCE_LEVEL_3, forcedata_s::forcePowerDebounce, FP_GRIP, FP_SABER_DEFENSE, G_AddVoiceEvent(), g_spskill, gentity_t, gPainPoint, gentity_s::health, vmCvar_t::integer, Jedi_WaitingAmbush(), playerState_s::legsAnim, level, gclient_s::noclip, gentity_s::NPC, gclient_s::NPC_class, NPC_Pain(), NPC_SetAnim(), gentity_s::NPC_type, NULL, gclient_s::ps, Q_irand(), Q_stricmp(), qfalse, gentity_s::r, gNPC_t::rank, RANK_LT_JG, gclient_s::renderInfo, gentity_s::s, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, SETANIM_LEGS, SETANIM_TORSO, gNPC_t::stats, level_locals_t::time, TIMER_Set(), playerState_s::torsoAnim, vec3_t, VectorCopy, VectorSubtract, playerState_s::viewangles, entityState_s::weapon, WP_ForcePowerStop(), and WP_SABER.

Referenced by NPC_PainFunc().

05359 {
05360         gentity_t *other = attacker;
05361         vec3_t point;
05362 
05363         VectorCopy(gPainPoint, point);
05364 
05365         //FIXME: base the actual aggression add/subtract on health?
05366         //FIXME: don't do this more than once per frame?
05367         //FIXME: when take pain, stop force gripping....?
05368         if ( other->s.weapon == WP_SABER )
05369         {//back off
05370                 TIMER_Set( self, "parryTime", -1 );
05371                 if ( self->client->NPC_class == CLASS_DESANN || !Q_stricmp("Yoda",self->NPC_type) )
05372                 {//less for Desann
05373                         self->client->ps.fd.forcePowerDebounce[FP_SABER_DEFENSE] = level.time + (3-g_spskill.integer)*50;
05374                 }
05375                 else if ( self->NPC->rank >= RANK_LT_JG )
05376                 {
05377                         self->client->ps.fd.forcePowerDebounce[FP_SABER_DEFENSE] = level.time + (3-g_spskill.integer)*100;//300
05378                 }
05379                 else
05380                 {
05381                         self->client->ps.fd.forcePowerDebounce[FP_SABER_DEFENSE] = level.time + (3-g_spskill.integer)*200;//500
05382                 }
05383                 if ( !Q_irand( 0, 3 ) )
05384                 {//ouch... maybe switch up which saber power level we're using
05385                         Jedi_AdjustSaberAnimLevel( self, Q_irand( FORCE_LEVEL_1, FORCE_LEVEL_3 ) );
05386                 }
05387                 if ( !Q_irand( 0, 1 ) )//damage > 20 || self->health < 40 || 
05388                 {
05389                         //Com_Printf( "(%d) drop agg - hit by saber\n", level.time );
05390                         Jedi_Aggression( self, -1 );
05391                 }
05392                 if ( d_JediAI.integer )
05393                 {
05394                         Com_Printf( "(%d) PAIN: agg %d, no parry until %d\n", level.time, self->NPC->stats.aggression, level.time+500 );
05395                 }
05396                 //for testing only
05397                 // Figure out what quadrant the hit was in.
05398                 if ( d_JediAI.integer )
05399                 {
05400                         vec3_t  diff, fwdangles, right;
05401                         float rightdot, zdiff;
05402 
05403                         VectorSubtract( point, self->client->renderInfo.eyePoint, diff );
05404                         diff[2] = 0;
05405                         fwdangles[1] = self->client->ps.viewangles[1];
05406                         AngleVectors( fwdangles, NULL, right, NULL );
05407                         rightdot = DotProduct(right, diff);
05408                         zdiff = point[2] - self->client->renderInfo.eyePoint[2];
05409                 
05410                         Com_Printf( "(%d) saber hit at height %4.2f, zdiff: %4.2f, rightdot: %4.2f\n", level.time, point[2]-self->r.absmin[2],zdiff,rightdot);
05411                 }
05412         }
05413         else
05414         {//attack
05415                 //Com_Printf( "(%d) raise agg - hit by ranged\n", level.time );
05416                 Jedi_Aggression( self, 1 );
05417         }
05418 
05419         self->NPC->enemyCheckDebounceTime = 0;
05420 
05421         WP_ForcePowerStop( self, FP_GRIP );
05422 
05423         //NPC_Pain( self, inflictor, other, point, damage, mod );
05424         NPC_Pain(self, attacker, damage);
05425 
05426         if ( !damage && self->health > 0 )
05427         {//FIXME: better way to know I was pushed
05428                 G_AddVoiceEvent( self, Q_irand(EV_PUSHED1, EV_PUSHED3), 2000 );
05429         }
05430 
05431         //drop me from the ceiling if I'm on it
05432         if ( Jedi_WaitingAmbush( self ) )
05433         {
05434                 self->client->noclip = qfalse;
05435         }
05436         if ( self->client->ps.legsAnim == BOTH_CEILING_CLING )
05437         {
05438                 NPC_SetAnim( self, SETANIM_LEGS, BOTH_CEILING_DROP, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
05439         }
05440         if ( self->client->ps.torsoAnim == BOTH_CEILING_CLING )
05441         {
05442                 NPC_SetAnim( self, SETANIM_TORSO, BOTH_CEILING_DROP, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
05443         }
05444 }

void NPC_Jedi_PlayConfusionSound gentity_t self  ) 
 

Definition at line 163 of file NPC_AI_Jedi.c.

References CLASS_DESANN, CLASS_TAVION, gentity_s::client, EV_CONFUSE1, EV_CONFUSE3, EV_GLOAT1, EV_GLOAT3, EV_TAUNT1, EV_TAUNT3, G_AddVoiceEvent(), gentity_t, gentity_s::health, gclient_s::NPC_class, and Q_irand().

Referenced by ForceTelepathyCheckDirectNPCTarget().

00164 {
00165         if ( self->health > 0 )
00166         {
00167                 if ( self->client && ( self->client->NPC_class == CLASS_TAVION || self->client->NPC_class == CLASS_DESANN ) )
00168                 {
00169                         G_AddVoiceEvent( self, Q_irand( EV_CONFUSE1, EV_CONFUSE3 ), 2000 );
00170                 }
00171                 else if ( Q_irand( 0, 1 ) )
00172                 {
00173                         G_AddVoiceEvent( self, Q_irand( EV_TAUNT1, EV_TAUNT3 ), 2000 );
00174                 }
00175                 else
00176                 {
00177                         G_AddVoiceEvent( self, Q_irand( EV_GLOAT1, EV_GLOAT3 ), 2000 );
00178                 }
00179         }
00180 }

void NPC_Jedi_RateNewEnemy gentity_t self,
gentity_t enemy
 

Definition at line 914 of file NPC_AI_Jedi.c.

References gNPCstats_e::aggression, ceil(), entityShared_t::currentOrigin, gentity_t, gentity_s::health, gentity_s::NPC, Q_irand(), gentity_s::r, gentity_s::s, gNPC_t::stats, TIMER_Set(), entityState_s::weapon, WP_BLASTER, and WP_SABER.

Referenced by G_SetEnemy().

00915 {
00916         float healthAggression;
00917         float weaponAggression;
00918         int newAggression;
00919 
00920         switch( enemy->s.weapon )
00921         {
00922         case WP_SABER:
00923                 healthAggression = (float)self->health/200.0f*6.0f;
00924                 weaponAggression = 7;//go after him
00925                 break;
00926         case WP_BLASTER:
00927                 if ( DistanceSquared( self->r.currentOrigin, enemy->r.currentOrigin ) < 65536 )//256 squared
00928                 {
00929                         healthAggression = (float)self->health/200.0f*8.0f;
00930                         weaponAggression = 8;//go after him
00931                 }
00932                 else
00933                 {
00934                         healthAggression = 8.0f - ((float)self->health/200.0f*8.0f);
00935                         weaponAggression = 2;//hang back for a second
00936                 }
00937                 break;
00938         default:
00939                 healthAggression = (float)self->health/200.0f*8.0f;
00940                 weaponAggression = 6;//approach
00941                 break;
00942         }
00943         //Average these with current aggression
00944         newAggression = ceil( (healthAggression + weaponAggression + (float)self->NPC->stats.aggression )/3.0f);
00945         //Com_Printf( "(%d) new agg %d - new enemy\n", level.time, newAggression );
00946         Jedi_Aggression( self, newAggression - self->NPC->stats.aggression );
00947 
00948         //don't taunt right away
00949         TIMER_Set( self, "chatter", Q_irand( 4000, 7000 ) );
00950 }

qboolean NPC_MoveDirClear int  forwardmove,
int  rightmove,
qboolean  reset
 

Definition at line 1079 of file NPC_AI_Jedi.c.

References trace_t::allsolid, AngleVectors(), gentity_s::client, gentity_s::clipmask, CONTENTS_BOTCLIP, entityShared_t::currentOrigin, trace_t::endpos, gentity_s::enemy, trace_t::entityNum, ENTITYNUM_NONE, playerState_s::fd, forcedata_s::forceJumpCharge, usercmd_s::forwardmove, trace_t::fraction, gNPC_t::goalEntity, playerState_s::groundEntityNum, entityShared_t::maxs, entityShared_t::mins, playerState_s::moveDir, NPC, NPCInfo, NULL, entityState_s::number, PITCH, gclient_s::ps, qboolean, qfalse, qtrue, gentity_s::r, usercmd_s::rightmove, ROLL, gentity_s::s, trace_t::startsolid, STEPSIZE, trap_Trace(), ucmd, usercmd_s::upmove, vec3_t, VectorClear, VectorCopy, VectorMA, VectorScale, playerState_s::viewangles, and YAW.

Referenced by NPC_BSFollowLeader().

01080 {
01081         vec3_t  forward, right, testPos, angles, mins;
01082         trace_t trace;
01083         float   fwdDist, rtDist;
01084         float   bottom_max = -STEPSIZE*4 - 1;
01085 
01086         if ( !forwardmove && !rightmove )
01087         {//not even moving
01088                 //Com_Printf( "%d skipping walk-cliff check (not moving)\n", level.time );
01089                 return qtrue;
01090         }
01091 
01092         if ( ucmd.upmove > 0 || NPC->client->ps.fd.forceJumpCharge )
01093         {//Going to jump
01094                 //Com_Printf( "%d skipping walk-cliff check (going to jump)\n", level.time );
01095                 return qtrue;
01096         }
01097 
01098         if ( NPC->client->ps.groundEntityNum == ENTITYNUM_NONE )
01099         {//in the air
01100                 //Com_Printf( "%d skipping walk-cliff check (in air)\n", level.time );
01101                 return qtrue;
01102         }
01103         /*
01104         if ( fabs( AngleDelta( NPC->r.currentAngles[YAW], NPCInfo->desiredYaw ) ) < 5.0 )//!ucmd.angles[YAW] )
01105         {//Not turning much, don't do this
01106                 //NOTE: Should this not happen only if you're not turning AT ALL?
01107                 //      You could be turning slowly but moving fast, so that would
01108                 //      still let you walk right off a cliff...
01109                 //NOTE: Or maybe it is a good idea to ALWAYS do this, regardless
01110                 //      of whether ot not we're turning?  But why would we be walking
01111                 //  straight into a wall or off a cliff unless we really wanted to?
01112                 return;
01113         }
01114         */
01115 
01116         //FIXME: to really do this right, we'd have to actually do a pmove to predict where we're
01117         //going to be... maybe this should be a flag and pmove handles it and sets a flag so AI knows
01118         //NEXT frame?  Or just incorporate current velocity, runspeed and possibly friction?
01119         VectorCopy( NPC->r.mins, mins );
01120         mins[2] += STEPSIZE;
01121         angles[PITCH] = angles[ROLL] = 0;
01122         angles[YAW] = NPC->client->ps.viewangles[YAW];//Add ucmd.angles[YAW]?
01123         AngleVectors( angles, forward, right, NULL );
01124         fwdDist = ((float)forwardmove)/2.0f;
01125         rtDist = ((float)rightmove)/2.0f;
01126         VectorMA( NPC->r.currentOrigin, fwdDist, forward, testPos );
01127         VectorMA( testPos, rtDist, right, testPos );
01128         trap_Trace( &trace, NPC->r.currentOrigin, mins, NPC->r.maxs, testPos, NPC->s.number, NPC->clipmask|CONTENTS_BOTCLIP );
01129         if ( trace.allsolid || trace.startsolid )
01130         {//hmm, trace started inside this brush... how do we decide if we should continue?
01131                 //FIXME: what do we do if we start INSIDE a CONTENTS_BOTCLIP? Try the trace again without that in the clipmask?
01132                 if ( reset )
01133                 {
01134                         trace.fraction = 1.0f;
01135                 }
01136                 VectorCopy( testPos, trace.endpos );
01137                 //return qtrue;
01138         }
01139         if ( trace.fraction < 0.6 )
01140         {//Going to bump into something very close, don't move, just turn
01141                 if ( (NPC->enemy && trace.entityNum == NPC->enemy->s.number) || (NPCInfo->goalEntity && trace.entityNum == NPCInfo->goalEntity->s.number) )
01142                 {//okay to bump into enemy or goal
01143                         //Com_Printf( "%d bump into enemy/goal okay\n", level.time );
01144                         return qtrue;
01145                 }
01146                 else if ( reset )
01147                 {//actually want to screw with the ucmd
01148                         //Com_Printf( "%d avoiding walk into wall (entnum %d)\n", level.time, trace.entityNum );
01149                         ucmd.forwardmove = 0;
01150                         ucmd.rightmove = 0;
01151                         VectorClear( NPC->client->ps.moveDir );
01152                 }
01153                 return qfalse;
01154         }
01155 
01156         if ( NPCInfo->goalEntity )
01157         {
01158                 if ( NPCInfo->goalEntity->r.currentOrigin[2] < NPC->r.currentOrigin[2] )
01159                 {//goal is below me, okay to step off at least that far plus stepheight
01160                         bottom_max += NPCInfo->goalEntity->r.currentOrigin[2] - NPC->r.currentOrigin[2];
01161                 }
01162         }
01163         VectorCopy( trace.endpos, testPos );
01164         testPos[2] += bottom_max;
01165 
01166         trap_Trace( &trace, trace.endpos, mins, NPC->r.maxs, testPos, NPC->s.number, NPC->clipmask );
01167 
01168         //FIXME:Should we try to see if we can still get to our goal using the waypoint network from this trace.endpos?
01169         //OR: just put NPC clip brushes on these edges (still fall through when die)
01170 
01171         if ( trace.allsolid || trace.startsolid )
01172         {//Not going off a cliff
01173                 //Com_Printf( "%d walk off cliff okay (droptrace in solid)\n", level.time );
01174                 return qtrue;
01175         }
01176 
01177         if ( trace.fraction < 1.0 )
01178         {//Not going off a cliff
01179                 //FIXME: what if plane.normal is sloped?  We'll slide off, not land... plus this doesn't account for slide-movement... 
01180                 //Com_Printf( "%d walk off cliff okay will hit entnum %d at dropdist of %4.2f\n", level.time, trace.entityNum, (trace.fraction*bottom_max) );
01181                 return qtrue;
01182         }
01183 
01184         //going to fall at least bottom_max, don't move, just turn... is this bad, though?  What if we want them to drop off?
01185         if ( reset )
01186         {//actually want to screw with the ucmd
01187                 //Com_Printf( "%d avoiding walk off cliff\n", level.time );
01188                 ucmd.forwardmove *= -1.0;//= 0;
01189                 ucmd.rightmove *= -1.0;//= 0;
01190                 VectorScale( NPC->client->ps.moveDir, -1, NPC->client->ps.moveDir );
01191         }
01192         return qfalse;
01193 }

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_ShadowTrooper_Precache void   ) 
 

Definition at line 103 of file NPC_AI_Jedi.c.

References AMMO_FORCE, BG_FindItemForAmmo(), G_SoundIndex(), and RegisterItem().

Referenced by NPC_SpawnType(), and SP_NPC_ShadowTrooper().

00104 {
00105         RegisterItem( BG_FindItemForAmmo( AMMO_FORCE ) );
00106         G_SoundIndex( "sound/chars/shadowtrooper/cloak.wav" );
00107         G_SoundIndex( "sound/chars/shadowtrooper/decloak.wav" );
00108 }

qboolean NPC_SomeoneLookingAtMe gentity_t ent  ) 
 

Definition at line 1042 of file NPC_utils.c.

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.

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 }

qboolean PM_InKnockDown playerState_t ps  ) 
 

Definition at line 1216 of file bg_panimate.c.

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.

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_SaberInBounce int  move  ) 
 

Definition at line 700 of file bg_saber.c.

00701 {
00702         if ( move >= LS_B1_BR && move <= LS_B1_BL )
00703         {
00704                 return qtrue;
00705         }
00706         if ( move >= LS_D1_BR && move <= LS_D1_BL )
00707         {
00708                 return qtrue;
00709         }
00710         return qfalse;
00711 }

qboolean PM_SaberInBrokenParry int  move  ) 
 

Definition at line 1580 of file bg_saber.c.

01581 {
01582         if ( move >= LS_V1_BR && move <= LS_V1_B_ )
01583         {
01584                 return qtrue;
01585         }
01586         if ( move >= LS_H1_T_ && move <= LS_H1_BL )
01587         {
01588                 return qtrue;
01589         }
01590         return qfalse;
01591 }

qboolean PM_SaberInDeflect int  move  ) 
 

Definition at line 1148 of file bg_panimate.c.

01149 {
01150         if ( move >= LS_D1_BR && move <= LS_D1_B_ )
01151         {
01152                 return qtrue;
01153         }
01154         return qfalse;
01155 }

qboolean PM_SaberInKnockaway int  move  ) 
 

Definition at line 1166 of file bg_panimate.c.

References LS_K1_BL, LS_K1_T_, qboolean, qfalse, and qtrue.

Referenced by PM_SetSaberMove().

01167 {
01168         if ( move >= LS_K1_T_ && move <= LS_K1_BL )
01169         {
01170                 return qtrue;
01171         }
01172         return qfalse;
01173 }

qboolean PM_SaberInParry int  move  ) 
 

Definition at line 1157 of file bg_panimate.c.

References LS_PARRY_LL, LS_PARRY_UP, qboolean, qfalse, and qtrue.

Referenced by PM_SetSaberMove().

01158 {
01159         if ( move >= LS_PARRY_UP && move <= LS_PARRY_LL )
01160         {
01161                 return qtrue;
01162         }
01163         return qfalse;
01164 }

qboolean PM_SaberInStart int  move  ) 
 

Definition at line 1184 of file bg_panimate.c.

References LS_S_T2B, LS_S_TL2BR, qboolean, qfalse, and qtrue.

Referenced by BG_SaberInTransitionAny(), ClientThink_real(), Jedi_CheckFlipEvasions(), Jedi_SaberBlockGo(), and PM_SaberMoveOkayForKata().

01185 {
01186         if ( move >= LS_S_TL2BR && move <= LS_S_T2B )
01187         {
01188                 return qtrue;
01189         }
01190         return qfalse;
01191 }

float ShortestLineSegBewteen2LineSegs vec3_t  start1,
vec3_t  end1,
vec3_t  start2,
vec3_t  end2,
vec3_t  close_pnt1,
vec3_t  close_pnt2
 

Definition at line 2131 of file g_utils.c.

References DotProduct, fabs(), G_FindClosestPointOnLineSegment(), Q3_INFINITE, qboolean, qfalse, qtrue, vec3_t, VectorCopy, VectorMA, and VectorSubtract.

02132 {
02133         float   current_dist, new_dist;
02134         vec3_t  new_pnt;
02135         //start1, end1 : the first segment
02136         //start2, end2 : the second segment
02137 
02138         //output, one point on each segment, the closest two points on the segments.
02139 
02140         //compute some temporaries:
02141         //vec start_dif = start2 - start1
02142         vec3_t  start_dif;
02143         vec3_t  v1;
02144         vec3_t  v2;
02145         float v1v1, v2v2, v1v2;
02146         float denom;
02147 
02148         VectorSubtract( start2, start1, start_dif );
02149         //vec v1 = end1 - start1
02150         VectorSubtract( end1, start1, v1 );
02151         //vec v2 = end2 - start2
02152         VectorSubtract( end2, start2, v2 );
02153         //
02154         v1v1 = DotProduct( v1, v1 );
02155         v2v2 = DotProduct( v2, v2 );
02156         v1v2 = DotProduct( v1, v2 );
02157 
02158         //the main computation
02159 
02160         denom = (v1v2 * v1v2) - (v1v1 * v2v2);
02161 
02162         //if denom is small, then skip all this and jump to the section marked below
02163         if ( fabs(denom) > 0.001f )
02164         {
02165                 float s = -( (v2v2*DotProduct( v1, start_dif )) - (v1v2*DotProduct( v2, start_dif )) ) / denom;
02166                 float t = ( (v1v1*DotProduct( v2, start_dif )) - (v1v2*DotProduct( v1, start_dif )) ) / denom;
02167                 qboolean done = qtrue;
02168 
02169                 if ( s < 0 )
02170                 {
02171                         done = qfalse;
02172                         s = 0;// and see note below
02173                 }
02174 
02175                 if ( s > 1 ) 
02176                 {
02177                         done = qfalse;
02178                         s = 1;// and see note below
02179                 }
02180 
02181                 if ( t < 0 ) 
02182                 {
02183                         done = qfalse;
02184                         t = 0;// and see note below
02185                 }
02186 
02187                 if ( t > 1 ) 
02188                 {
02189                         done = qfalse;
02190                         t = 1;// and see note below
02191                 }
02192 
02193                 //vec close_pnt1 = start1 + s * v1
02194                 VectorMA( start1, s, v1, close_pnt1 );
02195                 //vec close_pnt2 = start2 + t * v2
02196                 VectorMA( start2, t, v2, close_pnt2 );
02197 
02198                 current_dist = Distance( close_pnt1, close_pnt2 );
02199                 //now, if none of those if's fired, you are done. 
02200                 if ( done )
02201                 {
02202                         return current_dist;
02203                 }
02204                 //If they did fire, then we need to do some additional tests.
02205 
02206                 //What we are gonna do is see if we can find a shorter distance than the above
02207                 //involving the endpoints.
02208         }
02209         else
02210         {
02211                 //******start here for paralell lines with current_dist = infinity****
02212                 current_dist = Q3_INFINITE;
02213         }
02214 
02215         //test 2 close_pnts first
02216         /*
02217         G_FindClosestPointOnLineSegment( start1, end1, close_pnt2, new_pnt );
02218         new_dist = Distance( close_pnt2, new_pnt );
02219         if ( new_dist < current_dist )
02220         {//then update close_pnt1 close_pnt2 and current_dist
02221                 VectorCopy( new_pnt, close_pnt1 );
02222                 VectorCopy( close_pnt2, close_pnt2 );
02223                 current_dist = new_dist;
02224         }
02225 
02226         G_FindClosestPointOnLineSegment( start2, end2, close_pnt1, new_pnt );
02227         new_dist = Distance( close_pnt1, new_pnt );
02228         if ( new_dist < current_dist )
02229         {//then update close_pnt1 close_pnt2 and current_dist
02230                 VectorCopy( close_pnt1, close_pnt1 );
02231                 VectorCopy( new_pnt, close_pnt2 );
02232                 current_dist = new_dist;
02233         }
02234         */
02235         //test all the endpoints
02236         new_dist = Distance( start1, start2 );
02237         if ( new_dist < current_dist )
02238         {//then update close_pnt1 close_pnt2 and current_dist
02239                 VectorCopy( start1, close_pnt1 );
02240                 VectorCopy( start2, close_pnt2 );
02241                 current_dist = new_dist;
02242         }
02243 
02244         new_dist = Distance( start1, end2 );
02245         if ( new_dist < current_dist )
02246         {//then update close_pnt1 close_pnt2 and current_dist
02247                 VectorCopy( start1, close_pnt1 );
02248                 VectorCopy( end2, close_pnt2 );
02249                 current_dist = new_dist;
02250         }
02251 
02252         new_dist = Distance( end1, start2 );
02253         if ( new_dist < current_dist )
02254         {//then update close_pnt1 close_pnt2 and current_dist
02255                 VectorCopy( end1, close_pnt1 );
02256                 VectorCopy( start2, close_pnt2 );
02257                 current_dist = new_dist;
02258         }
02259 
02260         new_dist = Distance( end1, end2 );
02261         if ( new_dist < current_dist )
02262         {//then update close_pnt1 close_pnt2 and current_dist
02263                 VectorCopy( end1, close_pnt1 );
02264                 VectorCopy( end2, close_pnt2 );
02265                 current_dist = new_dist;
02266         }
02267 
02268         //Then we have 4 more point / segment tests
02269 
02270         G_FindClosestPointOnLineSegment( start2, end2, start1, new_pnt );
02271         new_dist = Distance( start1, new_pnt );
02272         if ( new_dist < current_dist )
02273         {//then update close_pnt1 close_pnt2 and current_dist
02274                 VectorCopy( start1, close_pnt1 );
02275                 VectorCopy( new_pnt, close_pnt2 );
02276                 current_dist = new_dist;
02277         }
02278 
02279         G_FindClosestPointOnLineSegment( start2, end2, end1, new_pnt );
02280         new_dist = Distance( end1, new_pnt );
02281         if ( new_dist < current_dist )
02282         {//then update close_pnt1 close_pnt2 and current_dist
02283                 VectorCopy( end1, close_pnt1 );
02284                 VectorCopy( new_pnt, close_pnt2 );
02285                 current_dist = new_dist;
02286         }
02287 
02288         G_FindClosestPointOnLineSegment( start1, end1, start2, new_pnt );
02289         new_dist = Distance( start2, new_pnt );
02290         if ( new_dist < current_dist )
02291         {//then update close_pnt1 close_pnt2 and current_dist
02292                 VectorCopy( new_pnt, close_pnt1 );
02293                 VectorCopy( start2, close_pnt2 );
02294                 current_dist = new_dist;
02295         }
02296 
02297         G_FindClosestPointOnLineSegment( start1, end1, end2, new_pnt );
02298         new_dist = Distance( end2, new_pnt );
02299         if ( new_dist < current_dist )
02300         {//then update close_pnt1 close_pnt2 and current_dist
02301                 VectorCopy( new_pnt, close_pnt1 );
02302                 VectorCopy( end2, close_pnt2 );
02303                 current_dist = new_dist;
02304         }
02305 
02306         return current_dist;
02307 }

void WP_ActivateSaber gentity_t self  ) 
 

Definition at line 248 of file w_saber.c.

References CHAN_WEAPON, gentity_s::client, playerState_s::fd, forcedata_s::forceGripCripple, playerState_s::forceHandExtend, playerState_s::forceHandExtendTime, G_Sound(), gentity_t, HANDEXTEND_JEDITAUNT, HANDEXTEND_NONE, level, gentity_s::NPC, gclient_s::ps, gclient_s::saber, playerState_s::saberHolstered, saberInfo_t::soundOn, and level_locals_t::time.

Referenced by Jedi_Ambush(), and WP_SaberStartMissileBlockCheck().

00249 {
00250         if ( !self || !self->client )
00251         {
00252                 return;
00253         }
00254 
00255         if (self->NPC &&
00256                 self->client->ps.forceHandExtend == HANDEXTEND_JEDITAUNT &&
00257                 (self->client->ps.forceHandExtendTime - level.time) > 200)
00258         { //if we're an NPC and in the middle of a taunt then stop it
00259                 self->client->ps.forceHandExtend = HANDEXTEND_NONE;
00260                 self->client->ps.forceHandExtendTime = 0;
00261         }
00262         else if (self->client->ps.fd.forceGripCripple)
00263         { //can't activate saber while being gripped
00264                 return;
00265         }
00266 
00267         if ( self->client->ps.saberHolstered )
00268         {
00269                 self->client->ps.saberHolstered = 0;
00270                 if (self->client->saber[0].soundOn)
00271                 {
00272                         G_Sound(self, CHAN_WEAPON, self->client->saber[0].soundOn);
00273                 }
00274 
00275                 if (self->client->saber[1].soundOn)
00276                 {
00277                         G_Sound(self, CHAN_WEAPON, self->client->saber[1].soundOn);
00278                 }
00279         }
00280 }

void WP_DeactivateSaber gentity_t self,
qboolean  clearLength
 

Definition at line 217 of file w_saber.c.

References CHAN_WEAPON, gentity_s::client, G_Sound(), gentity_t, saberInfo_t::model, gclient_s::ps, gclient_s::saber, playerState_s::saberHolstered, and saberInfo_t::soundOff.

00218 {
00219         if ( !self || !self->client )
00220         {
00221                 return;
00222         }
00223         //keep my saber off!
00224         if ( !self->client->ps.saberHolstered )
00225         {
00226                 self->client->ps.saberHolstered = 2;
00227                 /*
00228                 if ( clearLength )
00229                 {
00230                         self->client->ps.SetSaberLength( 0 );
00231                 }
00232                 */
00233                 //Doens't matter ATM
00234                 if (self->client->saber[0].soundOff)
00235                 {
00236                         G_Sound(self, CHAN_WEAPON, self->client->saber[0].soundOff);
00237                 }
00238 
00239                 if (self->client->saber[1].soundOff &&
00240                         self->client->saber[1].model[0])
00241                 {
00242                         G_Sound(self, CHAN_WEAPON, self->client->saber[1].soundOff);
00243                 }
00244 
00245         }
00246 }

qboolean WP_ForcePowerAvailable gentity_t self,
forcePowers_t  forcePower,
int  overrideAmt
 

Definition at line 774 of file w_force.c.

References gentity_s::client, playerState_s::fd, forcedata_s::forcePower, forcedata_s::forcePowerLevel, forcePowerNeeded, forcePowers_t, forcedata_s::forcePowersActive, FP_DRAIN, FP_LEVITATION, FP_LIGHTNING, gentity_t, gclient_s::ps, qboolean, qfalse, and qtrue.

Referenced by WP_DoSpecificPower(), WP_ForcePowerStart(), and WP_ForcePowerUsable().

00775 {
00776         int     drain = overrideAmt ? overrideAmt :
00777                                 forcePowerNeeded[self->client->ps.fd.forcePowerLevel[forcePower]][forcePower];
00778 
00779         if (self->client->ps.fd.forcePowersActive & (1 << forcePower))
00780         { //we're probably going to deactivate it..
00781                 return qtrue;
00782         }
00783         if ( forcePower == FP_LEVITATION )
00784         {
00785                 return qtrue;
00786         }
00787         if ( !drain )
00788         {
00789                 return qtrue;
00790         }
00791         if ((forcePower == FP_DRAIN || forcePower == FP_LIGHTNING) &&
00792                 self->client->ps.fd.forcePower >= 25)
00793         { //it's ok then, drain/lightning are actually duration
00794                 return qtrue;
00795         }
00796         if ( self->client->ps.fd.forcePower < drain )
00797         {
00798                 return qfalse;
00799         }
00800         return qtrue;
00801 }

void WP_ForcePowerStop gentity_t self,
forcePowers_t  forcePower
 

Definition at line 3819 of file w_force.c.

References playerState_s::activeForcePass, CHAN_AUTO, CHAN_VOICE, gentity_s::client, ENTITYNUM_NONE, playerState_s::fd, FORCE_LEVEL_1, FORCE_LEVEL_2, forcedata_s::forceGripEntityNum, forcedata_s::forceGripUseTime, playerState_s::forceHandExtend, playerState_s::forceHandExtendTime, forcedata_s::forceHealAmount, forcedata_s::forceHealTime, forcedata_s::forceMindtrickTargetIndex, forcedata_s::forceMindtrickTargetIndex2, forcedata_s::forceMindtrickTargetIndex3, forcedata_s::forceMindtrickTargetIndex4, forcedata_s::forcePowerDebounce, forcedata_s::forcePowerLevel, forcePowers_t, forcedata_s::forcePowersActive, forcedata_s::forceRageRecoveryTime, FP_ABSORB, FP_DRAIN, FP_GRIP, FP_HEAL, FP_LEVITATION, FP_LIGHTNING, FP_PROTECT, FP_PULL, FP_PUSH, FP_RAGE, FP_SEE, FP_SPEED, FP_TELEPATHY, g_entities, G_EntitySound(), G_MuteSound(), G_Sound(), G_SoundIndex(), gentity_t, HANDEXTEND_FORCE_HOLD, forcedata_s::killSoundEntIndex, level, PM_NORMAL, playerState_s::powerups, gclient_s::ps, PW_DISINT_4, level_locals_t::time, TRACK_CHANNEL_2, TRACK_CHANNEL_3, and TRACK_CHANNEL_5.

Referenced by ClientBegin(), ClientDisconnect(), DoGripAction(), ForceAbsorb(), ForceProtect(), ForceRage(), ForceSeeing(), ForceSpeed(), ForceTelepathy(), ForceThrow(), HolocronUpdate(), Jedi_SaberBlockGo(), JediMasterUpdate(), NPC_Jedi_Pain(), WP_ForcePowersUpdate(), and WP_SpawnInitForcePowers().

03820 {
03821         int wasActive = self->client->ps.fd.forcePowersActive;
03822 
03823         self->client->ps.fd.forcePowersActive &= ~( 1 << forcePower );
03824 
03825         switch( (int)forcePower )
03826         {
03827         case FP_HEAL:
03828                 self->client->ps.fd.forceHealAmount = 0;
03829                 self->client->ps.fd.forceHealTime = 0;
03830                 break;
03831         case FP_LEVITATION:
03832                 break;
03833         case FP_SPEED:
03834                 if (wasActive & (1 << FP_SPEED))
03835                 {
03836                         G_MuteSound(self->client->ps.fd.killSoundEntIndex[TRACK_CHANNEL_2-50], CHAN_VOICE);
03837                 }
03838                 break;
03839         case FP_PUSH:
03840                 break;
03841         case FP_PULL:
03842                 break;
03843         case FP_TELEPATHY:
03844                 if (wasActive & (1 << FP_TELEPATHY))
03845                 {
03846                         G_Sound( self, CHAN_AUTO, G_SoundIndex("sound/weapons/force/distractstop.wav") );
03847                 }
03848                 self->client->ps.fd.forceMindtrickTargetIndex = 0;
03849                 self->client->ps.fd.forceMindtrickTargetIndex2 = 0;
03850                 self->client->ps.fd.forceMindtrickTargetIndex3 = 0;
03851                 self->client->ps.fd.forceMindtrickTargetIndex4 = 0;
03852                 break;
03853         case FP_SEE:
03854                 if (wasActive & (1 << FP_SEE))
03855                 {
03856                         G_MuteSound(self->client->ps.fd.killSoundEntIndex[TRACK_CHANNEL_5-50], CHAN_VOICE);
03857                 }
03858                 break;
03859         case FP_GRIP:
03860                 self->client->ps.fd.forceGripUseTime = level.time + 3000;
03861                 if (self->client->ps.fd.forcePowerLevel[FP_GRIP] > FORCE_LEVEL_1 &&
03862                         g_entities[self->client->ps.fd.forceGripEntityNum].client &&
03863                         g_entities[self->client->ps.fd.forceGripEntityNum].health > 0 &&
03864                         g_entities[self->client->ps.fd.forceGripEntityNum].inuse &&
03865                         (level.time - g_entities[self->client->ps.fd.forceGripEntityNum].client->ps.fd.forceGripStarted) > 500)
03866                 { //if we had our throat crushed in for more than half a second, gasp for air when we're let go
03867                         if (wasActive & (1 << FP_GRIP))
03868                         {
03869                                 G_EntitySound( &g_entities[self->client->ps.fd.forceGripEntityNum], CHAN_VOICE, G_SoundIndex("*gasp.wav") );
03870                         }
03871                 }
03872 
03873                 if (g_entities[self->client->ps.fd.forceGripEntityNum].client &&
03874                         g_entities[self->client->ps.fd.forceGripEntityNum].inuse)
03875                 {
03876                         
03877                         g_entities[self->client->ps.fd.forceGripEntityNum].client->ps.forceGripChangeMovetype = PM_NORMAL;
03878                 }
03879 
03880                 if (self->client->ps.forceHandExtend == HANDEXTEND_FORCE_HOLD)
03881                 {
03882                         self->client->ps.forceHandExtendTime = 0;
03883                 }
03884 
03885                 self->client->ps.fd.forceGripEntityNum = ENTITYNUM_NONE;
03886 
03887                 self->client->ps.powerups[PW_DISINT_4] = 0;
03888                 break;
03889         case FP_LIGHTNING:
03890                 if ( self->client->ps.fd.forcePowerLevel[FP_LIGHTNING] < FORCE_LEVEL_2 )
03891                 {//don't do it again for 3 seconds, minimum... FIXME: this should be automatic once regeneration is slower (normal)
03892                         self->client->ps.fd.forcePowerDebounce[FP_LIGHTNING] = level.time + 3000;
03893                 }
03894                 else
03895                 {
03896                         self->client->ps.fd.forcePowerDebounce[FP_LIGHTNING] = level.time + 1500;
03897                 }
03898                 if (self->client->ps.forceHandExtend == HANDEXTEND_FORCE_HOLD)
03899                 {
03900                         self->client->ps.forceHandExtendTime = 0; //reset hand position
03901                 }
03902 
03903                 self->client->ps.activeForcePass = 0;
03904                 break;
03905         case FP_RAGE:
03906                 self->client->ps.fd.forceRageRecoveryTime = level.time + 10000;
03907                 if (wasActive & (1 << FP_RAGE))
03908                 {
03909                         G_MuteSound(self->client->ps.fd.killSoundEntIndex[TRACK_CHANNEL_3-50], CHAN_VOICE);
03910                 }
03911                 break;
03912         case FP_ABSORB:
03913                 if (wasActive & (1 << FP_ABSORB))
03914                 {
03915                         G_MuteSound(self->client->ps.fd.killSoundEntIndex[TRACK_CHANNEL_3-50], CHAN_VOICE);
03916                 }
03917                 break;
03918         case FP_PROTECT:
03919                 if (wasActive & (1 << FP_PROTECT))
03920                 {
03921                         G_MuteSound(self->client->ps.fd.killSoundEntIndex[TRACK_CHANNEL_3-50], CHAN_VOICE);
03922                 }
03923                 break;
03924         case FP_DRAIN:
03925                 if ( self->client->ps.fd.forcePowerLevel[FP_DRAIN] < FORCE_LEVEL_2 )
03926                 {//don't do it again for 3 seconds, minimum...
03927                         self->client->ps.fd.forcePowerDebounce[FP_DRAIN] = level.time + 3000;
03928                 }
03929                 else
03930                 {
03931                         self->client->ps.fd.forcePowerDebounce[FP_DRAIN] = level.time + 1500;
03932                 }
03933 
03934                 if (self->client->ps.forceHandExtend == HANDEXTEND_FORCE_HOLD)
03935                 {
03936                         self->client->ps.forceHandExtendTime = 0; //reset hand position
03937                 }
03938 
03939                 self->client->ps.activeForcePass = 0;
03940         default:
03941                 break;
03942         }
03943 }

qboolean WP_ForcePowerUsable gentity_t self,
forcePowers_t  forcePower,
int  overrideAmt
 

int WP_GetVelocityForForceJump gentity_t self,
vec3_t  jumpVel,
usercmd_t ucmd
 

Definition at line 2377 of file w_force.c.

References AngleVectors(), CHAN_VOICE, gentity_s::client, playerState_s::fd, FJ_BACKWARD, FJ_FORWARD, FJ_LEFT, FJ_RIGHT, FJ_UP, forcedata_s::forceJumpCharge, usercmd_s::forwardmove, G_MuteSound(), G_PreDefSound(), gentity_t, JUMP_VELOCITY, forcedata_s::killSoundEntIndex, NULL, playerState_s::origin, PDSOUND_FORCEJUMP, gclient_s::ps, usercmd_s::rightmove, TRACK_CHANNEL_1, ucmd, usercmd_t, vec3_t, VectorCopy, VectorMA, playerState_s::velocity, and playerState_s::viewangles.

Referenced by ForceJump().

02378 {
02379         float pushFwd = 0, pushRt = 0;
02380         vec3_t  view, forward, right;
02381         VectorCopy( self->client->ps.viewangles, view );
02382         view[0] = 0;
02383         AngleVectors( view, forward, right, NULL );
02384         if ( ucmd->forwardmove && ucmd->rightmove )
02385         {
02386                 if ( ucmd->forwardmove > 0 )
02387                 {
02388                         pushFwd = 50;
02389                 }
02390                 else
02391                 {
02392                         pushFwd = -50;
02393                 }
02394                 if ( ucmd->rightmove > 0 )
02395                 {
02396                         pushRt = 50;
02397                 }
02398                 else
02399                 {
02400                         pushRt = -50;
02401                 }
02402         }
02403         else if ( ucmd->forwardmove || ucmd->rightmove )
02404         {
02405                 if ( ucmd->forwardmove > 0 )
02406                 {
02407                         pushFwd = 100;
02408                 }
02409                 else if ( ucmd->forwardmove < 0 )
02410                 {
02411                         pushFwd = -100;
02412                 }
02413                 else if ( ucmd->rightmove > 0 )
02414                 {
02415                         pushRt = 100;
02416                 }
02417                 else if ( ucmd->rightmove < 0 )
02418                 {
02419                         pushRt = -100;
02420                 }
02421         }
02422 
02423         G_MuteSound(self->client->ps.fd.killSoundEntIndex[TRACK_CHANNEL_1-50], CHAN_VOICE);
02424 
02425         G_PreDefSound(self->client->ps.origin, PDSOUND_FORCEJUMP);
02426 
02427         if (self->client->ps.fd.forceJumpCharge < JUMP_VELOCITY+40)
02428         { //give him at least a tiny boost from just a tap
02429                 self->client->ps.fd.forceJumpCharge = JUMP_VELOCITY+400;
02430         }
02431 
02432         if (self->client->ps.velocity[2] < -30)
02433         { //so that we can get a good boost when force jumping in a fall
02434                 self->client->ps.velocity[2] = -30;
02435         }
02436 
02437         VectorMA( self->client->ps.velocity, pushFwd, forward, jumpVel );
02438         VectorMA( self->client->ps.velocity, pushRt, right, jumpVel );
02439         jumpVel[2] += self->client->ps.fd.forceJumpCharge;
02440         if ( pushFwd > 0 && self->client->ps.fd.forceJumpCharge > 200 )
02441         {
02442                 return FJ_FORWARD;
02443         }
02444         else if ( pushFwd < 0 && self->client->ps.fd.forceJumpCharge > 200 )
02445         {
02446                 return FJ_BACKWARD;
02447         }
02448         else if ( pushRt > 0 && self->client->ps.fd.forceJumpCharge > 200 )
02449         {
02450                 return FJ_RIGHT;
02451         }
02452         else if ( pushRt < 0 && self->client->ps.fd.forceJumpCharge > 200 )
02453         {
02454                 return FJ_LEFT;
02455         }
02456         else
02457         {
02458                 return FJ_UP;
02459         }
02460 }

int WP_MissileBlockForBlock int  saberBlock  ) 
 

Definition at line 9099 of file w_saber.c.

References BLOCKED_LOWER_LEFT, BLOCKED_LOWER_LEFT_PROJ, BLOCKED_LOWER_RIGHT, BLOCKED_LOWER_RIGHT_PROJ, BLOCKED_TOP, BLOCKED_TOP_PROJ, BLOCKED_UPPER_LEFT, BLOCKED_UPPER_LEFT_PROJ, BLOCKED_UPPER_RIGHT, and BLOCKED_UPPER_RIGHT_PROJ.

Referenced by Jedi_SaberBlockGo(), WP_SaberBlock(), and WP_SaberBlockNonRandom().

09100 {
09101         switch( saberBlock )
09102         {
09103         case BLOCKED_UPPER_RIGHT:
09104                 return BLOCKED_UPPER_RIGHT_PROJ;
09105                 break;
09106         case BLOCKED_UPPER_LEFT:
09107                 return BLOCKED_UPPER_LEFT_PROJ;
09108                 break;
09109         case BLOCKED_LOWER_RIGHT:
09110                 return BLOCKED_LOWER_RIGHT_PROJ;
09111                 break;
09112         case BLOCKED_LOWER_LEFT:
09113                 return BLOCKED_LOWER_LEFT_PROJ;
09114                 break;
09115         case BLOCKED_TOP:
09116                 return BLOCKED_TOP_PROJ;
09117                 break;
09118         }
09119         return saberBlock;
09120 }

void WP_ResistForcePush gentity_t self,
gentity_t pusher,
qboolean  noPenalty
 

Definition at line 203 of file NPC_AI_Jedi.c.

References atof(), BG_CrouchAnim(), BG_FlippingAnim(), BG_SpinningSaberAnim(), BOTH_RESISTPUSH, CLASS_DESANN, CLASS_LUKE, gentity_s::client, ENTITYNUM_NONE, playerState_s::fd, floor(), FORCE_LEVEL_3, forcedata_s::forcePowerLevel, forcedata_s::forcePowersActive, FP_PULL, FP_PUSH, FP_SPEED, gentity_t, playerState_s::groundEntityNum, gentity_s::health, Jedi_PlayBlockedPushSound(), playerState_s::legsAnim, level, gclient_s::NPC_class, NPC_SetAnim(), gentity_s::NPC_type, entityState_s::number, playerState_s::pm_flags, PM_InKnockDown(), PM_RollingAnim(), playerState_s::pm_time, PMF_TIME_KNOCKBACK, playerState_s::powerups, gclient_s::ps, PW_DISINT_4, PW_PULL, Q_stricmp(), qboolean, qfalse, qtrue, gentity_s::s, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, SETANIM_TORSO, level_locals_t::time, playerState_s::torsoTimer, trap_Cvar_VariableStringBuffer(), VectorClear, playerState_s::velocity, and playerState_s::weaponTime.

Referenced by Boba_StopKnockdown().

00204 {
00205         int parts;
00206         qboolean runningResist = qfalse;
00207 
00208         if ( !self || self->health <= 0 || !self->client || !pusher || !pusher->client ) 
00209         {
00210                 return;
00211         }
00212         if ( (!self->s.number || self->client->NPC_class == CLASS_DESANN || !Q_stricmp("Yoda",self->NPC_type) || self->client->NPC_class == CLASS_LUKE)
00213                 && (VectorLengthSquared( self->client->ps.velocity ) > 10000 || self->client->ps.fd.forcePowerLevel[FP_PUSH] >= FORCE_LEVEL_3 || self->client->ps.fd.forcePowerLevel[FP_PULL] >= FORCE_LEVEL_3 ) )
00214         {
00215                 runningResist = qtrue;
00216         }
00217         if ( !runningResist
00218                 && self->client->ps.groundEntityNum != ENTITYNUM_NONE 
00219                 && !BG_SpinningSaberAnim( self->client->ps.legsAnim ) 
00220                 && !BG_FlippingAnim( self->client->ps.legsAnim ) 
00221                 && !PM_RollingAnim( self->client->ps.legsAnim ) 
00222                 && !PM_InKnockDown( &self->client->ps ) 
00223                 && !BG_CrouchAnim( self->client->ps.legsAnim ))
00224         {//if on a surface and not in a spin or flip, play full body resist
00225                 parts = SETANIM_BOTH;
00226         }
00227         else
00228         {//play resist just in torso
00229                 parts = SETANIM_TORSO;
00230         }
00231         NPC_SetAnim( self, parts, BOTH_RESISTPUSH, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00232         if ( !noPenalty )
00233         {
00234                 char buf[128];
00235                 float tFVal = 0;
00236 
00237                 trap_Cvar_VariableStringBuffer("timescale", buf, sizeof(buf));
00238 
00239                 tFVal = atof(buf);
00240 
00241                 if ( !runningResist )
00242                 {
00243                         VectorClear( self->client->ps.velocity );
00244                         //still stop them from attacking or moving for a bit, though
00245                         //FIXME: maybe push just a little (like, slide)?
00246                         self->client->ps.weaponTime = 1000;
00247                         if ( self->client->ps.fd.forcePowersActive&(1<<FP_SPEED) )
00248                         {
00249                                 self->client->ps.weaponTime = floor( self->client->ps.weaponTime * tFVal );
00250                         }
00251                         self->client->ps.pm_time = self->client->ps.weaponTime;
00252                         self->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
00253                         //play the full body push effect on me
00254                         //self->forcePushTime = level.time + 600; // let the push effect last for 600 ms
00255                         //rwwFIXMEFIXME: Do this?
00256                 }
00257                 else
00258                 {
00259                         self->client->ps.weaponTime = 600;
00260                         if ( self->client->ps.fd.forcePowersActive&(1<<FP_SPEED) )
00261                         {
00262                                 self->client->ps.weaponTime = floor( self->client->ps.weaponTime * tFVal );
00263                         }
00264                 }
00265         }
00266         //play my force push effect on my hand
00267         self->client->ps.powerups[PW_DISINT_4] = level.time + self->client->ps.torsoTimer + 500;
00268         self->client->ps.powerups[PW_PULL] = 0;
00269         Jedi_PlayBlockedPushSound( self );
00270 }

float WP_SpeedOfMissileForWeapon int  wp,
qboolean  alt_fire
 

Definition at line 174 of file g_weapon.c.

00175 {
00176         return 500;
00177 }

int WPDEBUG_SaberColor saber_colors_t  saberColor  ) 
 

Definition at line 2812 of file w_saber.c.

References SABER_BLUE, saber_colors_t, SABER_GREEN, SABER_ORANGE, SABER_PURPLE, SABER_RED, and SABER_YELLOW.

02813 {
02814         switch( (int)(saberColor) )
02815         {
02816                 case SABER_RED:
02817                         return 0x000000ff;
02818                         break;
02819                 case SABER_ORANGE:
02820                         return 0x000088ff;
02821                         break;
02822                 case SABER_YELLOW:
02823                         return 0x0000ffff;
02824                         break;
02825                 case SABER_GREEN:
02826                         return 0x0000ff00;
02827                         break;
02828                 case SABER_BLUE:
02829                         return 0x00ff0000;
02830                         break;
02831                 case SABER_PURPLE:
02832                         return 0x00ff00ff;
02833                         break;
02834                 default:
02835                         return 0x00ffffff;//white
02836                         break;
02837         }
02838 }


Variable Documentation

int bg_parryDebounce[]
 

Definition at line 91 of file NPC_AI_Jedi.c.

Referenced by Jedi_ReCalcParryTime(), and PM_WeaponLightsaber().

vmCvar_t d_slowmodeath
 

Definition at line 14 of file NPC_AI_Jedi.c.

Referenced by Jedi_SaberBlockGo().

vmCvar_t g_saberRealisticCombat
 

Definition at line 13 of file NPC_AI_Jedi.c.