codemp/game/w_saber.c File Reference

#include "g_local.h"
#include "bg_local.h"
#include "w_saber.h"
#include "ai_main.h"
#include "../ghoul2/G2.h"
#include "../namespace_begin.h"
#include "../namespace_end.h"

Go to the source code of this file.

Data Structures

struct  saberFace_s

Defines

#define SABER_BOX_SIZE   16.0f
#define PROPER_THROWN_VALUE   999
#define LOOK_DEFAULT_SPEED   0.15f
#define LOOK_TALKING_SPEED   0.15f
#define LOCK_IDEAL_DIST_TOP   32.0f
#define LOCK_IDEAL_DIST_CIRCLE   48.0f
#define SABER_HITDAMAGE   35
#define LOCK_IDEAL_DIST_JKA   46.0f
#define SABER_NONATTACK_DAMAGE   1
#define SABER_EXTRAPOLATE_DIST   16.0f
#define MAX_SABER_VICTIMS   16
#define MAX_SABER_SWING_INC   0.33f
#define MIN_SABER_SLICE_DISTANCE   50
#define MIN_SABER_SLICE_RETURN_DISTANCE   30
#define SABER_THROWN_HIT_DAMAGE   30
#define SABER_THROWN_RETURN_HIT_DAMAGE   5
#define THROWN_SABER_COMP
#define MAX_LEAVE_TIME   20000
#define SABER_RETRIEVE_DELAY   3000
#define SABERINVALID   (!saberent || !saberOwner || !other || !saberent->inuse || !saberOwner->inuse || !other->inuse || !saberOwner->client || !other->client || !saberOwner->client->ps.saberEntityNum || saberOwner->client->ps.saberLockTime > (level.time-100))
#define SABER_MAX_THROW_DISTANCE   700
#define STAFF_KICK_RANGE   16

Typedefs

typedef saberFace_s saberFace_t

Enumerations

enum  sabersLockMode_t {
  LOCK_FIRST = 0, LOCK_TOP = LOCK_FIRST, LOCK_DIAG_TR, LOCK_DIAG_TL,
  LOCK_DIAG_BR, LOCK_DIAG_BL, LOCK_R, LOCK_L,
  LOCK_RANDOM
}

Functions

qboolean InFront (vec3_t spot, vec3_t from, vec3_t fromAngles, float threshHold)
void G_TestLine (vec3_t start, vec3_t end, int color, int time)
qboolean PM_SaberInTransition (int move)
qboolean PM_SaberInDeflect (int move)
qboolean PM_SaberInBrokenParry (int move)
qboolean PM_SaberInBounce (int move)
qboolean BG_SaberInReturn (int move)
qboolean BG_InKnockDownOnGround (playerState_t *ps)
qboolean BG_StabDownAnim (int anim)
qboolean BG_SabersOff (playerState_t *ps)
qboolean BG_SaberInTransitionAny (int move)
qboolean BG_SaberInAttackPure (int move)
qboolean WP_SaberBladeUseSecondBladeStyle (saberInfo_t *saber, int bladeNum)
qboolean WP_SaberBladeDoTransitionDamage (saberInfo_t *saber, int bladeNum)
void WP_SaberAddG2Model (gentity_t *saberent, const char *saberModel, qhandle_t saberSkin)
void WP_SaberRemoveG2Model (gentity_t *saberent)
float RandFloat (float min, float max)
void G_DebugBoxLines (vec3_t mins, vec3_t maxs, int duration)
qboolean G_CanBeEnemy (gentity_t *self, gentity_t *enemy)
void WP_DeactivateSaber (gentity_t *self, qboolean clearLength)
void WP_ActivateSaber (gentity_t *self)
void SaberUpdateSelf (gentity_t *ent)
void SaberGotHit (gentity_t *self, gentity_t *other, trace_t *trace)
qboolean BG_SuperBreakLoseAnim (int anim)
void WP_SaberInitBladeData (gentity_t *ent)
void NPC_SetBoneAngles (gentity_t *ent, char *bone, vec3_t angles)
void WP_SaberBlockNonRandom (gentity_t *self, vec3_t hitloc, qboolean missileBlock)
int G_SaberLockAnim (int attackerSaberStyle, int defenderSaberStyle, int topOrSide, int lockOrBreakOrSuperBreak, int winOrLose)
qboolean BG_CheckIncrementLockAnim (int anim, int winOrLose)
qboolean WP_SabersCheckLock (gentity_t *ent1, gentity_t *ent2)
int PM_SaberBounceForAttack (int move)
int PM_SaberDeflectionForQuad (int quad)
int G_KnockawayForParry (int move)
qboolean saberCheckKnockdown_Thrown (gentity_t *saberent, gentity_t *saberOwner, gentity_t *other)
qboolean saberCheckKnockdown_Smashed (gentity_t *saberent, gentity_t *saberOwner, gentity_t *other, int damage)
qboolean saberCheckKnockdown_BrokenParry (gentity_t *saberent, gentity_t *saberOwner, gentity_t *other)
float WP_SaberBladeLength (saberInfo_t *saber)
float WP_SaberLength (gentity_t *ent)
int WPDEBUG_SaberColor (saber_colors_t saberColor)
qboolean tri_tri_intersect (vec3_t V0, vec3_t V1, vec3_t V2, vec3_t U0, vec3_t U1, vec3_t U2)
qboolean WP_SabersIntersect (gentity_t *ent1, int ent1SaberNum, int ent1BladeNum, gentity_t *ent2, qboolean checkDir)
void WP_SaberClearDamage (void)
void WP_SaberDamageAdd (int trVictimEntityNum, vec3_t trDmgDir, vec3_t trDmgSpot, int trDmg, qboolean doDismemberment, int knockBackFlags)
void WP_SaberApplyDamage (gentity_t *self)
void WP_SaberDoHit (gentity_t *self, int saberNum, int bladeNum)
qboolean G_EntIsBreakable (int entityNum)
void G_Knockdown (gentity_t *victim)
void WP_SaberRadiusDamage (gentity_t *ent, vec3_t point, float radius, int damage, float knockBack)
void WP_SaberDoClash (gentity_t *self, int saberNum, int bladeNum)
void WP_SaberBounceSound (gentity_t *ent, int saberNum, int bladeNum)
qboolean BG_SuperBreakWinAnim (int anim)
GAME_INLINE int VectorCompare2 (const vec3_t v1, const vec3_t v2)
void G_SPSaberDamageTraceLerped (gentity_t *self, int saberNum, int bladeNum, vec3_t baseNew, vec3_t endNew, int clipmask)
qboolean WP_ForcePowerUsable (gentity_t *self, forcePowers_t forcePower)
qboolean InFOV3 (vec3_t spot, vec3_t from, vec3_t fromAngles, int hFOV, int vFOV)
qboolean Jedi_WaitingAmbush (gentity_t *self)
void Jedi_Ambush (gentity_t *self)
evasionType_t Jedi_SaberBlockGo (gentity_t *self, usercmd_t *cmd, vec3_t pHitloc, vec3_t phitDir, gentity_t *incoming, float dist)
void NPC_SetLookTarget (gentity_t *self, int entNum, int clearTime)
void WP_SaberStartMissileBlockCheck (gentity_t *self, usercmd_t *ucmd)
void thrownSaberTouch (gentity_t *saberent, gentity_t *other, trace_t *trace)
void SaberBounceSound (gentity_t *self, gentity_t *other, trace_t *trace)
void DeadSaberThink (gentity_t *saberent)
void MakeDeadSaber (gentity_t *ent)
void saberReactivate (gentity_t *saberent, gentity_t *saberOwner)
void saberBackToOwner (gentity_t *saberent)
void DownedSaberThink (gentity_t *saberent)
void saberKnockDown (gentity_t *saberent, gentity_t *saberOwner, gentity_t *other)
qboolean saberKnockOutOfHand (gentity_t *saberent, gentity_t *saberOwner, vec3_t velocity)
qboolean saberCheckKnockdown_DuelLoss (gentity_t *saberent, gentity_t *saberOwner, gentity_t *other)
qboolean BG_InExtraDefenseSaberMove (int move)
void saberFirstThrown (gentity_t *saberent)
void UpdateClientRenderBolts (gentity_t *self, vec3_t renderOrigin, vec3_t renderAngles)
void UpdateClientRenderinfo (gentity_t *self, vec3_t renderOrigin, vec3_t renderAngles)
void G_GetBoltPosition (gentity_t *self, int boltIndex, vec3_t pos, int modelIndex)
qboolean BG_InKnockDown (int anim)
void WP_SaberPositionUpdate (gentity_t *self, usercmd_t *ucmd)
int WP_MissileBlockForBlock (int saberBlock)
void WP_SaberBlock (gentity_t *playerent, vec3_t hitloc, qboolean missileBlock)
int WP_SaberCanBlock (gentity_t *self, vec3_t point, int dflags, int mod, qboolean projectile, int attackStr)
qboolean HasSetSaberOnly (void)

Variables

bot_state_tbotstates [MAX_CLIENTS]
vmCvar_t g_saberRealisticCombat
vmCvar_t d_saberSPStyleDamage
vmCvar_t g_debugSaberLocks
vmCvar_t g_saberWallDamageScale
int saberSpinSound = 0
stringID_table_t animTable [MAX_ANIMATIONS+1]


Define Documentation

#define LOCK_IDEAL_DIST_CIRCLE   48.0f
 

Definition at line 1087 of file w_saber.c.

#define LOCK_IDEAL_DIST_JKA   46.0f
 

Definition at line 1214 of file w_saber.c.

#define LOCK_IDEAL_DIST_TOP   32.0f
 

Definition at line 1086 of file w_saber.c.

#define LOOK_DEFAULT_SPEED   0.15f
 

Definition at line 637 of file w_saber.c.

#define LOOK_TALKING_SPEED   0.15f
 

Definition at line 638 of file w_saber.c.

#define MAX_LEAVE_TIME   20000
 

Definition at line 6335 of file w_saber.c.

Referenced by DownedSaberThink().

#define MAX_SABER_SWING_INC   0.33f
 

Definition at line 5282 of file w_saber.c.

Referenced by G_SPSaberDamageTraceLerped().

#define MAX_SABER_VICTIMS   16
 

Definition at line 3501 of file w_saber.c.

Referenced by WP_SaberClearDamage(), and WP_SaberDamageAdd().

#define MIN_SABER_SLICE_DISTANCE   50
 

Definition at line 5883 of file w_saber.c.

#define MIN_SABER_SLICE_RETURN_DISTANCE   30
 

Definition at line 5885 of file w_saber.c.

#define PROPER_THROWN_VALUE   999
 

Definition at line 282 of file w_saber.c.

Referenced by SaberUpdateSelf(), and WP_SaberPositionUpdate().

#define SABER_BOX_SIZE   16.0f
 

Definition at line 7 of file w_saber.c.

#define SABER_EXTRAPOLATE_DIST   16.0f
 

Definition at line 2848 of file w_saber.c.

Referenced by WP_SabersIntersect().

#define SABER_HITDAMAGE   35
 

Definition at line 1089 of file w_saber.c.

#define SABER_MAX_THROW_DISTANCE   700
 

Definition at line 7113 of file w_saber.c.

Referenced by saberFirstThrown().

#define SABER_NONATTACK_DAMAGE   1
 

Definition at line 2233 of file w_saber.c.

Referenced by WP_SaberDoHit().

#define SABER_RETRIEVE_DELAY   3000
 

Definition at line 6508 of file w_saber.c.

Referenced by saberKnockDown().

#define SABER_THROWN_HIT_DAMAGE   30
 

Definition at line 5887 of file w_saber.c.

Referenced by saberKnockOutOfHand(), and WP_SaberPositionUpdate().

#define SABER_THROWN_RETURN_HIT_DAMAGE   5
 

Definition at line 5888 of file w_saber.c.

#define SABERINVALID   (!saberent || !saberOwner || !other || !saberent->inuse || !saberOwner->inuse || !other->inuse || !saberOwner->client || !other->client || !saberOwner->client->ps.saberEntityNum || saberOwner->client->ps.saberLockTime > (level.time-100))
 

Definition at line 6585 of file w_saber.c.

Referenced by saberCheckKnockdown_BrokenParry(), saberCheckKnockdown_DuelLoss(), saberCheckKnockdown_Smashed(), and saberCheckKnockdown_Thrown().

#define STAFF_KICK_RANGE   16
 

Definition at line 7468 of file w_saber.c.

#define THROWN_SABER_COMP
 

Definition at line 6161 of file w_saber.c.


Typedef Documentation

typedef struct saberFace_s saberFace_t
 


Enumeration Type Documentation

enum sabersLockMode_t
 

Enumeration values:
LOCK_FIRST 
LOCK_TOP 
LOCK_DIAG_TR 
LOCK_DIAG_TL 
LOCK_DIAG_BR 
LOCK_DIAG_BL 
LOCK_R 
LOCK_L 
LOCK_RANDOM 

Definition at line 1073 of file w_saber.c.

01074 {
01075         LOCK_FIRST = 0,
01076         LOCK_TOP = LOCK_FIRST,
01077         LOCK_DIAG_TR,
01078         LOCK_DIAG_TL,
01079         LOCK_DIAG_BR,
01080         LOCK_DIAG_BL,
01081         LOCK_R,
01082         LOCK_L,
01083         LOCK_RANDOM
01084 } sabersLockMode_t;


Function Documentation

qboolean BG_CheckIncrementLockAnim int  anim,
int  winOrLose
 

Definition at line 1339 of file bg_saber.c.

References BOTH_LK_DL_DL_S_L_1, BOTH_LK_DL_DL_S_L_2, BOTH_LK_DL_DL_T_L_1, BOTH_LK_DL_DL_T_L_2, BOTH_LK_DL_S_S_L_1, BOTH_LK_DL_S_T_L_1, BOTH_LK_DL_ST_S_L_1, BOTH_LK_DL_ST_T_L_1, BOTH_LK_S_DL_S_L_1, BOTH_LK_S_DL_T_L_1, BOTH_LK_S_S_S_L_1, BOTH_LK_S_S_S_L_2, BOTH_LK_S_S_T_L_1, BOTH_LK_S_S_T_L_2, BOTH_LK_S_ST_S_L_1, BOTH_LK_S_ST_T_L_1, BOTH_LK_ST_DL_S_L_1, BOTH_LK_ST_DL_T_L_1, BOTH_LK_ST_S_S_L_1, BOTH_LK_ST_S_T_L_1, BOTH_LK_ST_ST_S_L_1, BOTH_LK_ST_ST_S_L_2, BOTH_LK_ST_ST_T_L_1, BOTH_LK_ST_ST_T_L_2, qboolean, qfalse, qtrue, and SABERLOCK_WIN.

Referenced by PM_SaberLocked().

01340 {
01341         qboolean increment = qfalse;//???
01342         //RULE: if you are the first style in the lock anim, you advance from LOSING position to WINNING position
01343         //              if you are the second style in the lock anim, you advance from WINNING position to LOSING position
01344         switch ( anim )
01345         {
01346         //increment to win:
01347         case BOTH_LK_DL_DL_S_L_1:       //lock if I'm using dual vs. dual and I initiated
01348         case BOTH_LK_DL_DL_S_L_2:       //lock if I'm using dual vs. dual and other initiated
01349         case BOTH_LK_DL_DL_T_L_1:       //lock if I'm using dual vs. dual and I initiated
01350         case BOTH_LK_DL_DL_T_L_2:       //lock if I'm using dual vs. dual and other initiated
01351         case BOTH_LK_DL_S_S_L_1:                //lock if I'm using dual vs. a single
01352         case BOTH_LK_DL_S_T_L_1:                //lock if I'm using dual vs. a single
01353         case BOTH_LK_DL_ST_S_L_1:       //lock if I'm using dual vs. a staff
01354         case BOTH_LK_DL_ST_T_L_1:       //lock if I'm using dual vs. a staff
01355         case BOTH_LK_S_S_S_L_1:         //lock if I'm using single vs. a single and I initiated
01356         case BOTH_LK_S_S_T_L_2:         //lock if I'm using single vs. a single and other initiated
01357         case BOTH_LK_ST_S_S_L_1:                //lock if I'm using staff vs. a single
01358         case BOTH_LK_ST_S_T_L_1:                //lock if I'm using staff vs. a single
01359         case BOTH_LK_ST_ST_T_L_1:       //lock if I'm using staff vs. a staff and I initiated
01360         case BOTH_LK_ST_ST_T_L_2:       //lock if I'm using staff vs. a staff and other initiated
01361                 if ( winOrLose == SABERLOCK_WIN )
01362                 {
01363                         increment = qtrue;
01364                 }
01365                 else
01366                 {
01367                         increment = qfalse;
01368                 }
01369                 break;
01370 
01371         //decrement to win:
01372         case BOTH_LK_S_DL_S_L_1:                //lock if I'm using single vs. a dual
01373         case BOTH_LK_S_DL_T_L_1:                //lock if I'm using single vs. a dual
01374         case BOTH_LK_S_S_S_L_2:         //lock if I'm using single vs. a single and other intitiated
01375         case BOTH_LK_S_S_T_L_1:         //lock if I'm using single vs. a single and I initiated
01376         case BOTH_LK_S_ST_S_L_1:                //lock if I'm using single vs. a staff
01377         case BOTH_LK_S_ST_T_L_1:                //lock if I'm using single vs. a staff
01378         case BOTH_LK_ST_DL_S_L_1:       //lock if I'm using staff vs. dual
01379         case BOTH_LK_ST_DL_T_L_1:       //lock if I'm using staff vs. dual
01380         case BOTH_LK_ST_ST_S_L_1:       //lock if I'm using staff vs. a staff and I initiated
01381         case BOTH_LK_ST_ST_S_L_2:       //lock if I'm using staff vs. a staff and other initiated
01382                 if ( winOrLose == SABERLOCK_WIN )
01383                 {
01384                         increment = qfalse;
01385                 }
01386                 else
01387                 {
01388                         increment = qtrue;
01389                 }
01390                 break;
01391         default:
01392                 break;
01393         }
01394         return increment;
01395 }

qboolean BG_InExtraDefenseSaberMove int  move  ) 
 

Definition at line 415 of file bg_panimate.c.

References LS_A1_SPECIAL, LS_A2_SPECIAL, LS_A3_SPECIAL, LS_DUAL_SPIN_PROTECT, LS_JUMPATTACK_DUAL, LS_SPINATTACK, LS_SPINATTACK_DUAL, LS_STAFF_SOULCAL, qboolean, qfalse, and qtrue.

Referenced by saberCheckKnockdown_Smashed().

00416 {
00417         switch ( move )
00418         {
00419         case LS_SPINATTACK_DUAL:
00420         case LS_SPINATTACK:
00421         case LS_DUAL_SPIN_PROTECT:
00422         case LS_STAFF_SOULCAL:
00423         case LS_A1_SPECIAL:
00424         case LS_A2_SPECIAL:
00425         case LS_A3_SPECIAL:
00426         case LS_JUMPATTACK_DUAL:
00427                 return qtrue;
00428                 break;
00429         }
00430         return qfalse;
00431 }

qboolean BG_InKnockDown int  anim  ) 
 

Definition at line 8526 of file bg_pmove.c.

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

Referenced by ForcePowerUsableOn(), and PM_CheckStabDown().

08527 {
08528         switch ( (anim) )
08529         {
08530         case BOTH_KNOCKDOWN1:
08531         case BOTH_KNOCKDOWN2:
08532         case BOTH_KNOCKDOWN3:
08533         case BOTH_KNOCKDOWN4:
08534         case BOTH_KNOCKDOWN5:
08535                 return qtrue;
08536                 break;
08537         case BOTH_GETUP1:
08538         case BOTH_GETUP2:
08539         case BOTH_GETUP3:
08540         case BOTH_GETUP4:
08541         case BOTH_GETUP5:
08542         case BOTH_FORCE_GETUP_F1:
08543         case BOTH_FORCE_GETUP_F2:
08544         case BOTH_FORCE_GETUP_B1:
08545         case BOTH_FORCE_GETUP_B2:
08546         case BOTH_FORCE_GETUP_B3:
08547         case BOTH_FORCE_GETUP_B4:
08548         case BOTH_FORCE_GETUP_B5:
08549         case BOTH_GETUP_BROLL_B:
08550         case BOTH_GETUP_BROLL_F:
08551         case BOTH_GETUP_BROLL_L:
08552         case BOTH_GETUP_BROLL_R:
08553         case BOTH_GETUP_FROLL_B:
08554         case BOTH_GETUP_FROLL_F:
08555         case BOTH_GETUP_FROLL_L:
08556         case BOTH_GETUP_FROLL_R:
08557                 return qtrue;
08558                 break;
08559         }
08560         return qfalse;
08561 }

qboolean BG_InKnockDownOnGround playerState_t ps  ) 
 

Definition at line 1010 of file bg_panimate.c.

References animNumber_t, BG_AnimLength(), BOTH_FORCE_GETUP_B1, BOTH_FORCE_GETUP_B2, BOTH_FORCE_GETUP_B3, BOTH_FORCE_GETUP_B4, BOTH_FORCE_GETUP_B5, BOTH_FORCE_GETUP_B6, BOTH_FORCE_GETUP_F1, BOTH_FORCE_GETUP_F2, BOTH_GETUP1, BOTH_GETUP2, BOTH_GETUP3, BOTH_GETUP4, BOTH_GETUP5, BOTH_GETUP_BROLL_B, BOTH_GETUP_BROLL_F, BOTH_GETUP_BROLL_L, BOTH_GETUP_BROLL_R, BOTH_GETUP_CROUCH_B1, BOTH_GETUP_CROUCH_F1, BOTH_GETUP_FROLL_B, BOTH_GETUP_FROLL_F, BOTH_GETUP_FROLL_L, BOTH_GETUP_FROLL_R, BOTH_KNOCKDOWN1, BOTH_KNOCKDOWN2, BOTH_KNOCKDOWN3, BOTH_KNOCKDOWN4, BOTH_KNOCKDOWN5, BOTH_LK_DL_ST_T_SB_1_L, BOTH_PLAYER_PA_3_FLY, BOTH_RELEASED, playerState_s::legsAnim, playerState_s::legsTimer, playerState_t, qboolean, qfalse, and qtrue.

01011 {
01012         switch ( ps->legsAnim )
01013         {
01014         case BOTH_KNOCKDOWN1:
01015         case BOTH_KNOCKDOWN2:
01016         case BOTH_KNOCKDOWN3:
01017         case BOTH_KNOCKDOWN4:
01018         case BOTH_KNOCKDOWN5:
01019         case BOTH_RELEASED:
01020                 //if ( PM_AnimLength( g_entities[ps->clientNum].client->clientInfo.animFileIndex, (animNumber_t)ps->legsAnim ) - ps->legsAnimTimer > 300 )
01021                 {//at end of fall down anim
01022                         return qtrue;
01023                 }
01024                 break;
01025         case BOTH_GETUP1:
01026         case BOTH_GETUP2:
01027         case BOTH_GETUP3:
01028         case BOTH_GETUP4:
01029         case BOTH_GETUP5:
01030         case BOTH_GETUP_CROUCH_F1:
01031         case BOTH_GETUP_CROUCH_B1:
01032         case BOTH_FORCE_GETUP_F1:
01033         case BOTH_FORCE_GETUP_F2:
01034         case BOTH_FORCE_GETUP_B1:
01035         case BOTH_FORCE_GETUP_B2:
01036         case BOTH_FORCE_GETUP_B3:
01037         case BOTH_FORCE_GETUP_B4:
01038         case BOTH_FORCE_GETUP_B5:
01039         case BOTH_FORCE_GETUP_B6:
01040                 if ( BG_AnimLength( 0, (animNumber_t)ps->legsAnim ) - ps->legsTimer < 500 )
01041                 {//at beginning of getup anim
01042                         return qtrue;
01043                 }
01044                 break;
01045         case BOTH_GETUP_BROLL_B:
01046         case BOTH_GETUP_BROLL_F:
01047         case BOTH_GETUP_BROLL_L:
01048         case BOTH_GETUP_BROLL_R:
01049         case BOTH_GETUP_FROLL_B:
01050         case BOTH_GETUP_FROLL_F:
01051         case BOTH_GETUP_FROLL_L:
01052         case BOTH_GETUP_FROLL_R:
01053                 if ( BG_AnimLength( 0, (animNumber_t)ps->legsAnim ) - ps->legsTimer < 500 )
01054                 {//at beginning of getup anim
01055                         return qtrue;
01056                 }
01057                 break;
01058         case BOTH_LK_DL_ST_T_SB_1_L:
01059                 if ( ps->legsTimer < 1000 )
01060                 {
01061                         return qtrue;
01062                 }
01063                 break;
01064         case BOTH_PLAYER_PA_3_FLY:
01065                 if ( ps->legsTimer < 300 )
01066                 {
01067                         return qtrue;
01068                 }
01069                 break;
01070         }
01071         return qfalse;
01072 }

qboolean BG_SaberInAttackPure int  move  ) 
 

Definition at line 219 of file bg_panimate.c.

References LS_A_T2B, LS_A_TL2BR, qboolean, qfalse, and qtrue.

00220 {
00221         if ( move >= LS_A_TL2BR && move <= LS_A_T2B )
00222         {
00223                 return qtrue;
00224         }
00225         return qfalse;
00226 }

qboolean BG_SaberInReturn int  move  ) 
 

Definition at line 1202 of file bg_panimate.c.

References PM_SaberInReturn(), and qboolean.

01203 {
01204         return PM_SaberInReturn( move );
01205 }

qboolean BG_SaberInTransitionAny int  move  ) 
 

Definition at line 1619 of file bg_panimate.c.

References PM_SaberInReturn(), PM_SaberInStart(), PM_SaberInTransition(), qboolean, qfalse, and qtrue.

Referenced by PM_SaberAttackForMovement(), and WP_SaberStartMissileBlockCheck().

01620 {
01621         if ( PM_SaberInStart( move ) )
01622         {
01623                 return qtrue;
01624         }
01625         else if ( PM_SaberInTransition( move ) )
01626         {
01627                 return qtrue;
01628         }
01629         else if ( PM_SaberInReturn( move ) )
01630         {
01631                 return qtrue;
01632         }
01633         return qfalse;
01634 }

qboolean BG_SabersOff playerState_t ps  ) 
 

Definition at line 201 of file bg_pmove.c.

References playerState_s::fd, playerState_t, qboolean, qfalse, qtrue, forcedata_s::saberAnimLevelBase, playerState_s::saberHolstered, SS_DUAL, and SS_STAFF.

Referenced by Jedi_SaberBlockGo(), NPC_BSGrenadier_Attack(), PM_GetSaberStance(), PM_VehicleWeaponAnimate(), PM_WeaponLightsaber(), SaberUpdateSelf(), WP_SaberCanBlock(), WP_SaberPositionUpdate(), WP_SabersIntersect(), and WP_SaberStartMissileBlockCheck().

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_StabDownAnim int  anim  ) 
 

Definition at line 1074 of file bg_panimate.c.

References BOTH_STABDOWN, BOTH_STABDOWN_DUAL, BOTH_STABDOWN_STAFF, qboolean, qfalse, and qtrue.

01075 {
01076         switch ( anim )
01077         {
01078         case BOTH_STABDOWN:
01079         case BOTH_STABDOWN_STAFF:
01080         case BOTH_STABDOWN_DUAL:
01081                 return qtrue;
01082         }
01083         return qfalse;
01084 }

qboolean BG_SuperBreakLoseAnim int  anim  ) 
 

Definition at line 1430 of file bg_panimate.c.

References BOTH_LK_DL_DL_S_SB_1_L, BOTH_LK_DL_DL_T_SB_1_L, BOTH_LK_DL_S_S_SB_1_L, BOTH_LK_DL_S_T_SB_1_L, BOTH_LK_DL_ST_S_SB_1_L, BOTH_LK_DL_ST_T_SB_1_L, BOTH_LK_S_DL_S_SB_1_L, BOTH_LK_S_DL_T_SB_1_L, BOTH_LK_S_S_S_SB_1_L, BOTH_LK_S_S_T_SB_1_L, BOTH_LK_S_ST_S_SB_1_L, BOTH_LK_S_ST_T_SB_1_L, BOTH_LK_ST_DL_S_SB_1_L, BOTH_LK_ST_DL_T_SB_1_L, BOTH_LK_ST_S_S_SB_1_L, BOTH_LK_ST_S_T_SB_1_L, BOTH_LK_ST_ST_S_SB_1_L, BOTH_LK_ST_ST_T_SB_1_L, qboolean, qfalse, and qtrue.

Referenced by BG_SaberLockBreakAnim(), and PM_WeaponLightsaber().

01431 {
01432         switch ( anim )
01433         {
01434         case BOTH_LK_S_DL_S_SB_1_L:     //super break I lost
01435         case BOTH_LK_S_DL_T_SB_1_L:     //super break I lost
01436         case BOTH_LK_S_ST_S_SB_1_L:     //super break I lost
01437         case BOTH_LK_S_ST_T_SB_1_L:     //super break I lost
01438         case BOTH_LK_S_S_S_SB_1_L:      //super break I lost
01439         case BOTH_LK_S_S_T_SB_1_L:      //super break I lost
01440         case BOTH_LK_DL_DL_S_SB_1_L:    //super break I lost
01441         case BOTH_LK_DL_DL_T_SB_1_L:    //super break I lost
01442         case BOTH_LK_DL_ST_S_SB_1_L:    //super break I lost
01443         case BOTH_LK_DL_ST_T_SB_1_L:    //super break I lost
01444         case BOTH_LK_DL_S_S_SB_1_L:     //super break I lost
01445         case BOTH_LK_DL_S_T_SB_1_L:     //super break I lost
01446         case BOTH_LK_ST_DL_S_SB_1_L:    //super break I lost
01447         case BOTH_LK_ST_DL_T_SB_1_L:    //super break I lost
01448         case BOTH_LK_ST_ST_S_SB_1_L:    //super break I lost
01449         case BOTH_LK_ST_ST_T_SB_1_L:    //super break I lost
01450         case BOTH_LK_ST_S_S_SB_1_L:     //super break I lost
01451         case BOTH_LK_ST_S_T_SB_1_L:     //super break I lost
01452                 return qtrue;
01453                 break;
01454         }
01455         return qfalse;
01456 }

qboolean BG_SuperBreakWinAnim int  anim  ) 
 

Definition at line 1458 of file bg_panimate.c.

References BOTH_LK_DL_DL_S_SB_1_W, BOTH_LK_DL_DL_T_SB_1_W, BOTH_LK_DL_S_S_SB_1_W, BOTH_LK_DL_S_T_SB_1_W, BOTH_LK_DL_ST_S_SB_1_W, BOTH_LK_DL_ST_T_SB_1_W, BOTH_LK_S_DL_S_SB_1_W, BOTH_LK_S_DL_T_SB_1_W, BOTH_LK_S_S_S_SB_1_W, BOTH_LK_S_S_T_SB_1_W, BOTH_LK_S_ST_S_SB_1_W, BOTH_LK_S_ST_T_SB_1_W, BOTH_LK_ST_DL_S_SB_1_W, BOTH_LK_ST_DL_T_SB_1_W, BOTH_LK_ST_S_S_SB_1_W, BOTH_LK_ST_S_T_SB_1_W, BOTH_LK_ST_ST_S_SB_1_W, BOTH_LK_ST_ST_T_SB_1_W, qboolean, qfalse, and qtrue.

Referenced by BG_SaberLockBreakAnim(), CG_AddSaberBlade(), PM_WeaponLightsaber(), and WP_SaberPositionUpdate().

01459 {
01460         switch ( anim )
01461         {
01462         case BOTH_LK_S_DL_S_SB_1_W:     //super break I won
01463         case BOTH_LK_S_DL_T_SB_1_W:     //super break I won
01464         case BOTH_LK_S_ST_S_SB_1_W:     //super break I won
01465         case BOTH_LK_S_ST_T_SB_1_W:     //super break I won
01466         case BOTH_LK_S_S_S_SB_1_W:      //super break I won
01467         case BOTH_LK_S_S_T_SB_1_W:      //super break I won
01468         case BOTH_LK_DL_DL_S_SB_1_W:    //super break I won
01469         case BOTH_LK_DL_DL_T_SB_1_W:    //super break I won
01470         case BOTH_LK_DL_ST_S_SB_1_W:    //super break I won
01471         case BOTH_LK_DL_ST_T_SB_1_W:    //super break I won
01472         case BOTH_LK_DL_S_S_SB_1_W:     //super break I won
01473         case BOTH_LK_DL_S_T_SB_1_W:     //super break I won
01474         case BOTH_LK_ST_DL_S_SB_1_W:    //super break I won
01475         case BOTH_LK_ST_DL_T_SB_1_W:    //super break I won
01476         case BOTH_LK_ST_ST_S_SB_1_W:    //super break I won
01477         case BOTH_LK_ST_ST_T_SB_1_W:    //super break I won
01478         case BOTH_LK_ST_S_S_SB_1_W:     //super break I won
01479         case BOTH_LK_ST_S_T_SB_1_W:     //super break I won
01480                 return qtrue;
01481                 break;
01482         }
01483         return qfalse;
01484 }

void DeadSaberThink gentity_t saberent  ) 
 

Definition at line 6233 of file w_saber.c.

References G_FreeEntity(), G_RunObject(), gentity_t, level, gentity_s::nextthink, gentity_s::speed, gentity_s::think, and level_locals_t::time.

Referenced by MakeDeadSaber().

06234 {
06235         if (saberent->speed < level.time)
06236         {
06237                 saberent->think = G_FreeEntity;
06238                 saberent->nextthink = level.time;
06239                 return;
06240         }
06241 
06242         G_RunObject(saberent);
06243 }

void DownedSaberThink gentity_t saberent  ) 
 

Definition at line 6340 of file w_saber.c.

References BUTTON_ATTACK, usercmd_s::buttons, CHAN_BODY, gentity_s::client, clientPersistant_t::cmd, entityShared_t::contents, CONTENTS_LIGHTSABER, ENTITYNUM_NONE, playerState_s::fd, forcedata_s::forcePowerLevel, FP_SABER_OFFENSE, g_entities, G_FreeEntity(), G_RunObject(), G_Sound(), G_SoundIndex(), gentity_s::genericValue5, gentity_t, gentity_s::health, gentity_s::inuse, level, entityState_s::loopIsSoundset, entityState_s::loopSound, MakeDeadSaber(), MAX_LEAVE_TIME, gentity_s::nextthink, NULL, entityState_s::number, entityShared_t::ownerNum, gclient_s::pers, playerState_s::pm_flags, PMF_FOLLOW, gclient_s::ps, qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, gclient_s::saber, saberBackToOwner(), playerState_s::saberCanThrow, playerState_s::saberEntityNum, playerState_s::saberEntityState, SaberGotHit(), playerState_s::saberInFlight, gclient_s::saberKnockedTime, saberReactivate(), gclient_s::saberStoredIndex, playerState_s::saberThrowDelay, SaberUpdateSelf(), gclient_s::sess, clientSession_t::sessionTeam, saberInfo_t::soundOn, gentity_s::speed, SVF_NOCLIENT, entityShared_t::svFlags, TEAM_SPECTATOR, gentity_s::think, level_locals_t::time, gentity_s::touch, and WP_SaberRemoveG2Model().

Referenced by saberKnockDown().

06341 {
06342         gentity_t *saberOwn = NULL;
06343         qboolean notDisowned = qfalse;
06344         qboolean pullBack = qfalse;
06345 
06346         saberent->nextthink = level.time;
06347 
06348         if (saberent->r.ownerNum == ENTITYNUM_NONE)
06349         {
06350                 MakeDeadSaber(saberent);
06351 
06352                 saberent->think = G_FreeEntity;
06353                 saberent->nextthink = level.time;
06354                 return;
06355         }
06356 
06357         saberOwn = &g_entities[saberent->r.ownerNum];
06358 
06359         if (!saberOwn ||
06360                 !saberOwn->inuse ||
06361                 !saberOwn->client ||
06362                 saberOwn->client->sess.sessionTeam == TEAM_SPECTATOR ||
06363                 (saberOwn->client->ps.pm_flags & PMF_FOLLOW))
06364         {
06365                 MakeDeadSaber(saberent);
06366 
06367                 saberent->think = G_FreeEntity;
06368                 saberent->nextthink = level.time;
06369                 return;
06370         }
06371 
06372         if (saberOwn->client->ps.saberEntityNum)
06373         {
06374                 if (saberOwn->client->ps.saberEntityNum == saberent->s.number)
06375                 { //owner shouldn't have this set if we're thinking in here. Must've fallen off a cliff and instantly respawned or something.
06376                         notDisowned = qtrue;
06377                 }
06378                 else
06379                 { //This should never happen, but just in case..
06380                         assert(!"ULTRA BAD THING");
06381                         MakeDeadSaber(saberent);
06382 
06383                         saberent->think = G_FreeEntity;
06384                         saberent->nextthink = level.time;
06385                         return;
06386                 }
06387         }
06388 
06389         if (notDisowned || saberOwn->health < 1 || !saberOwn->client->ps.fd.forcePowerLevel[FP_SABER_OFFENSE])
06390         { //He's dead, just go back to our normal saber status
06391                 saberOwn->client->ps.saberEntityNum = saberOwn->client->saberStoredIndex;
06392 
06393                 //MakeDeadSaber(saberent); //spawn a dead saber on top of where we are now. The "bodyqueue" method.
06394                 //Actually this will get taken care of when the thrown saber func sees we're dead.
06395 
06396 #ifdef _DEBUG
06397                 if (saberOwn->client->saberStoredIndex != saberent->s.number)
06398                 { //I'm paranoid.
06399                         assert(!"Bad saber index!!!");
06400                 }
06401 #endif
06402 
06403                 saberReactivate(saberent, saberOwn);
06404 
06405                 if (saberOwn->health < 1)
06406                 {
06407                         saberOwn->client->ps.saberInFlight = qfalse;
06408                         MakeDeadSaber(saberent);
06409                 }
06410 
06411                 saberent->touch = SaberGotHit;
06412                 saberent->think = SaberUpdateSelf;
06413                 saberent->genericValue5 = 0;
06414                 saberent->nextthink = level.time;
06415 
06416                 saberent->r.svFlags |= (SVF_NOCLIENT);
06417                 //saberent->r.contents = CONTENTS_LIGHTSABER;
06418                 saberent->s.loopSound = 0;
06419                 saberent->s.loopIsSoundset = qfalse;
06420 
06421                 if (saberOwn->health > 0)
06422                 { //only set this if he's alive. If dead we want to reflect the lack of saber on the corpse, as he died with his saber out.
06423                         saberOwn->client->ps.saberInFlight = qfalse;
06424                         WP_SaberRemoveG2Model( saberent );
06425                 }
06426                 saberOwn->client->ps.saberEntityState = 0;
06427                 saberOwn->client->ps.saberThrowDelay = level.time + 500;
06428                 saberOwn->client->ps.saberCanThrow = qfalse;
06429 
06430                 return;
06431         }
06432 
06433         if (saberOwn->client->saberKnockedTime < level.time && (saberOwn->client->pers.cmd.buttons & BUTTON_ATTACK))
06434         { //He wants us back
06435                 pullBack = qtrue;
06436         }
06437         else if ((level.time - saberOwn->client->saberKnockedTime) > MAX_LEAVE_TIME)
06438         { //Been sitting around for too long, go back no matter what he wants.
06439                 pullBack = qtrue;
06440         }
06441 
06442         if (pullBack)
06443         { //Get going back to the owner.
06444                 saberOwn->client->ps.saberEntityNum = saberOwn->client->saberStoredIndex;
06445 
06446 #ifdef _DEBUG
06447                 if (saberOwn->client->saberStoredIndex != saberent->s.number)
06448                 { //I'm paranoid.
06449                         assert(!"Bad saber index!!!");
06450                 }
06451 #endif
06452                 saberReactivate(saberent, saberOwn);
06453 
06454                 saberent->touch = SaberGotHit;
06455 
06456                 saberent->think = saberBackToOwner;
06457                 saberent->speed = 0;
06458                 saberent->genericValue5 = 0;
06459                 saberent->nextthink = level.time;
06460 
06461                 saberent->r.contents = CONTENTS_LIGHTSABER;
06462 
06463                 G_Sound( saberOwn, CHAN_BODY, G_SoundIndex( "sound/weapons/force/pull.wav" ) );
06464                 if (saberOwn->client->saber[0].soundOn)
06465                 {
06466                         G_Sound( saberent, CHAN_BODY, saberOwn->client->saber[0].soundOn );
06467                 }
06468                 if (saberOwn->client->saber[1].soundOn)
06469                 {
06470                         G_Sound( saberOwn, CHAN_BODY, saberOwn->client->saber[1].soundOn );
06471                 }
06472 
06473                 return;
06474         }
06475 
06476         G_RunObject(saberent);
06477         saberent->nextthink = level.time;
06478 }

qboolean G_CanBeEnemy gentity_t self,
gentity_t enemy
 

Definition at line 80 of file w_saber.c.

References gentity_s::client, playerState_s::duelIndex, playerState_s::duelInProgress, g_friendlyFire, g_gametype, gentity_t, GT_TEAM, vmCvar_t::integer, gentity_s::inuse, entityState_s::number, OnSameTeam(), gclient_s::ps, qboolean, qfalse, qtrue, and gentity_s::s.

Referenced by PM_VehicleImpact().

00081 {
00082         if (!self->inuse || !enemy->inuse || !self->client || !enemy->client)
00083         {
00084                 return qfalse;
00085         }
00086 
00087         if (self->client->ps.duelInProgress && self->client->ps.duelIndex != enemy->s.number)
00088         { //dueling but not with this person
00089                 return qfalse;
00090         }
00091 
00092         if (enemy->client->ps.duelInProgress && enemy->client->ps.duelIndex != self->s.number)
00093         { //other guy dueling but not with me
00094                 return qfalse;
00095         }
00096 
00097         if (g_gametype.integer < GT_TEAM)
00098         { //ok, sure
00099                 return qtrue;
00100         }
00101 
00102         if (g_friendlyFire.integer)
00103         { //if ff on then can inflict damage normally on teammates
00104                 return qtrue;
00105         }
00106 
00107         if (OnSameTeam(self, enemy))
00108         { //ff not on, don't hurt teammates
00109                 return qfalse;
00110         }
00111 
00112         return qtrue;
00113 }

void G_DebugBoxLines vec3_t  mins,
vec3_t  maxs,
int  duration
 

Definition at line 44 of file w_saber.c.

References G_TestLine(), vec3_t, and VectorCopy.

Referenced by SaberUpdateSelf().

00045 {
00046         vec3_t start;
00047         vec3_t end;
00048 
00049         float x = maxs[0] - mins[0];
00050         float y = maxs[1] - mins[1];
00051 
00052         // top of box
00053         VectorCopy(maxs, start);
00054         VectorCopy(maxs, end);
00055         start[0] -= x;
00056         G_TestLine(start, end, 0x00000ff, duration);
00057         end[0] = start[0];
00058         end[1] -= y;
00059         G_TestLine(start, end, 0x00000ff, duration);
00060         start[1] = end[1];
00061         start[0] += x;
00062         G_TestLine(start, end, 0x00000ff, duration);
00063         G_TestLine(start, maxs, 0x00000ff, duration);
00064         // bottom of box
00065         VectorCopy(mins, start);
00066         VectorCopy(mins, end);
00067         start[0] += x;
00068         G_TestLine(start, end, 0x00000ff, duration);
00069         end[0] = start[0];
00070         end[1] += y;
00071         G_TestLine(start, end, 0x00000ff, duration);
00072         start[1] = end[1];
00073         start[0] -= x;
00074         G_TestLine(start, end, 0x00000ff, duration);
00075         G_TestLine(start, mins, 0x00000ff, duration);
00076 }

qboolean G_EntIsBreakable int  entityNum  ) 
 

Definition at line 2817 of file g_mover.c.

References gentity_s::classname, ENTITYNUM_WORLD, g_entities, gentity_t, Q_stricmp(), qboolean, qfalse, qtrue, gentity_s::r, SVF_GLASS_BRUSH, and entityShared_t::svFlags.

Referenced by NAV_TestBestNode(), vmMain(), and WP_SaberRadiusDamage().

02818 {
02819         gentity_t *ent;
02820 
02821         if ( entityNum < 0 || entityNum >= ENTITYNUM_WORLD )
02822         {
02823                 return qfalse;
02824         }
02825 
02826         ent = &g_entities[entityNum];
02827         if ( (ent->r.svFlags & SVF_GLASS_BRUSH) )
02828         {
02829                 return qtrue;
02830         }
02831         /*
02832         if ( (ent->svFlags&SVF_BBRUSH) )
02833         {
02834                 return qtrue;
02835         }
02836         */
02837         if ( !Q_stricmp( "func_breakable", ent->classname ) )
02838         {
02839                 return qtrue;
02840         }
02841 
02842         if ( !Q_stricmp( "misc_model_breakable", ent->classname ) )
02843         {
02844                 return qtrue;
02845         }
02846         if ( !Q_stricmp( "misc_maglock", ent->classname ) )
02847         {
02848                 return qtrue;
02849         }
02850 
02851         return qfalse;
02852 }

void G_GetBoltPosition gentity_t self,
int  boltIndex,
vec3_t  pos,
int  modelIndex
 

Definition at line 1707 of file NPC_utils.c.

References gentity_s::client, entityShared_t::currentAngles, entityShared_t::currentOrigin, gentity_t, gentity_s::ghoul2, gentity_s::inuse, level, gentity_s::modelScale, NULL, ORIGIN, gclient_s::ps, gentity_s::r, level_locals_t::time, trap_G2API_GetBoltMatrix(), vec3_t, VectorCopy, VectorSet, playerState_s::viewangles, and YAW.

Referenced by NPC_EntRangeFromBolt(), NPC_GetEntsNearBolt(), and Rancor_Attack().

01708 {
01709         mdxaBone_t      boltMatrix;
01710         vec3_t          result, angles;
01711         
01712         if (!self || !self->inuse)
01713         {
01714                 return;
01715         }
01716 
01717         if (self->client)
01718         { //clients don't actually even keep r.currentAngles maintained
01719                 VectorSet(angles, 0, self->client->ps.viewangles[YAW], 0);
01720         }
01721         else
01722         {
01723                 VectorSet(angles, 0, self->r.currentAngles[YAW], 0);
01724         }
01725 
01726         if (  !self->ghoul2 )
01727         {
01728                 return;
01729         }
01730 
01731         trap_G2API_GetBoltMatrix( self->ghoul2, modelIndex, 
01732                                 boltIndex,
01733                                 &boltMatrix, angles, self->r.currentOrigin, level.time,
01734                                 NULL, self->modelScale );
01735         if ( pos )
01736         {
01737                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, result );
01738                 VectorCopy( result, pos );
01739         }
01740 }

int G_KnockawayForParry int  move  ) 
 

Definition at line 2208 of file w_saber.c.

References LS_K1_BL, LS_K1_BR, LS_K1_T_, LS_K1_TL, LS_K1_TR, LS_PARRY_LL, LS_PARRY_LR, LS_PARRY_UL, LS_PARRY_UP, and LS_PARRY_UR.

02209 {
02210         //FIXME: need actual anims for this
02211         //FIXME: need to know which side of the saber was hit!  For now, we presume the saber gets knocked away from the center
02212         switch ( move )
02213         {
02214         case LS_PARRY_UP:
02215                 return LS_K1_T_;//push up
02216                 break;
02217         case LS_PARRY_UR:
02218         default://case LS_READY:
02219                 return LS_K1_TR;//push up, slightly to right
02220                 break;
02221         case LS_PARRY_UL:
02222                 return LS_K1_TL;//push up and to left
02223                 break;
02224         case LS_PARRY_LR:
02225                 return LS_K1_BR;//push down and to left
02226                 break;
02227         case LS_PARRY_LL:
02228                 return LS_K1_BL;//push down and to right
02229                 break;
02230         }
02231 }

void G_Knockdown gentity_t victim  ) 
 

Definition at line 4327 of file g_combat.c.

References BG_KnockDownable(), gentity_s::client, playerState_s::forceDodgeAnim, playerState_s::forceHandExtend, playerState_s::forceHandExtendTime, gentity_t, HANDEXTEND_KNOCKDOWN, level, gclient_s::ps, qfalse, playerState_s::quickerGetup, and level_locals_t::time.

04328 {
04329         if ( victim && victim->client && BG_KnockDownable(&victim->client->ps) )
04330         {
04331                 victim->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
04332                 victim->client->ps.forceDodgeAnim = 0;
04333                 victim->client->ps.forceHandExtendTime = level.time + 1100;
04334                 victim->client->ps.quickerGetup = qfalse;
04335         }
04336 }

int G_SaberLockAnim int  attackerSaberStyle,
int  defenderSaberStyle,
int  topOrSide,
int  lockOrBreakOrSuperBreak,
int  winOrLose
 

Definition at line 1092 of file w_saber.c.

References BOTH_LK_DL_DL_S_B_1_L, BOTH_LK_DL_DL_S_L_2, BOTH_LK_DL_DL_T_L_2, BOTH_LK_DL_S_S_B_1_L, BOTH_LK_DL_ST_S_B_1_L, BOTH_LK_S_DL_S_B_1_L, BOTH_LK_S_S_S_B_1_L, BOTH_LK_S_S_S_L_2, BOTH_LK_S_S_T_L_2, BOTH_LK_S_ST_S_B_1_L, BOTH_LK_ST_DL_S_B_1_L, BOTH_LK_ST_S_S_B_1_L, BOTH_LK_ST_ST_S_B_1_L, BOTH_LK_ST_ST_S_L_2, BOTH_LK_ST_ST_T_L_2, SABERLOCK_LOCK, SABERLOCK_LOSE, SABERLOCK_SUPERBREAK, SABERLOCK_TOP, SABERLOCK_WIN, SS_DUAL, SS_FAST, SS_STAFF, and SS_TAVION.

01093 {
01094         int baseAnim = -1;
01095         if ( lockOrBreakOrSuperBreak == SABERLOCK_LOCK )
01096         {//special case: if we're using the same style and locking
01097                 if ( attackerSaberStyle == defenderSaberStyle 
01098                         || (attackerSaberStyle>=SS_FAST&&attackerSaberStyle<=SS_TAVION&&defenderSaberStyle>=SS_FAST&&defenderSaberStyle<=SS_TAVION) )
01099                 {//using same style
01100                         if ( winOrLose == SABERLOCK_LOSE )
01101                         {//you want the defender's stance...
01102                                 switch ( defenderSaberStyle )
01103                                 {
01104                                 case SS_DUAL:
01105                                         if ( topOrSide == SABERLOCK_TOP )
01106                                         {
01107                                                 baseAnim = BOTH_LK_DL_DL_T_L_2;
01108                                         }
01109                                         else
01110                                         {
01111                                                 baseAnim = BOTH_LK_DL_DL_S_L_2;
01112                                         }
01113                                         break;
01114                                 case SS_STAFF:
01115                                         if ( topOrSide == SABERLOCK_TOP )
01116                                         {
01117                                                 baseAnim = BOTH_LK_ST_ST_T_L_2;
01118                                         }
01119                                         else
01120                                         {
01121                                                 baseAnim = BOTH_LK_ST_ST_S_L_2;
01122                                         }
01123                                         break;
01124                                 default:
01125                                         if ( topOrSide == SABERLOCK_TOP )
01126                                         {
01127                                                 baseAnim = BOTH_LK_S_S_T_L_2;
01128                                         }
01129                                         else
01130                                         {
01131                                                 baseAnim = BOTH_LK_S_S_S_L_2;
01132                                         }
01133                                         break;
01134                                 }
01135                         }
01136                 }
01137         }
01138         if ( baseAnim == -1 )
01139         {
01140                 switch ( attackerSaberStyle )
01141                 {
01142                 case SS_DUAL:
01143                         switch ( defenderSaberStyle )
01144                         {
01145                                 case SS_DUAL:
01146                                         baseAnim = BOTH_LK_DL_DL_S_B_1_L;
01147                                         break;
01148                                 case SS_STAFF:
01149                                         baseAnim = BOTH_LK_DL_ST_S_B_1_L;
01150                                         break;
01151                                 default://single
01152                                         baseAnim = BOTH_LK_DL_S_S_B_1_L;
01153                                         break;
01154                         }
01155                         break;
01156                 case SS_STAFF:
01157                         switch ( defenderSaberStyle )
01158                         {
01159                                 case SS_DUAL:
01160                                         baseAnim = BOTH_LK_ST_DL_S_B_1_L;
01161                                         break;
01162                                 case SS_STAFF:
01163                                         baseAnim = BOTH_LK_ST_ST_S_B_1_L;
01164                                         break;
01165                                 default://single
01166                                         baseAnim = BOTH_LK_ST_S_S_B_1_L;
01167                                         break;
01168                         }
01169                         break;
01170                 default://single
01171                         switch ( defenderSaberStyle )
01172                         {
01173                                 case SS_DUAL:
01174                                         baseAnim = BOTH_LK_S_DL_S_B_1_L;
01175                                         break;
01176                                 case SS_STAFF:
01177                                         baseAnim = BOTH_LK_S_ST_S_B_1_L;
01178                                         break;
01179                                 default://single
01180                                         baseAnim = BOTH_LK_S_S_S_B_1_L;
01181                                         break;
01182                         }
01183                         break;
01184                 }
01185                 //side lock or top lock?
01186                 if ( topOrSide == SABERLOCK_TOP )
01187                 {
01188                         baseAnim += 5;
01189                 }
01190                 //lock, break or superbreak?
01191                 if ( lockOrBreakOrSuperBreak == SABERLOCK_LOCK )
01192                 {
01193                         baseAnim += 2;
01194                 }
01195                 else 
01196                 {//a break or superbreak
01197                         if ( lockOrBreakOrSuperBreak == SABERLOCK_SUPERBREAK )
01198                         {
01199                                 baseAnim += 3;
01200                         }
01201                         //winner or loser?
01202                         if ( winOrLose == SABERLOCK_WIN )
01203                         {
01204                                 baseAnim += 1;
01205                         }
01206                 }
01207         }
01208         return baseAnim;
01209 }

void G_SPSaberDamageTraceLerped gentity_t self,
int  saberNum,
int  bladeNum,
vec3_t  baseNew,
vec3_t  endNew,
int  clipmask
 

Definition at line 5283 of file w_saber.c.

References AngleVectors(), saberTrail_t::base, BG_InSpecialJump(), BG_SaberInAttack(), BG_SaberInSpecialAttack(), BG_SpinningSaberAnim(), saberInfo_t::blade, gentity_s::client, DotProduct, fabs(), gentity_t, saberTrail_t::lastTime, bladeInfo_t::lengthMax, LerpAngle(), level, MAX_SABER_SWING_INC, NULL, gclient_s::ps, qboolean, qfalse, qtrue, gclient_s::saber, playerState_s::saberMove, level_locals_t::time, saberTrail_t::tip, playerState_s::torsoAnim, bladeInfo_t::trail, vec3_t, vectoangles(), VectorCompare2(), VectorCopy, VectorMA, VectorNormalize(), and VectorSubtract.

Referenced by WP_SaberPositionUpdate().

05284 {
05285         vec3_t baseOld, endOld;
05286         vec3_t mp1, mp2;
05287         vec3_t md1, md2;
05288 
05289         if ( (level.time-self->client->saber[saberNum].blade[bladeNum].trail.lastTime) > 100 )
05290         {//no valid last pos, use current
05291                 VectorCopy(baseNew, baseOld);
05292                 VectorCopy(endNew, endOld);
05293         }
05294         else
05295         {//trace from last pos
05296                 VectorCopy( self->client->saber[saberNum].blade[bladeNum].trail.base, baseOld );
05297                 VectorCopy( self->client->saber[saberNum].blade[bladeNum].trail.tip, endOld );
05298         }
05299 
05300         VectorCopy( baseOld, mp1 );
05301         VectorCopy( baseNew, mp2 );
05302         VectorSubtract( endOld, baseOld, md1 );
05303         VectorNormalize( md1 );
05304         VectorSubtract( endNew, baseNew, md2 );
05305         VectorNormalize( md2 );
05306 
05307         saberHitWall = qfalse;
05308         saberHitSaber = qfalse;
05309         saberHitFraction = 1.0f;
05310         if ( VectorCompare2( baseOld, baseNew ) && VectorCompare2( endOld, endNew ) )
05311         {//no diff
05312                 CheckSaberDamage( self, saberNum, bladeNum, baseNew, endNew, qfalse, clipmask, qfalse );
05313         }
05314         else
05315         {//saber moved, lerp
05316                 float step = 8, stepsize = 8;//aveLength, 
05317                 vec3_t  ma1, ma2, md2ang, curBase1, curBase2;
05318                 int     xx;
05319                 vec3_t curMD1, curMD2;//, mdDiff, dirDiff;
05320                 float dirInc, curDirFrac;
05321                 vec3_t baseDiff, bladePointOld, bladePointNew;
05322                 qboolean extrapolate = qtrue;
05323 
05324                 //do the trace at the base first
05325                 VectorCopy( baseOld, bladePointOld );
05326                 VectorCopy( baseNew, bladePointNew );
05327                 CheckSaberDamage( self, saberNum, bladeNum, bladePointOld, bladePointNew, qfalse, clipmask, qtrue );
05328 
05329                 //if hit a saber, shorten rest of traces to match
05330                 if ( saberHitFraction < 1.0f )
05331                 {
05332                         //adjust muzzleDir...
05333                         vec3_t ma1, ma2;
05334                         vectoangles( md1, ma1 );
05335                         vectoangles( md2, ma2 );
05336                         for ( xx = 0; xx < 3; xx++ )
05337                         {
05338                                 md2ang[xx] = LerpAngle( ma1[xx], ma2[xx], saberHitFraction );
05339                         }
05340                         AngleVectors( md2ang, md2, NULL, NULL );
05341                         //shorten the base pos
05342                         VectorSubtract( mp2, mp1, baseDiff );
05343                         VectorMA( mp1, saberHitFraction, baseDiff, baseNew );
05344                         VectorMA( baseNew, self->client->saber[saberNum].blade[bladeNum].lengthMax, md2, endNew );
05345                 }
05346 
05347                 //If the angle diff in the blade is high, need to do it in chunks of 33 to avoid flattening of the arc
05348                 if ( BG_SaberInAttack( self->client->ps.saberMove ) 
05349                         || BG_SaberInSpecialAttack( self->client->ps.torsoAnim ) 
05350                         || BG_SpinningSaberAnim( self->client->ps.torsoAnim ) 
05351                         || BG_InSpecialJump( self->client->ps.torsoAnim ) )
05352                         //|| (g_timescale->value<1.0f&&BG_SaberInTransitionAny( ent->client->ps.saberMove )) )
05353                 {
05354                         curDirFrac = DotProduct( md1, md2 );
05355                 }
05356                 else
05357                 {
05358                         curDirFrac = 1.0f;
05359                 }
05360                 //NOTE: if saber spun at least 180 degrees since last damage trace, this is not reliable...!
05361                 if ( fabs(curDirFrac) < 1.0f - MAX_SABER_SWING_INC )
05362                 {//the saber blade spun more than 33 degrees since the last damage trace
05363                         curDirFrac = dirInc = 1.0f/((1.0f - curDirFrac)/MAX_SABER_SWING_INC);
05364                 }
05365                 else
05366                 {
05367                         curDirFrac = 1.0f;
05368                         dirInc = 0.0f;
05369                 }
05370                 //qboolean hit_saber = qfalse;
05371 
05372                 vectoangles( md1, ma1 );
05373                 vectoangles( md2, ma2 );
05374 
05375                 //VectorSubtract( md2, md1, mdDiff );
05376                 VectorCopy( md1, curMD2 );
05377                 VectorCopy( baseOld, curBase2 );
05378 
05379                 while ( 1 )
05380                 {
05381                         VectorCopy( curMD2, curMD1 );
05382                         VectorCopy( curBase2, curBase1 );
05383                         if ( curDirFrac >= 1.0f )
05384                         {
05385                                 VectorCopy( md2, curMD2 );
05386                                 VectorCopy( baseNew, curBase2 );
05387                         }
05388                         else
05389                         {
05390                                 for ( xx = 0; xx < 3; xx++ )
05391                                 {
05392                                         md2ang[xx] = LerpAngle( ma1[xx], ma2[xx], curDirFrac );
05393                                 }
05394                                 AngleVectors( md2ang, curMD2, NULL, NULL );
05395                                 //VectorMA( md1, curDirFrac, mdDiff, curMD2 );
05396                                 VectorSubtract( baseNew, baseOld, baseDiff );
05397                                 VectorMA( baseOld, curDirFrac, baseDiff, curBase2 );
05398                         }
05399                         // Move up the blade in intervals of stepsize
05400                         for ( step = stepsize; step <= self->client->saber[saberNum].blade[bladeNum].lengthMax /*&& step < self->client->saber[saberNum].blade[bladeNum].lengthOld*/; step += stepsize )
05401                         {
05402                                 VectorMA( curBase1, step, curMD1, bladePointOld );
05403                                 VectorMA( curBase2, step, curMD2, bladePointNew );
05404                                 
05405                                 if ( step+stepsize >= self->client->saber[saberNum].blade[bladeNum].lengthMax )
05406                                 {
05407                                         extrapolate = qfalse;
05408                                 }
05409                                 //do the damage trace
05410                                 CheckSaberDamage( self, saberNum, bladeNum, bladePointOld, bladePointNew, qfalse, clipmask, extrapolate );
05411                                 /*
05412                                 if ( WP_SaberDamageForTrace( ent->s.number, bladePointOld, bladePointNew, baseDamage, curMD2, 
05413                                         qfalse, entPowerLevel, ent->client->ps.saber[saberNum].type, qtrue,
05414                                         saberNum, bladeNum ) )
05415                                 {
05416                                         hit_wall = qtrue;
05417                                 }
05418                                 */
05419 
05420                                 //if hit a saber, shorten rest of traces to match
05421                                 if ( saberHitFraction < 1.0f )
05422                                 {
05423                                         vec3_t curMA1, curMA2;
05424                                         //adjust muzzle endpoint
05425                                         VectorSubtract( mp2, mp1, baseDiff );
05426                                         VectorMA( mp1, saberHitFraction, baseDiff, baseNew );
05427                                         VectorMA( baseNew, self->client->saber[saberNum].blade[bladeNum].lengthMax, curMD2, endNew );
05428                                         //adjust muzzleDir...
05429                                         vectoangles( curMD1, curMA1 );
05430                                         vectoangles( curMD2, curMA2 );
05431                                         for ( xx = 0; xx < 3; xx++ )
05432                                         {
05433                                                 md2ang[xx] = LerpAngle( curMA1[xx], curMA2[xx], saberHitFraction );
05434                                         }
05435                                         AngleVectors( md2ang, curMD2, NULL, NULL );
05436                                         saberHitSaber = qtrue;
05437                                 }
05438                                 if (saberHitWall)
05439                                 {
05440                                         break;
05441                                 }
05442                         }
05443                         if ( saberHitWall || saberHitSaber )
05444                         {
05445                                 break;
05446                         }
05447                         if ( curDirFrac >= 1.0f )
05448                         {
05449                                 break;
05450                         }
05451                         else
05452                         {
05453                                 curDirFrac += dirInc;
05454                                 if ( curDirFrac >= 1.0f )
05455                                 {
05456                                         curDirFrac = 1.0f;
05457                                 }
05458                         }
05459                 }
05460 
05461                 //do the trace at the end last
05462                 //Special check- adjust for length of blade not being a multiple of 12
05463                 /*
05464                 aveLength = (ent->client->ps.saber[saberNum].blade[bladeNum].lengthOld + ent->client->ps.saber[saberNum].blade[bladeNum].length)/2;
05465                 if ( step > aveLength )
05466                 {//less dmg if the last interval was not stepsize
05467                         tipDmgMod = (stepsize-(step-aveLength))/stepsize;
05468                 }
05469                 //NOTE: since this is the tip, we do not extrapolate the extra 16
05470                 if ( WP_SaberDamageForTrace( ent->s.number, endOld, endNew, tipDmgMod*baseDamage, md2, 
05471                         qfalse, entPowerLevel, ent->client->ps.saber[saberNum].type, qfalse,
05472                         saberNum, bladeNum ) )
05473                 {
05474                         hit_wall = qtrue;
05475                 }
05476                 */
05477         }
05478 }

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

Definition at line 212 of file ai_wpnav.c.

References EV_TESTLINE, G_TempEntity(), gentity_t, entityState_s::origin, entityState_s::origin2, gentity_s::r, gentity_s::s, SVF_BROADCAST, entityShared_t::svFlags, entityState_s::time2, vec3_t, VectorCopy, and entityState_s::weapon.

Referenced by AI_RefreshGroup(), BotWaypointRender(), CTFTakesPriority(), G_DebugBoxLines(), UpdateClientRenderinfo(), and WP_SabersIntersect().

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 }

qboolean HasSetSaberOnly void   ) 
 

Definition at line 9448 of file w_saber.c.

References g_duelWeaponDisable, g_gametype, g_weaponDisable, GT_DUEL, GT_JEDIMASTER, GT_POWERDUEL, vmCvar_t::integer, qboolean, qfalse, qtrue, WP_NONE, WP_NUM_WEAPONS, and WP_SABER.

Referenced by CalculateTactician(), ClientSpawn(), FinishSpawningItem(), HolocronUpdate(), SP_misc_holocron(), WP_InitForcePowers(), and WP_SpawnInitForcePowers().

09449 {
09450         int i = 0;
09451         int wDisable = 0;
09452 
09453         if (g_gametype.integer == GT_JEDIMASTER)
09454         { //set to 0 
09455                 return qfalse;
09456         }
09457 
09458         if (g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL)
09459         {
09460                 wDisable = g_duelWeaponDisable.integer;
09461         }
09462         else
09463         {
09464                 wDisable = g_weaponDisable.integer;
09465         }
09466 
09467         while (i < WP_NUM_WEAPONS)
09468         {
09469                 if (!(wDisable & (1 << i)) &&
09470                         i != WP_SABER && i != WP_NONE)
09471                 {
09472                         return qfalse;
09473                 }
09474 
09475                 i++;
09476         }
09477 
09478         return qtrue;
09479 }

qboolean InFOV3 vec3_t  spot,
vec3_t  from,
vec3_t  fromAngles,
int  hFOV,
int  vFOV
 

Definition at line 109 of file NPC_senses.c.

References AngleDelta(), fabs(), PITCH, qboolean, qfalse, qtrue, vec3_t, vectoangles(), VectorSubtract, and YAW.

Referenced by InFOV2(), NPC_BSGrenadier_Attack(), Rancor_Combat(), Wampa_Combat(), and WP_SaberStartMissileBlockCheck().

00110 {
00111         vec3_t  deltaVector, angles, deltaAngles;
00112 
00113         VectorSubtract ( spot, from, deltaVector );
00114         vectoangles ( deltaVector, angles );
00115         
00116         deltaAngles[PITCH]      = AngleDelta ( fromAngles[PITCH], angles[PITCH] );
00117         deltaAngles[YAW]        = AngleDelta ( fromAngles[YAW], angles[YAW] );
00118 
00119         if ( fabs ( deltaAngles[PITCH] ) <= vFOV && fabs ( deltaAngles[YAW] ) <= hFOV ) 
00120         {
00121                 return qtrue;
00122         }
00123 
00124         return qfalse;
00125 }

qboolean InFront vec3_t  spot,
vec3_t  from,
vec3_t  fromAngles,
float  threshHold
 

Definition at line 82 of file NPC_senses.c.

References AngleVectors(), DotProduct, NULL, qboolean, vec3_t, VectorCopy, VectorNormalize(), and VectorSubtract.

Referenced by DoGripAction(), FindGenericEnemyIndex(), NPC_BSGM_Attack(), SeekerDroneUpdate(), WP_SaberCanBlock(), and WP_SabersCheckLock().

00083 {
00084         vec3_t  dir, forward, angles;
00085         float   dot;
00086 
00087         VectorSubtract( spot, from, dir );
00088         dir[2] = 0;
00089         VectorNormalize( dir );
00090 
00091         VectorCopy( fromAngles, angles );
00092         angles[0] = 0;
00093         AngleVectors( angles, forward, NULL, NULL );
00094 
00095         dot = DotProduct( dir, forward );
00096 
00097         return (dot > threshHold);
00098 }

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 }

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, NPC, gentity_s::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_WaitingAmbush gentity_t self  ) 
 

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

void MakeDeadSaber gentity_t ent  ) 
 

Definition at line 6245 of file w_saber.c.

References entityState_s::angles, entityState_s::apos, gentity_s::bounceCount, gentity_s::classname, gentity_s::client, gentity_s::clipmask, entityShared_t::contents, CONTENTS_TRIGGER, entityShared_t::currentAngles, entityShared_t::currentOrigin, DeadSaberThink(), ENTITYNUM_WORLD, ET_MISSILE, entityState_s::eType, FL_BOUNCE_HALF, gentity_s::flags, entityState_s::g2radius, g_entities, G_FreeEntity(), g_gametype, G_Spawn(), gentity_t, GT_JEDIMASTER, vmCvar_t::integer, gentity_s::inuse, level, MASK_PLAYERSOLID, entityShared_t::maxs, entityShared_t::mins, saberInfo_t::model, entityState_s::modelGhoul2, gentity_s::nextthink, NULL, entityState_s::number, entityState_s::origin, entityShared_t::ownerNum, entityState_s::pos, Q_irand(), qtrue, gentity_s::r, gentity_s::s, gclient_s::saber, SaberBounceSound(), saberInfo_t::skin, gentity_s::speed, SVF_USE_CURRENT_ORIGIN, entityShared_t::svFlags, gentity_s::think, level_locals_t::time, gentity_s::touch, TR_GRAVITY, trap_LinkEntity(), trajectory_t::trBase, trajectory_t::trDelta, trajectory_t::trTime, trajectory_t::trType, vec3_t, VectorCopy, VectorSet, entityState_s::weapon, WP_SABER, and WP_SaberAddG2Model().

Referenced by DownedSaberThink(), saberBackToOwner(), and saberFirstThrown().

06246 {       //spawn a "dead" saber entity here so it looks like the saber fell out of the air.
06247         //This entity will remove itself after a very short time period.
06248         vec3_t startorg;
06249         vec3_t startang;
06250         gentity_t *saberent;
06251         gentity_t *owner = NULL;
06252         
06253         if (g_gametype.integer == GT_JEDIMASTER)
06254         { //never spawn a dead saber in JM, because the only saber on the level is really a world object
06255                 //G_Sound(ent, CHAN_AUTO, saberOffSound);
06256                 return;
06257         }
06258 
06259         saberent = G_Spawn();
06260 
06261         VectorCopy(ent->r.currentOrigin, startorg);
06262         VectorCopy(ent->r.currentAngles, startang);
06263 
06264         saberent->classname = "deadsaber";
06265                         
06266         saberent->r.svFlags = SVF_USE_CURRENT_ORIGIN;
06267         saberent->r.ownerNum = ent->s.number;
06268 
06269         saberent->clipmask = MASK_PLAYERSOLID;
06270         saberent->r.contents = CONTENTS_TRIGGER;//0;
06271 
06272         VectorSet( saberent->r.mins, -3.0f, -3.0f, -1.5f );
06273         VectorSet( saberent->r.maxs, 3.0f, 3.0f, 1.5f );
06274 
06275         saberent->touch = SaberBounceSound;
06276 
06277         saberent->think = DeadSaberThink;
06278         saberent->nextthink = level.time;
06279 
06280         VectorCopy(startorg, saberent->s.pos.trBase);
06281         VectorCopy(startang, saberent->s.apos.trBase);
06282 
06283         VectorCopy(startorg, saberent->s.origin);
06284         VectorCopy(startang, saberent->s.angles);
06285 
06286         VectorCopy(startorg, saberent->r.currentOrigin);
06287         VectorCopy(startang, saberent->r.currentAngles);
06288 
06289         saberent->s.apos.trType = TR_GRAVITY;
06290         saberent->s.apos.trDelta[0] = Q_irand(200, 800);
06291         saberent->s.apos.trDelta[1] = Q_irand(200, 800);
06292         saberent->s.apos.trDelta[2] = Q_irand(200, 800);
06293         saberent->s.apos.trTime = level.time-50;
06294 
06295         saberent->s.pos.trType = TR_GRAVITY;
06296         saberent->s.pos.trTime = level.time-50;
06297         saberent->flags = FL_BOUNCE_HALF;
06298         if (ent->r.ownerNum >= 0 && ent->r.ownerNum < ENTITYNUM_WORLD)
06299         {
06300                 owner = &g_entities[ent->r.ownerNum];
06301 
06302                 if (owner->inuse && owner->client &&
06303                         owner->client->saber[0].model[0])
06304                 {
06305                         WP_SaberAddG2Model( saberent, owner->client->saber[0].model, owner->client->saber[0].skin );
06306                 }
06307                 else
06308                 {
06309                         //WP_SaberAddG2Model( saberent, NULL, 0 );
06310                         //argh!!!!
06311                         G_FreeEntity(saberent);
06312                         return;
06313                 }
06314         }
06315 
06316         saberent->s.modelGhoul2 = 1;
06317         saberent->s.g2radius = 20;
06318 
06319         saberent->s.eType = ET_MISSILE;
06320         saberent->s.weapon = WP_SABER;
06321 
06322         saberent->speed = level.time + 4000;
06323 
06324         saberent->bounceCount = 12;
06325 
06326         //fall off in the direction the real saber was headed
06327         VectorCopy(ent->s.pos.trDelta, saberent->s.pos.trDelta);
06328 
06329         saberMoveBack(saberent, qtrue);
06330         saberent->s.pos.trType = TR_GRAVITY;
06331 
06332         trap_LinkEntity(saberent);      
06333 }

void NPC_SetBoneAngles gentity_t ent,
char *  bone,
vec3_t  angles
 

Definition at line 906 of file NPC_utils.c.

References BONE_ANGLES_POSTMULT, entityState_s::boneAngles1, entityState_s::boneAngles2, entityState_s::boneAngles3, entityState_s::boneAngles4, entityState_s::boneIndex1, entityState_s::boneIndex2, entityState_s::boneIndex3, entityState_s::boneIndex4, entityState_s::boneOrient, byte, Com_Printf(), G_BoneIndex(), gentity_t, gentity_s::ghoul2, level, NEGATIVE_Y, NEGATIVE_Z, NULL, POSITIVE_X, gentity_s::s, level_locals_t::time, trap_G2API_SetBoneAngles(), vec3_t, and VectorCopy.

Referenced by Interrogator_PartsMove(), R2D2_PartsMove(), and VEH_TurretAim().

00907 {
00908 #ifdef _XBOX
00909         byte *thebone = &ent->s.boneIndex1;
00910         byte *firstFree = NULL;
00911 #else
00912         int *thebone = &ent->s.boneIndex1;
00913         int *firstFree = NULL;
00914 #endif
00915         int i = 0;
00916         int boneIndex = G_BoneIndex(bone);
00917         int flags, up, right, forward;
00918         vec3_t *boneVector = &ent->s.boneAngles1;
00919         vec3_t *freeBoneVec = NULL;
00920 
00921         while (thebone)
00922         {
00923                 if (!*thebone && !firstFree)
00924                 { //if the value is 0 then this index is clear, we can use it if we don't find the bone we want already existing.
00925                         firstFree = thebone;
00926                         freeBoneVec = boneVector;
00927                 }
00928                 else if (*thebone)
00929                 {
00930                         if (*thebone == boneIndex)
00931                         { //this is it
00932                                 break;
00933                         }
00934                 }
00935 
00936                 switch (i)
00937                 {
00938                 case 0:
00939                         thebone = &ent->s.boneIndex2;
00940                         boneVector = &ent->s.boneAngles2;
00941                         break;
00942                 case 1:
00943                         thebone = &ent->s.boneIndex3;
00944                         boneVector = &ent->s.boneAngles3;
00945                         break;
00946                 case 2:
00947                         thebone = &ent->s.boneIndex4;
00948                         boneVector = &ent->s.boneAngles4;
00949                         break;
00950                 default:
00951                         thebone = NULL;
00952                         boneVector = NULL;
00953                         break;
00954                 }
00955 
00956                 i++;
00957         }
00958 
00959         if (!thebone)
00960         { //didn't find it, create it
00961                 if (!firstFree)
00962                 { //no free bones.. can't do a thing then.
00963                         Com_Printf("WARNING: NPC has no free bone indexes\n");
00964                         return;
00965                 }
00966 
00967                 thebone = firstFree;
00968 
00969                 *thebone = boneIndex;
00970                 boneVector = freeBoneVec;
00971         }
00972 
00973         //If we got here then we have a vector and an index.
00974 
00975         //Copy the angles over the vector in the entitystate, so we can use the corresponding index
00976         //to set the bone angles on the client.
00977         VectorCopy(angles, *boneVector);
00978 
00979         //Now set the angles on our server instance if we have one.
00980 
00981         if (!ent->ghoul2)
00982         {
00983                 return;
00984         }
00985 
00986         flags = BONE_ANGLES_POSTMULT;
00987         up = POSITIVE_X;
00988         right = NEGATIVE_Y;
00989         forward = NEGATIVE_Z;
00990 
00991         //first 3 bits is forward, second 3 bits is right, third 3 bits is up
00992         ent->s.boneOrient = ((forward)|(right<<3)|(up<<6));
00993 
00994         trap_G2API_SetBoneAngles(ent->ghoul2, 0, bone, angles, flags, up, right, forward, NULL, 100, level.time);
00995 }

void NPC_SetLookTarget gentity_t self,
int  entNum,
int  clearTime
 

Definition at line 1632 of file NPC_utils.c.

References gentity_s::client, EF2_HELD_BY_MONSTER, playerState_s::eFlags2, gentity_t, renderInfo_s::lookTarget, renderInfo_s::lookTargetClearTime, gclient_s::ps, and gclient_s::renderInfo.

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

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 }

int PM_SaberBounceForAttack int  move  ) 
 

Definition at line 1086 of file bg_panimate.c.

References LS_B1__L, LS_B1__R, LS_B1_BL, LS_B1_BR, LS_B1_T_, LS_B1_TL, LS_B1_TR, LS_NONE, Q_B, Q_BL, Q_BR, Q_L, Q_R, Q_T, Q_TL, Q_TR, saberMoveData, and saberMoveData_t::startQuad.

Referenced by PM_WeaponLightsaber().

01087 {
01088         switch ( saberMoveData[move].startQuad )
01089         {
01090         case Q_B:
01091         case Q_BR:
01092                 return LS_B1_BR;
01093                 break;
01094         case Q_R:
01095                 return LS_B1__R;
01096                 break;
01097         case Q_TR:
01098                 return LS_B1_TR;
01099                 break;
01100         case Q_T:
01101                 return LS_B1_T_;
01102                 break;
01103         case Q_TL:
01104                 return LS_B1_TL;
01105                 break;
01106         case Q_L:
01107                 return LS_B1__L;
01108                 break;
01109         case Q_BL:
01110                 return LS_B1_BL;
01111                 break;
01112         }
01113         return LS_NONE;
01114 }

int PM_SaberDeflectionForQuad int  quad  ) 
 

Definition at line 1116 of file bg_panimate.c.

References LS_D1__L, LS_D1__R, LS_D1_B_, LS_D1_BL, LS_D1_BR, LS_D1_T_, LS_D1_TL, LS_D1_TR, LS_NONE, Q_B, Q_BL, Q_BR, Q_L, Q_R, Q_T, Q_TL, and Q_TR.

01117 {
01118         switch ( quad )
01119         {
01120         case Q_B:
01121                 return LS_D1_B_;
01122                 break;
01123         case Q_BR:
01124                 return LS_D1_BR;
01125                 break;
01126         case Q_R:
01127                 return LS_D1__R;
01128                 break;
01129         case Q_TR:
01130                 return LS_D1_TR;
01131                 break;
01132         case Q_T:
01133                 return LS_D1_T_;
01134                 break;
01135         case Q_TL:
01136                 return LS_D1_TL;
01137                 break;
01138         case Q_L:
01139                 return LS_D1__L;
01140                 break;
01141         case Q_BL:
01142                 return LS_D1_BL;
01143                 break;
01144         }
01145         return LS_NONE;
01146 }

qboolean PM_SaberInBounce int  move  ) 
 

Definition at line 700 of file bg_saber.c.

References LS_B1_BL, LS_B1_BR, LS_D1_BL, LS_D1_BR, qboolean, qfalse, and qtrue.

Referenced by PM_SaberAttackForMovement(), and PM_WeaponLightsaber().

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.

References LS_H1_BL, LS_H1_T_, LS_V1_B_, LS_V1_BR, qboolean, qfalse, and qtrue.

Referenced by Jedi_SaberBusy(), PM_SetSaberMove(), PM_WeaponLightsaber(), and WP_SaberCanBlock().

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.

References LS_D1_B_, LS_D1_BR, qboolean, qfalse, and qtrue.

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

qboolean PM_SaberInTransition int  move  ) 
 

Definition at line 1610 of file bg_panimate.c.

References LS_T1_BL__L, LS_T1_BR__R, qboolean, qfalse, and qtrue.

Referenced by BG_AdjustClientSpeed(), BG_SaberInTransitionAny(), ClientThink_real(), PM_WeaponLightsaber(), and WP_SaberPositionUpdate().

01611 {
01612         if ( move >= LS_T1_BR__R && move <= LS_T1_BL__L )
01613         {
01614                 return qtrue;
01615         }
01616         return qfalse;
01617 }

float RandFloat float  min,
float  max
 

Definition at line 39 of file w_saber.c.

References min, and rand().

Referenced by G_DeflectMissile(), G_ReflectMissile(), and WP_SaberBlock().

00039                                       {
00040         return ((rand() * (max - min)) / 32768.0F) + min;
00041 }

void saberBackToOwner gentity_t saberent  ) 
 

Definition at line 6915 of file w_saber.c.

References CHAN_AUTO, gentity_s::client, entityShared_t::contents, CONTENTS_LIGHTSABER, entityShared_t::currentOrigin, ENTITYNUM_NONE, playerState_s::fd, FORCE_LEVEL_3, forcedata_s::forcePowerLevel, FP_SABER_OFFENSE, FP_SABERTHROW, g_entities, G_FreeEntity(), G_Sound(), G_SoundIndex(), gentity_s::genericValue5, gentity_t, gentity_s::health, gentity_s::inuse, level, entityState_s::loopIsSoundset, entityState_s::loopSound, MakeDeadSaber(), gentity_s::nextthink, entityState_s::number, entityShared_t::ownerNum, entityState_s::pos, gentity_s::pos1, gclient_s::ps, qfalse, qtrue, gentity_s::r, gentity_s::s, gclient_s::saber, playerState_s::saberCanThrow, playerState_s::saberEntityNum, playerState_s::saberEntityState, saberInfo_t::saberFlags, SaberGotHit(), playerState_s::saberHolstered, entityState_s::saberInFlight, playerState_s::saberInFlight, gclient_s::saberStoredIndex, playerState_s::saberThrowDelay, SaberUpdateSelf(), gclient_s::sess, clientSession_t::sessionTeam, SFL_RETURN_DAMAGE, saberInfo_t::soundLoop, saberInfo_t::soundOff, gentity_s::speed, SVF_NOCLIENT, entityShared_t::svFlags, TEAM_SPECTATOR, gentity_s::think, level_locals_t::time, gentity_s::touch, trajectory_t::trBase, trajectory_t::trDelta, trajectory_t::trTime, vec3_t, VectorCopy, VectorNormalize(), VectorScale, VectorSubtract, and WP_SaberRemoveG2Model().

Referenced by DownedSaberThink(), and thrownSaberTouch().

06916 {
06917         gentity_t *saberOwner = &g_entities[saberent->r.ownerNum];
06918         vec3_t dir;
06919         float ownerLen;
06920 
06921         if (saberent->r.ownerNum == ENTITYNUM_NONE)
06922         {
06923                 MakeDeadSaber(saberent);
06924 
06925                 saberent->think = G_FreeEntity;
06926                 saberent->nextthink = level.time;
06927                 return;
06928         }
06929 
06930         if (!saberOwner->inuse ||
06931                 !saberOwner->client ||
06932                 saberOwner->client->sess.sessionTeam == TEAM_SPECTATOR)
06933         {
06934                 MakeDeadSaber(saberent);
06935 
06936                 saberent->think = G_FreeEntity;
06937                 saberent->nextthink = level.time;
06938                 return;
06939         }
06940 
06941         if (saberOwner->health < 1 || !saberOwner->client->ps.fd.forcePowerLevel[FP_SABER_OFFENSE])
06942         { //He's dead, just go back to our normal saber status
06943                 saberent->touch = SaberGotHit;
06944                 saberent->think = SaberUpdateSelf;
06945                 saberent->genericValue5 = 0;
06946                 saberent->nextthink = level.time;
06947 
06948                 if (saberOwner->client &&
06949                         saberOwner->client->saber[0].soundOff)
06950                 {
06951                         G_Sound(saberent, CHAN_AUTO, saberOwner->client->saber[0].soundOff);
06952                 }
06953                 MakeDeadSaber(saberent);
06954 
06955                 saberent->r.svFlags |= (SVF_NOCLIENT);
06956                 saberent->r.contents = CONTENTS_LIGHTSABER;
06957                 SetSaberBoxSize(saberent);
06958                 saberent->s.loopSound = 0;
06959                 saberent->s.loopIsSoundset = qfalse;
06960                 WP_SaberRemoveG2Model( saberent );
06961 
06962                 saberOwner->client->ps.saberInFlight = qfalse;
06963                 saberOwner->client->ps.saberEntityState = 0;
06964                 saberOwner->client->ps.saberThrowDelay = level.time + 500;
06965                 saberOwner->client->ps.saberCanThrow = qfalse;
06966 
06967                 return;
06968         }
06969 
06970         //make sure this is set alright
06971         assert(saberOwner->client->ps.saberEntityNum == saberent->s.number ||
06972                 saberOwner->client->saberStoredIndex == saberent->s.number);
06973         saberOwner->client->ps.saberEntityNum = saberent->s.number;
06974 
06975         saberent->r.contents = CONTENTS_LIGHTSABER;
06976 
06977         VectorSubtract(saberent->pos1, saberent->r.currentOrigin, dir);
06978 
06979         ownerLen = VectorLength(dir);
06980 
06981         if (saberent->speed < level.time)
06982         {
06983                 float baseSpeed = 900;
06984 
06985                 VectorNormalize(dir);
06986 
06987                 saberMoveBack(saberent, qtrue);
06988                 VectorCopy(saberent->r.currentOrigin, saberent->s.pos.trBase);
06989 
06990                 if (saberOwner->client->ps.fd.forcePowerLevel[FP_SABERTHROW] >= FORCE_LEVEL_3)
06991                 { //allow players with high saber throw rank to control the return speed of the saber
06992                         baseSpeed = 900;
06993 
06994                         saberent->speed = level.time;// + 200;
06995                 }
06996                 else
06997                 {
06998                         baseSpeed = 700;
06999                         saberent->speed = level.time + 50;
07000                 }
07001 
07002                 //Gradually slow down as it approaches, so it looks smoother coming into the hand.
07003                 if (ownerLen < 64)
07004                 {
07005                         VectorScale(dir, baseSpeed-200, saberent->s.pos.trDelta );
07006                 }
07007                 else if (ownerLen < 128)
07008                 {
07009                         VectorScale(dir, baseSpeed-150, saberent->s.pos.trDelta );
07010                 }
07011                 else if (ownerLen < 256)
07012                 {
07013                         VectorScale(dir, baseSpeed-100, saberent->s.pos.trDelta );
07014                 }
07015                 else
07016                 {
07017                         VectorScale(dir, baseSpeed, saberent->s.pos.trDelta );
07018                 }
07019 
07020                 saberent->s.pos.trTime = level.time;
07021         }
07022 
07023         /*
07024         if (ownerLen <= 512)
07025         {
07026                 saberent->s.saberInFlight = qfalse;
07027                 saberent->s.loopSound = saberHumSound;
07028                 saberent->s.loopIsSoundset = qfalse;
07029         }
07030         */
07031         //I'm just doing this now. I don't really like the spin on the way back. And it does weird stuff with the new saber-knocked-away code.
07032         if (saberOwner->client->ps.saberEntityNum == saberent->s.number)
07033         {
07034                 if ( !(saberOwner->client->saber[0].saberFlags&SFL_RETURN_DAMAGE)
07035                         || saberOwner->client->ps.saberHolstered )
07036                 {
07037                         saberent->s.saberInFlight = qfalse;
07038                 }
07039                 saberent->s.loopSound = saberOwner->client->saber[0].soundLoop;
07040                 saberent->s.loopIsSoundset = qfalse;
07041 
07042                 if (ownerLen <= 32)
07043                 {
07044                         G_Sound( saberent, CHAN_AUTO, G_SoundIndex( "sound/weapons/saber/saber_catch.wav" ) );
07045 
07046                         saberOwner->client->ps.saberInFlight = qfalse;
07047                         saberOwner->client->ps.saberEntityState = 0;
07048                         saberOwner->client->ps.saberCanThrow = qfalse;
07049                         saberOwner->client->ps.saberThrowDelay = level.time + 300;
07050 
07051                         saberent->touch = SaberGotHit;
07052 
07053                         saberent->think = SaberUpdateSelf;
07054                         saberent->genericValue5 = 0;
07055                         saberent->nextthink = level.time + 50;
07056                         WP_SaberRemoveG2Model( saberent );
07057 
07058                         return;
07059                 }
07060 
07061                 if (!saberent->s.saberInFlight)
07062                 {
07063                         saberCheckRadiusDamage(saberent, 1);
07064                 }
07065                 else
07066                 {
07067                         saberCheckRadiusDamage(saberent, 2);
07068                 }
07069 
07070                 saberMoveBack(saberent, qtrue);
07071         }
07072 
07073         saberent->nextthink = level.time;
07074 }

void SaberBounceSound gentity_t self,
gentity_t other,
trace_t trace
 

Definition at line 6227 of file w_saber.c.

References entityState_s::apos, entityShared_t::currentAngles, gentity_t, PITCH, gentity_s::r, gentity_s::s, trajectory_t::trBase, and VectorCopy.

Referenced by MakeDeadSaber(), and saberKnockDown().

06228 {
06229         VectorCopy(self->r.currentAngles, self->s.apos.trBase);
06230         self->s.apos.trBase[PITCH] = 90;
06231 }

qboolean saberCheckKnockdown_BrokenParry gentity_t saberent,
gentity_t saberOwner,
gentity_t other
 

Definition at line 6763 of file w_saber.c.

References gentity_s::client, saberInfo_t::disarmBonus, gentity_t, gclient_s::lastSaberBase_Always, gclient_s::lastSaberStorageTime, level, saberInfo_t::model, gclient_s::olderIsValid, gclient_s::olderSaberBase, gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, gclient_s::saber, playerState_s::saberHolstered, SABERINVALID, saberKnockOutOfHand(), level_locals_t::time, vec3_t, VectorNormalize(), VectorScale, and VectorSubtract.

06764 {
06765         int myAttack;
06766         int otherAttack;
06767         qboolean doKnock = qfalse;
06768         int     disarmChance = 1;
06769 
06770         if (SABERINVALID)
06771         {
06772                 return qfalse;
06773         }
06774 
06775         //Neither gets an advantage based on attack state, when it comes to knocking
06776         //saber out of hand.
06777         myAttack = G_SaberAttackPower(saberOwner, qfalse);
06778         otherAttack = G_SaberAttackPower(other, qfalse);
06779 
06780         if (!other->client->olderIsValid || (level.time - other->client->lastSaberStorageTime) >= 200)
06781         { //if we don't know which way to throw the saber based on momentum between saber positions, just don't throw it
06782                 return qfalse;
06783         }
06784 
06785         //only knock the saber out of the hand if they're in a stronger stance I suppose. Makes strong more advantageous.
06786         if (otherAttack > myAttack+1 && Q_irand(1, 10) <= 7)
06787         { //This would be, say, strong stance against light stance.
06788                 doKnock = qtrue;
06789         }
06790         else if (otherAttack > myAttack && Q_irand(1, 10) <= 3)
06791         { //Strong vs. medium, medium vs. light
06792                 doKnock = qtrue;
06793         }
06794 
06795         if (doKnock)
06796         {
06797                 vec3_t dif;
06798                 float totalDistance;
06799                 float distScale = 6.5f;
06800 
06801                 VectorSubtract(other->client->lastSaberBase_Always, other->client->olderSaberBase, dif);
06802                 totalDistance = VectorNormalize(dif);
06803 
06804                 if (!totalDistance)
06805                 { //fine, try our own
06806                         if (!saberOwner->client->olderIsValid || (level.time - saberOwner->client->lastSaberStorageTime) >= 200)
06807                         { //if we don't know which way to throw the saber based on momentum between saber positions, just don't throw it
06808                                 return qfalse;
06809                         }
06810 
06811                         VectorSubtract(saberOwner->client->lastSaberBase_Always, saberOwner->client->olderSaberBase, dif);
06812                         totalDistance = VectorNormalize(dif);
06813                 }
06814 
06815                 if (!totalDistance)
06816                 { //...forget it then.
06817                         return qfalse;
06818                 }
06819 
06820                 if (totalDistance < 20)
06821                 {
06822                         totalDistance = 20;
06823                 }
06824                 VectorScale(dif, totalDistance*distScale, dif);
06825 
06826                 if ( other && other->client )
06827                 {
06828                         disarmChance += other->client->saber[0].disarmBonus;
06829                         if ( other->client->saber[1].model
06830                                 && other->client->saber[1].model[0]
06831                                 && !other->client->ps.saberHolstered )
06832                         {
06833                                 other->client->saber[1].disarmBonus;
06834                         }
06835                 }
06836                 if ( Q_irand( 0, disarmChance ) )
06837                 {
06838                         return saberKnockOutOfHand(saberent, saberOwner, dif);
06839                 }
06840         }
06841 
06842         return qfalse;
06843 }

qboolean saberCheckKnockdown_DuelLoss gentity_t saberent,
gentity_t saberOwner,
gentity_t other
 

Definition at line 6679 of file w_saber.c.

References BLOCKED_BOUNCE_MOVE, gentity_s::client, saberInfo_t::disarmBonus, gentity_t, gclient_s::lastSaberBase_Always, gclient_s::lastSaberStorageTime, level, LS_V1_BL, saberInfo_t::model, gclient_s::olderIsValid, gclient_s::olderSaberBase, gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, gclient_s::saber, playerState_s::saberBlocked, playerState_s::saberHolstered, SABERINVALID, saberKnockOutOfHand(), playerState_s::saberMove, level_locals_t::time, vec3_t, VectorClear, VectorNormalize(), VectorScale, and VectorSubtract.

Referenced by ClientThink_real().

06680 {
06681         vec3_t dif;
06682         float totalDistance = 1;
06683         float distScale = 6.5f;
06684         qboolean validMomentum = qtrue;
06685         int     disarmChance = 1;
06686 
06687         if (SABERINVALID)
06688         {
06689                 return qfalse;
06690         }
06691 
06692         VectorClear(dif);
06693 
06694         if (!other->client->olderIsValid || (level.time - other->client->lastSaberStorageTime) >= 200)
06695         { //see if the spots are valid
06696                 validMomentum = qfalse;
06697         }
06698 
06699         if (validMomentum)
06700         {
06701                 //Get the difference 
06702                 VectorSubtract(other->client->lastSaberBase_Always, other->client->olderSaberBase, dif);
06703                 totalDistance = VectorNormalize(dif);
06704 
06705                 if (!totalDistance)
06706                 { //fine, try our own
06707                         if (!saberOwner->client->olderIsValid || (level.time - saberOwner->client->lastSaberStorageTime) >= 200)
06708                         {
06709                                 validMomentum = qfalse;
06710                         }
06711 
06712                         if (validMomentum)
06713                         {
06714                                 VectorSubtract(saberOwner->client->lastSaberBase_Always, saberOwner->client->olderSaberBase, dif);
06715                                 totalDistance = VectorNormalize(dif);
06716                         }
06717                 }
06718 
06719                 if (validMomentum)
06720                 {
06721                         if (!totalDistance)
06722                         { //try the difference between the two blades
06723                                 VectorSubtract(saberOwner->client->lastSaberBase_Always, other->client->lastSaberBase_Always, dif);
06724                                 totalDistance = VectorNormalize(dif);
06725                         }
06726 
06727                         if (totalDistance)
06728                         { //if we still have no difference somehow, just let it fall to the ground when the time comes.
06729                                 if (totalDistance < 20)
06730                                 {
06731                                         totalDistance = 20;
06732                                 }
06733                                 VectorScale(dif, totalDistance*distScale, dif);
06734                         }
06735                 }
06736         }
06737 
06738         saberOwner->client->ps.saberMove = LS_V1_BL; //rwwFIXMEFIXME: Ideally check which lock it was exactly and use the proper anim (same goes for the attacker)
06739         saberOwner->client->ps.saberBlocked = BLOCKED_BOUNCE_MOVE;
06740 
06741         if ( other && other->client )
06742         {
06743                 disarmChance += other->client->saber[0].disarmBonus;
06744                 if ( other->client->saber[1].model
06745                         && other->client->saber[1].model[0]
06746                         && !other->client->ps.saberHolstered )
06747                 {
06748                         other->client->saber[1].disarmBonus;
06749                 }
06750         }
06751         if ( Q_irand( 0, disarmChance ) )
06752         {
06753                 return saberKnockOutOfHand(saberent, saberOwner, dif);
06754         }
06755         else
06756         {
06757                 return qfalse;
06758         }
06759 }

qboolean saberCheckKnockdown_Smashed gentity_t saberent,
gentity_t saberOwner,
gentity_t other,
int  damage
 

Definition at line 6850 of file w_saber.c.

References BG_InExtraDefenseSaberMove(), gentity_s::client, gentity_t, gentity_s::inuse, gclient_s::ps, qboolean, qfalse, qtrue, playerState_s::saberInFlight, SABERINVALID, saberKnockDown(), and playerState_s::saberMove.

06851 {
06852         if (SABERINVALID)
06853         {
06854                 return qfalse;
06855         }
06856 
06857         if (!saberOwner->client->ps.saberInFlight)
06858         { //can only do this if the saber is already actually in flight
06859                 return qfalse;
06860         }
06861 
06862         if ( other
06863                 && other->inuse
06864                 && other->client 
06865                 && BG_InExtraDefenseSaberMove( other->client->ps.saberMove ) )
06866         { //make sure the blow was strong enough
06867                 saberKnockDown(saberent, saberOwner, other);
06868                 return qtrue;
06869         }
06870 
06871         if (damage > 10)
06872         { //make sure the blow was strong enough
06873                 saberKnockDown(saberent, saberOwner, other);
06874                 return qtrue;
06875         }
06876 
06877         return qfalse;
06878 }

qboolean saberCheckKnockdown_Thrown gentity_t saberent,
gentity_t saberOwner,
gentity_t other
 

Definition at line 6882 of file w_saber.c.

References gentity_s::client, playerState_s::fd, forcedata_s::forcePowerLevel, FP_SABER_DEFENSE, FP_SABERTHROW, gentity_t, gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, SABERINVALID, and saberKnockDown().

06883 {
06884         int throwLevel = 0;
06885         int defenLevel = 0;
06886         qboolean tossIt = qfalse;
06887 
06888         if (SABERINVALID)
06889         {
06890                 return qfalse;
06891         }
06892 
06893         defenLevel = other->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE];
06894         throwLevel = saberOwner->client->ps.fd.forcePowerLevel[FP_SABERTHROW];
06895 
06896         if (defenLevel > throwLevel)
06897         {
06898                 tossIt = qtrue;
06899         }
06900         else if (defenLevel == throwLevel && Q_irand(1, 10) <= 4)
06901         {
06902                 tossIt = qtrue;
06903         }
06904         //otherwise don't
06905 
06906         if (tossIt)
06907         {
06908                 saberKnockDown(saberent, saberOwner, other);
06909                 return qtrue;
06910         }
06911 
06912         return qfalse;
06913 }

void saberFirstThrown gentity_t saberent  ) 
 

Definition at line 7115 of file w_saber.c.

References AngleVectors(), BG_CanUseFPNow(), BG_HasYsalamiri(), BUTTON_ALT_ATTACK, gclient_s::buttons, CHAN_AUTO, gentity_s::client, entityShared_t::contents, CONTENTS_LIGHTSABER, entityShared_t::currentOrigin, trace_t::endpos, ENTITYNUM_NONE, playerState_s::fd, FORCE_LEVEL_2, FORCE_LEVEL_3, forcedata_s::forcePowerLevel, FP_SABER_OFFENSE, FP_SABERTHROW, g_entities, G_FreeEntity(), g_gametype, G_RunObject(), G_Sound(), gentity_s::genericValue5, gentity_t, gentity_s::health, vmCvar_t::integer, gentity_s::inuse, level, entityState_s::loopIsSoundset, entityState_s::loopSound, MakeDeadSaber(), MASK_PLAYERSOLID, MASK_SOLID, gentity_s::nextthink, NULL, entityState_s::number, playerState_s::origin, entityShared_t::ownerNum, entityState_s::pos, gclient_s::ps, qfalse, gentity_s::r, gentity_s::s, gclient_s::saber, SABER_MAX_THROW_DISTANCE, playerState_s::saberCanThrow, playerState_s::saberDidThrowTime, playerState_s::saberEntityState, SaberGotHit(), playerState_s::saberInFlight, playerState_s::saberThrowDelay, SaberUpdateSelf(), gclient_s::sess, clientSession_t::sessionTeam, saberInfo_t::soundOff, gentity_s::speed, SVF_NOCLIENT, entityShared_t::svFlags, TEAM_SPECTATOR, gentity_s::think, thrownSaberTouch(), level_locals_t::time, gentity_s::touch, trap_Trace(), trajectory_t::trBase, trajectory_t::trDelta, trajectory_t::trTime, vec3_t, VectorCopy, VectorNormalize(), VectorScale, VectorSubtract, playerState_s::viewangles, playerState_s::viewheight, and WP_SaberRemoveG2Model().

Referenced by WP_SaberPositionUpdate().

07116 {
07117         vec3_t          vSub;
07118         float           vLen;
07119         gentity_t       *saberOwn = &g_entities[saberent->r.ownerNum];
07120 
07121         if (saberent->r.ownerNum == ENTITYNUM_NONE)
07122         {
07123                 MakeDeadSaber(saberent);
07124 
07125                 saberent->think = G_FreeEntity;
07126                 saberent->nextthink = level.time;
07127                 return;
07128         }
07129 
07130         if (!saberOwn ||
07131                 !saberOwn->inuse ||
07132                 !saberOwn->client ||
07133                 saberOwn->client->sess.sessionTeam == TEAM_SPECTATOR)
07134         {
07135                 MakeDeadSaber(saberent);
07136 
07137                 saberent->think = G_FreeEntity;
07138                 saberent->nextthink = level.time;
07139                 return;
07140         }
07141 
07142         if (saberOwn->health < 1 || !saberOwn->client->ps.fd.forcePowerLevel[FP_SABER_OFFENSE])
07143         { //He's dead, just go back to our normal saber status
07144                 saberent->touch = SaberGotHit;
07145                 saberent->think = SaberUpdateSelf;
07146                 saberent->genericValue5 = 0;
07147                 saberent->nextthink = level.time;
07148 
07149                 if (saberOwn->client &&
07150                         saberOwn->client->saber[0].soundOff)
07151                 {
07152                         G_Sound(saberent, CHAN_AUTO, saberOwn->client->saber[0].soundOff);
07153                 }
07154                 MakeDeadSaber(saberent);
07155 
07156                 saberent->r.svFlags |= (SVF_NOCLIENT);
07157                 saberent->r.contents = CONTENTS_LIGHTSABER;
07158                 SetSaberBoxSize(saberent);
07159                 saberent->s.loopSound = 0;
07160                 saberent->s.loopIsSoundset = qfalse;
07161                 WP_SaberRemoveG2Model( saberent );
07162 
07163                 saberOwn->client->ps.saberInFlight = qfalse;
07164                 saberOwn->client->ps.saberEntityState = 0;
07165                 saberOwn->client->ps.saberThrowDelay = level.time + 500;
07166                 saberOwn->client->ps.saberCanThrow = qfalse;
07167 
07168                 return;
07169         }
07170 
07171         if ((level.time - saberOwn->client->ps.saberDidThrowTime) > 500)
07172         {
07173                 if (!(saberOwn->client->buttons & BUTTON_ALT_ATTACK))
07174                 { //If owner releases altattack 500ms or later after throwing saber, it autoreturns
07175                         thrownSaberTouch(saberent, saberent, NULL);
07176                         goto runMin;
07177                 }
07178                 else if ((level.time - saberOwn->client->ps.saberDidThrowTime) > 6000)
07179                 { //if it's out longer than 6 seconds, return it
07180                         thrownSaberTouch(saberent, saberent, NULL);
07181                         goto runMin;
07182                 }
07183         }
07184 
07185         if (BG_HasYsalamiri(g_gametype.integer, &saberOwn->client->ps))
07186         {
07187                 thrownSaberTouch(saberent, saberent, NULL);
07188                 goto runMin;
07189         }
07190         
07191         if (!BG_CanUseFPNow(g_gametype.integer, &saberOwn->client->ps, level.time, FP_SABERTHROW))
07192         {
07193                 thrownSaberTouch(saberent, saberent, NULL);
07194                 goto runMin;
07195         }
07196 
07197         VectorSubtract(saberOwn->client->ps.origin, saberent->r.currentOrigin, vSub);
07198         vLen = VectorLength(vSub);
07199 
07200         if (vLen >= (SABER_MAX_THROW_DISTANCE*saberOwn->client->ps.fd.forcePowerLevel[FP_SABERTHROW]))
07201         {
07202                 thrownSaberTouch(saberent, saberent, NULL);
07203                 goto runMin;
07204         }
07205 
07206         if (saberOwn->client->ps.fd.forcePowerLevel[FP_SABERTHROW] >= FORCE_LEVEL_2 &&
07207                 saberent->speed < level.time)
07208         { //if owner is rank 3 in saber throwing, the saber goes where he points
07209                 vec3_t fwd, traceFrom, traceTo, dir;
07210                 trace_t tr;
07211 
07212                 AngleVectors(saberOwn->client->ps.viewangles, fwd, 0, 0);
07213 
07214                 VectorCopy(saberOwn->client->ps.origin, traceFrom);
07215                 traceFrom[2] += saberOwn->client->ps.viewheight;
07216 
07217                 VectorCopy(traceFrom, traceTo);
07218                 traceTo[0] += fwd[0]*4096;
07219                 traceTo[1] += fwd[1]*4096;
07220                 traceTo[2] += fwd[2]*4096;
07221 
07222                 saberMoveBack(saberent, qfalse);
07223                 VectorCopy(saberent->r.currentOrigin, saberent->s.pos.trBase);
07224 
07225                 if (saberOwn->client->ps.fd.forcePowerLevel[FP_SABERTHROW] >= FORCE_LEVEL_3)
07226                 { //if highest saber throw rank, we can direct the saber toward players directly by looking at them
07227                         trap_Trace(&tr, traceFrom, NULL, NULL, traceTo, saberOwn->s.number, MASK_PLAYERSOLID);
07228                 }
07229                 else
07230                 {
07231                         trap_Trace(&tr, traceFrom, NULL, NULL, traceTo, saberOwn->s.number, MASK_SOLID);
07232                 }
07233 
07234                 VectorSubtract(tr.endpos, saberent->r.currentOrigin, dir);
07235 
07236                 VectorNormalize(dir);
07237 
07238                 VectorScale(dir, 500, saberent->s.pos.trDelta );
07239                 saberent->s.pos.trTime = level.time;
07240 
07241                 if (saberOwn->client->ps.fd.forcePowerLevel[FP_SABERTHROW] >= FORCE_LEVEL_3)
07242                 { //we'll treat them to a quicker update rate if their throw rank is high enough
07243                         saberent->speed = level.time + 100;
07244                 }
07245                 else
07246                 {
07247                         saberent->speed = level.time + 400;
07248                 }
07249         }
07250 
07251 runMin:
07252 
07253         saberCheckRadiusDamage(saberent, 0);
07254         G_RunObject(saberent);
07255 }

void SaberGotHit gentity_t self,
gentity_t other,
trace_t trace
 

Definition at line 358 of file w_saber.c.

References gentity_s::client, g_entities, gentity_t, entityShared_t::ownerNum, and gentity_s::r.

Referenced by DownedSaberThink(), saberBackToOwner(), saberFirstThrown(), and WP_SaberInitBladeData().

00359 {
00360         gentity_t *own = &g_entities[self->r.ownerNum];
00361 
00362         if (!own || !own->client)
00363         {
00364                 return;
00365         }
00366 
00367         //Do something here..? Was handling projectiles here, but instead they're now handled in their own functions.
00368 }

void saberKnockDown gentity_t saberent,
gentity_t saberOwner,
gentity_t other
 

Definition at line 6510 of file w_saber.c.

References AngleVectors(), entityState_s::apos, gentity_s::bounceCount, CHAN_BODY, gentity_s::client, gentity_s::clipmask, entityShared_t::contents, CONTENTS_TRIGGER, DownedSaberThink(), ET_MISSILE, entityState_s::eType, FL_BOUNCE_HALF, gentity_s::flags, entityState_s::g2radius, G_Sound(), gentity_t, gentity_s::inuse, level, entityState_s::loopIsSoundset, entityState_s::loopSound, MASK_SOLID, entityShared_t::maxs, entityShared_t::mins, saberInfo_t::model, entityState_s::modelGhoul2, gentity_s::nextthink, entityState_s::pos, gclient_s::ps, Q_irand(), qfalse, qtrue, gentity_s::r, gentity_s::s, gclient_s::saber, SABER_RETRIEVE_DELAY, SaberBounceSound(), playerState_s::saberEntityNum, gclient_s::saberKnockedTime, saberInfo_t::skin, saberInfo_t::soundOff, gentity_s::speed, SVF_NOCLIENT, entityShared_t::svFlags, gentity_s::think, level_locals_t::time, gentity_s::touch, TR_GRAVITY, trap_LinkEntity(), trajectory_t::trDelta, trajectory_t::trTime, trajectory_t::trType, vec3_t, VectorSet, playerState_s::viewangles, entityState_s::weapon, WP_SABER, and WP_SaberAddG2Model().

Referenced by Cmd_ToggleSaber_f(), saberCheckKnockdown_Smashed(), saberCheckKnockdown_Thrown(), and saberKnockOutOfHand().

06511 {
06512         saberOwner->client->ps.saberEntityNum = 0; //still stored in client->saberStoredIndex
06513         saberOwner->client->saberKnockedTime = level.time + SABER_RETRIEVE_DELAY;
06514 
06515         saberent->clipmask = MASK_SOLID;
06516         saberent->r.contents = CONTENTS_TRIGGER;//0;
06517 
06518         VectorSet( saberent->r.mins, -3.0f, -3.0f, -1.5f );
06519         VectorSet( saberent->r.maxs, 3.0f, 3.0f, 1.5f );
06520 
06521         saberent->s.apos.trType = TR_GRAVITY;
06522         saberent->s.apos.trDelta[0] = Q_irand(200, 800);
06523         saberent->s.apos.trDelta[1] = Q_irand(200, 800);
06524         saberent->s.apos.trDelta[2] = Q_irand(200, 800);
06525         saberent->s.apos.trTime = level.time-50;
06526 
06527         saberent->s.pos.trType = TR_GRAVITY;
06528         saberent->s.pos.trTime = level.time-50;
06529         saberent->flags |= FL_BOUNCE_HALF;
06530 
06531         WP_SaberAddG2Model( saberent, saberOwner->client->saber[0].model, saberOwner->client->saber[0].skin );
06532 
06533         saberent->s.modelGhoul2 = 1;
06534         saberent->s.g2radius = 20;
06535 
06536         saberent->s.eType = ET_MISSILE;
06537         saberent->s.weapon = WP_SABER;
06538 
06539         saberent->speed = level.time + 4000;
06540 
06541         saberent->bounceCount = -5;//8;
06542 
06543         saberMoveBack(saberent, qtrue);
06544         saberent->s.pos.trType = TR_GRAVITY;
06545 
06546         saberent->s.loopSound = 0; //kill this in case it was spinning.
06547         saberent->s.loopIsSoundset = qfalse;
06548 
06549         saberent->r.svFlags &= ~(SVF_NOCLIENT); //make sure the client is getting updates on where it is and such.
06550 
06551         saberent->touch = SaberBounceSound;
06552         saberent->think = DownedSaberThink;
06553         saberent->nextthink = level.time;
06554 
06555         if (saberOwner != other)
06556         { //if someone knocked it out of the air and it wasn't turned off, go in the direction they were facing.
06557                 if (other->inuse && other->client)
06558                 {
06559                         vec3_t otherFwd;
06560                         float deflectSpeed = 200;
06561 
06562                         AngleVectors(other->client->ps.viewangles, otherFwd, 0, 0);
06563 
06564                         saberent->s.pos.trDelta[0] = otherFwd[0]*deflectSpeed;
06565                         saberent->s.pos.trDelta[1] = otherFwd[1]*deflectSpeed;
06566                         saberent->s.pos.trDelta[2] = otherFwd[2]*deflectSpeed;
06567                 }
06568         }
06569 
06570         trap_LinkEntity(saberent);
06571 
06572         if (saberOwner->client->saber[0].soundOff)
06573         {
06574                 G_Sound( saberent, CHAN_BODY, saberOwner->client->saber[0].soundOff );
06575         }
06576 
06577         if (saberOwner->client->saber[1].soundOff &&
06578                 saberOwner->client->saber[1].model[0])
06579         {
06580                 G_Sound( saberOwner, CHAN_BODY, saberOwner->client->saber[1].soundOff );
06581         }
06582 }

qboolean saberKnockOutOfHand gentity_t saberent,
gentity_t saberOwner,
vec3_t  velocity
 

Definition at line 6611 of file w_saber.c.

References gentity_s::client, entityShared_t::contents, CONTENTS_LIGHTSABER, gentity_s::damage, entityState_s::eFlags, ET_GENERAL, entityState_s::eType, G_SetOrigin(), entityState_s::genericenemyindex, gentity_s::genericValue5, gentity_t, gentity_s::inuse, gclient_s::lastSaberBase_Always, gclient_s::lastSaberStorageTime, level, entityShared_t::maxs, gentity_s::methodOfDeath, entityShared_t::mins, MOD_SABER, saberInfo_t::model, entityState_s::modelGhoul2, entityState_s::number, gentity_s::parent, entityState_s::pos, gclient_s::ps, qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, gclient_s::saber, SABER_THROWN_HIT_DAMAGE, playerState_s::saberEntityNum, playerState_s::saberEntityState, saberInfo_t::saberFlags, entityState_s::saberInFlight, playerState_s::saberInFlight, saberKnockDown(), playerState_s::saberLockTime, SFL_NOT_DISARMABLE, saberInfo_t::skin, entityState_s::solid, gentity_s::splashMethodOfDeath, level_locals_t::time, TR_LINEAR, trajectory_t::trDelta, trajectory_t::trType, vec3_t, VectorCopy, VectorSet, entityState_s::weapon, WP_SABER, and WP_SaberAddG2Model().

Referenced by ClientCommand(), saberCheckKnockdown_BrokenParry(), and saberCheckKnockdown_DuelLoss().

06612 {
06613         if (!saberent || !saberOwner ||
06614                 !saberent->inuse || !saberOwner->inuse ||
06615                 !saberOwner->client)
06616         {
06617                 return qfalse;
06618         }
06619 
06620         if (!saberOwner->client->ps.saberEntityNum)
06621         { //already gone
06622                 return qfalse;
06623         }
06624 
06625         if ((level.time - saberOwner->client->lastSaberStorageTime) > 50)
06626         { //must have a reasonably updated saber base pos
06627                 return qfalse;
06628         }
06629 
06630         if (saberOwner->client->ps.saberLockTime > (level.time-100))
06631         {
06632                 return qfalse;
06633         }
06634         if ( (saberOwner->client->saber[0].saberFlags&SFL_NOT_DISARMABLE) )
06635         {
06636                 return qfalse;
06637         }
06638 
06639         saberOwner->client->ps.saberInFlight = qtrue;
06640         saberOwner->client->ps.saberEntityState = 1;
06641 
06642         saberent->s.saberInFlight = qfalse;//qtrue;
06643 
06644         saberent->s.pos.trType = TR_LINEAR;
06645         saberent->s.eType = ET_GENERAL;
06646         saberent->s.eFlags = 0;
06647 
06648         WP_SaberAddG2Model( saberent, saberOwner->client->saber[0].model, saberOwner->client->saber[0].skin );
06649 
06650         saberent->s.modelGhoul2 = 127;
06651 
06652         saberent->parent = saberOwner;
06653 
06654         saberent->damage = SABER_THROWN_HIT_DAMAGE;
06655         saberent->methodOfDeath = MOD_SABER;
06656         saberent->splashMethodOfDeath = MOD_SABER;
06657         saberent->s.solid = 2;
06658         saberent->r.contents = CONTENTS_LIGHTSABER;
06659 
06660         saberent->genericValue5 = 0;
06661 
06662         VectorSet( saberent->r.mins, -24.0f, -24.0f, -8.0f );
06663         VectorSet( saberent->r.maxs, 24.0f, 24.0f, 8.0f );
06664 
06665         saberent->s.genericenemyindex = saberOwner->s.number+1024;
06666         saberent->s.weapon = WP_SABER;
06667 
06668         saberent->genericValue5 = 0;
06669 
06670         G_SetOrigin(saberent, saberOwner->client->lastSaberBase_Always); //use this as opposed to the right hand bolt,
06671         //because I don't want to risk reconstructing the skel again to get it here. And it isn't worth storing.
06672         saberKnockDown(saberent, saberOwner, saberOwner);
06673         VectorCopy(velocity, saberent->s.pos.trDelta); //override the velocity on the knocked away saber.
06674         
06675         return qtrue;
06676 }

void saberReactivate gentity_t saberent,
gentity_t saberOwner
 

Definition at line 6480 of file w_saber.c.

References entityState_s::apos, gentity_s::client, entityState_s::eFlags, ET_GENERAL, entityState_s::eType, gentity_s::genericValue5, gentity_t, gentity_s::parent, entityState_s::pos, gclient_s::ps, qtrue, gentity_s::s, playerState_s::saberEntityState, entityState_s::saberInFlight, thrownSaberTouch(), gentity_s::touch, TR_LINEAR, trap_LinkEntity(), trajectory_t::trDelta, trajectory_t::trType, entityState_s::weapon, and WP_SABER.

Referenced by DownedSaberThink().

06481 {
06482         saberent->s.saberInFlight = qtrue;
06483 
06484         saberent->s.apos.trType = TR_LINEAR;
06485         saberent->s.apos.trDelta[0] = 0;
06486         saberent->s.apos.trDelta[1] = 800;
06487         saberent->s.apos.trDelta[2] = 0;
06488 
06489         saberent->s.pos.trType = TR_LINEAR;
06490         saberent->s.eType = ET_GENERAL;
06491         saberent->s.eFlags = 0;
06492 
06493         saberent->parent = saberOwner;
06494 
06495         saberent->genericValue5 = 0;
06496 
06497         SetSaberBoxSize(saberent);
06498 
06499         saberent->touch = thrownSaberTouch;
06500 
06501         saberent->s.weapon = WP_SABER;
06502 
06503         saberOwner->client->ps.saberEntityState = 1;
06504 
06505         trap_LinkEntity(saberent);
06506 }

void SaberUpdateSelf gentity_t ent  ) 
 

Definition at line 284 of file w_saber.c.

References BG_SabersOff(), gentity_s::clipmask, entityShared_t::contents, CONTENTS_LIGHTSABER, entityShared_t::currentOrigin, ENTITYNUM_NONE, ET_NPC, FP_SABER_OFFENSE, G_DebugBoxLines(), g_entities, G_FreeEntity(), g_saberDebugBox, g_svfps, gentity_s::genericValue5, gentity_t, vmCvar_t::integer, level, MASK_PLAYERSOLID, entityShared_t::maxs, entityShared_t::mins, gentity_s::nextthink, entityShared_t::ownerNum, PMF_FOLLOW, PROPER_THROWN_VALUE, gentity_s::r, TEAM_SPECTATOR, gentity_s::think, level_locals_t::time, trap_LinkEntity(), vec3_t, VectorAdd, and WP_SABER.

Referenced by DownedSaberThink(), saberBackToOwner(), saberFirstThrown(), WP_SaberInitBladeData(), and WP_SaberPositionUpdate().

00285 {
00286         if (ent->r.ownerNum == ENTITYNUM_NONE)
00287         {
00288                 ent->think = G_FreeEntity;
00289                 ent->nextthink = level.time;
00290                 return;
00291         }
00292 
00293         if (!g_entities[ent->r.ownerNum].inuse ||
00294                 !g_entities[ent->r.ownerNum].client/* ||
00295                 g_entities[ent->r.ownerNum].client->sess.sessionTeam == TEAM_SPECTATOR*/)
00296         {
00297                 ent->think = G_FreeEntity;
00298                 ent->nextthink = level.time;
00299                 return;
00300         }
00301 
00302         if (g_entities[ent->r.ownerNum].client->ps.saberInFlight && g_entities[ent->r.ownerNum].health > 0)
00303         { //let The Master take care of us now (we'll get treated like a missile until we return)
00304                 ent->nextthink = level.time;
00305                 ent->genericValue5 = PROPER_THROWN_VALUE;
00306                 return;
00307         }
00308 
00309         ent->genericValue5 = 0;
00310 
00311         if (g_entities[ent->r.ownerNum].client->ps.weapon != WP_SABER ||
00312                 (g_entities[ent->r.ownerNum].client->ps.pm_flags & PMF_FOLLOW) ||
00313                 //RWW ADDED 7-19-03 BEGIN
00314                 g_entities[ent->r.ownerNum].client->sess.sessionTeam == TEAM_SPECTATOR ||
00315                 g_entities[ent->r.ownerNum].client->tempSpectate >= level.time ||
00316                 //RWW ADDED 7-19-03 END
00317                 g_entities[ent->r.ownerNum].health < 1 ||
00318                 BG_SabersOff( &g_entities[ent->r.ownerNum].client->ps ) ||
00319                 (!g_entities[ent->r.ownerNum].client->ps.fd.forcePowerLevel[FP_SABER_OFFENSE] && g_entities[ent->r.ownerNum].s.eType != ET_NPC))
00320         { //owner is not using saber, spectating, dead, saber holstered, or has no attack level
00321                 ent->r.contents = 0;
00322                 ent->clipmask = 0;
00323         }
00324         else
00325         { //Standard contents (saber is active)
00326 #ifdef DEBUG_SABER_BOX
00327                 if (g_saberDebugBox.integer == 1|| g_saberDebugBox.integer == 4)
00328                 {
00329                         vec3_t dbgMins;
00330                         vec3_t dbgMaxs;
00331 
00332                         VectorAdd( ent->r.currentOrigin, ent->r.mins, dbgMins );
00333                         VectorAdd( ent->r.currentOrigin, ent->r.maxs, dbgMaxs );
00334 
00335                         G_DebugBoxLines(dbgMins, dbgMaxs, (10.0f/(float)g_svfps.integer)*100);
00336                 }
00337 #endif
00338                 if (ent->r.contents != CONTENTS_LIGHTSABER)
00339                 {
00340                         if ((level.time - g_entities[ent->r.ownerNum].client->lastSaberStorageTime) <= 200)
00341                         { //Only go back to solid once we're sure our owner has updated recently
00342                                 ent->r.contents = CONTENTS_LIGHTSABER;
00343                                 ent->clipmask = MASK_PLAYERSOLID | CONTENTS_LIGHTSABER;
00344                         }
00345                 }
00346                 else
00347                 {
00348                         ent->r.contents = CONTENTS_LIGHTSABER;
00349                         ent->clipmask = MASK_PLAYERSOLID | CONTENTS_LIGHTSABER;
00350                 }
00351         }
00352 
00353         trap_LinkEntity(ent);
00354 
00355         ent->nextthink = level.time;
00356 }

void thrownSaberTouch gentity_t saberent,
gentity_t other,
trace_t trace
 

Definition at line 7078 of file w_saber.c.

References entityState_s::apos, entityShared_t::contents, CONTENTS_LIGHTSABER, entityShared_t::currentOrigin, g_entities, gentity_t, level, MAX_CLIENTS, gentity_s::nextthink, entityState_s::number, entityShared_t::ownerNum, entityState_s::pos, qtrue, gentity_s::r, gentity_s::s, saberBackToOwner(), gentity_s::speed, gentity_s::think, level_locals_t::time, TR_LINEAR, trajectory_t::trBase, trajectory_t::trDelta, trajectory_t::trTime, trajectory_t::trType, VectorClear, and VectorCopy.

Referenced by saberFirstThrown(), saberReactivate(), and WP_SaberPositionUpdate().

07079 {
07080         gentity_t *hitEnt = other;
07081 
07082         if (other && other->s.number == saberent->r.ownerNum)
07083         {
07084                 return;
07085         }
07086         VectorClear(saberent->s.pos.trDelta);
07087         saberent->s.pos.trTime = level.time;
07088 
07089         saberent->s.apos.trType = TR_LINEAR;
07090         saberent->s.apos.trDelta[0] = 0;
07091         saberent->s.apos.trDelta[1] = 800;
07092         saberent->s.apos.trDelta[2] = 0;
07093 
07094         VectorCopy(saberent->r.currentOrigin, saberent->s.pos.trBase);
07095 
07096         saberent->think = saberBackToOwner;
07097         saberent->nextthink = level.time;
07098 
07099         if (other && other->r.ownerNum < MAX_CLIENTS &&
07100                 (other->r.contents & CONTENTS_LIGHTSABER) &&
07101                 g_entities[other->r.ownerNum].client &&
07102                 g_entities[other->r.ownerNum].inuse)
07103         {
07104                 hitEnt = &g_entities[other->r.ownerNum];
07105         }
07106 
07107         //we'll skip the dist check, since we don't really care about that (we just hit it physically)
07108         CheckThrownSaberDamaged(saberent, &g_entities[saberent->r.ownerNum], hitEnt, 256, 0, qtrue);
07109 
07110         saberent->speed = 0;
07111 }

qboolean tri_tri_intersect vec3_t  V0,
vec3_t  V1,
vec3_t  V2,
vec3_t  U0,
vec3_t  U1,
vec3_t  U2
 

Definition at line 198 of file tri_coll_test.c.

References COMPUTE_INTERVALS, CROSS, DOT, EPSILON, fabs(), qboolean, qfalse, qtrue, SORT, SUB, and vec3_t.

Referenced by WP_SabersIntersect().

00200 {
00201   vec3_t E1,E2;
00202   vec3_t N1,N2;
00203   float d1,d2;
00204   float du0,du1,du2,dv0,dv1,dv2;
00205   vec3_t D;
00206   float isect1[2], isect2[2];
00207   float du0du1,du0du2,dv0dv1,dv0dv2;
00208   short index;
00209   float vp0,vp1,vp2;
00210   float up0,up1,up2;
00211   float b,c,max;
00212 
00213   /* compute plane equation of triangle(V0,V1,V2) */
00214   SUB(E1,V1,V0);
00215   SUB(E2,V2,V0);
00216   CROSS(N1,E1,E2);
00217   d1=-DOT(N1,V0);
00218   /* plane equation 1: N1.X+d1=0 */
00219 
00220   /* put U0,U1,U2 into plane equation 1 to compute signed distances to the plane*/
00221   du0=DOT(N1,U0)+d1;
00222   du1=DOT(N1,U1)+d1;
00223   du2=DOT(N1,U2)+d1;
00224 
00225   /* coplanarity robustness check */
00226 #if USE_EPSILON_TEST
00227   if(fabs(du0)<EPSILON) du0=0.0;
00228   if(fabs(du1)<EPSILON) du1=0.0;
00229   if(fabs(du2)<EPSILON) du2=0.0;
00230 #endif
00231   du0du1=du0*du1;
00232   du0du2=du0*du2;
00233 
00234   if(du0du1>0.0f && du0du2>0.0f) /* same sign on all of them + not equal 0 ? */
00235     return 0;                    /* no intersection occurs */
00236 
00237   /* compute plane of triangle (U0,U1,U2) */
00238   SUB(E1,U1,U0);
00239   SUB(E2,U2,U0);
00240   CROSS(N2,E1,E2);
00241   d2=-DOT(N2,U0);
00242   /* plane equation 2: N2.X+d2=0 */
00243 
00244   /* put V0,V1,V2 into plane equation 2 */
00245   dv0=DOT(N2,V0)+d2;
00246   dv1=DOT(N2,V1)+d2;
00247   dv2=DOT(N2,V2)+d2;
00248 
00249 #if USE_EPSILON_TEST
00250   if(fabs(dv0)<EPSILON) dv0=0.0;
00251   if(fabs(dv1)<EPSILON) dv1=0.0;
00252   if(fabs(dv2)<EPSILON) dv2=0.0;
00253 #endif
00254 
00255   dv0dv1=dv0*dv1;
00256   dv0dv2=dv0*dv2;
00257         
00258   if(dv0dv1>0.0f && dv0dv2>0.0f) /* same sign on all of them + not equal 0 ? */
00259     return 0;                    /* no intersection occurs */
00260 
00261   /* compute direction of intersection line */
00262   CROSS(D,N1,N2);
00263 
00264   /* compute and index to the largest component of D */
00265   max=fabs(D[0]);
00266   index=0;
00267   b=fabs(D[1]);
00268   c=fabs(D[2]);
00269   if(b>max) max=b,index=1;
00270   if(c>max) max=c,index=2;
00271 
00272         /* this is the simplified projection onto L*/
00273         vp0=V0[index];
00274         vp1=V1[index];
00275         vp2=V2[index];
00276 
00277         up0=U0[index];
00278         up1=U1[index];
00279         up2=U2[index];
00280 
00281   /* compute interval for triangle 1 */
00282   COMPUTE_INTERVALS(vp0,vp1,vp2,dv0,dv1,dv2,dv0dv1,dv0dv2,isect1[0],isect1[1]);
00283 
00284   /* compute interval for triangle 2 */
00285   COMPUTE_INTERVALS(up0,up1,up2,du0,du1,du2,du0du1,du0du2,isect2[0],isect2[1]);
00286 
00287   SORT(isect1[0],isect1[1]);
00288   SORT(isect2[0],isect2[1]);
00289 
00290   if(isect1[1]<isect2[0] || isect2[1]<isect1[0]) return qtrue;
00291   return qfalse;
00292 }

void UpdateClientRenderBolts gentity_t self,
vec3_t  renderOrigin,
vec3_t  renderAngles
 

Definition at line 7257 of file w_saber.c.

References renderInfo_s::boltValidityTime, gentity_s::client, renderInfo_s::crotchBolt, renderInfo_s::crotchPoint, renderInfo_s::footLBolt, renderInfo_s::footLPoint, renderInfo_s::footRBolt, renderInfo_s::footRPoint, gentity_t, gentity_s::ghoul2, renderInfo_s::handLBolt, renderInfo_s::handLPoint, renderInfo_s::handRBolt, renderInfo_s::handRPoint, renderInfo_s::headBolt, renderInfo_s::headPoint, level, mdxaBone_t::matrix, gentity_s::modelScale, NULL, playerState_s::origin, gclient_s::ps, gclient_s::renderInfo, renderInfo_t, level_locals_t::time, renderInfo_s::torsoBolt, renderInfo_s::torsoPoint, trap_G2API_GetBoltMatrix(), vec3_t, and VectorCopy.

Referenced by G_GetHitLocFromSurfName().

07258 {
07259         mdxaBone_t boltMatrix;
07260         renderInfo_t *ri = &self->client->renderInfo;
07261 
07262         if (!self->ghoul2)
07263         {
07264                 VectorCopy(self->client->ps.origin, ri->headPoint);
07265                 VectorCopy(self->client->ps.origin, ri->handRPoint);
07266                 VectorCopy(self->client->ps.origin, ri->handLPoint);
07267                 VectorCopy(self->client->ps.origin, ri->torsoPoint);
07268                 VectorCopy(self->client->ps.origin, ri->crotchPoint);
07269                 VectorCopy(self->client->ps.origin, ri->footRPoint);
07270                 VectorCopy(self->client->ps.origin, ri->footLPoint);
07271         }
07272         else
07273         {
07274                 //head
07275                 trap_G2API_GetBoltMatrix(self->ghoul2, 0, ri->headBolt, &boltMatrix, renderAngles, renderOrigin, level.time, NULL, self->modelScale);
07276                 ri->headPoint[0] = boltMatrix.matrix[0][3];
07277                 ri->headPoint[1] = boltMatrix.matrix[1][3];
07278                 ri->headPoint[2] = boltMatrix.matrix[2][3];
07279 
07280                 //right hand
07281                 trap_G2API_GetBoltMatrix(self->ghoul2, 0, ri->handRBolt, &boltMatrix, renderAngles, renderOrigin, level.time, NULL, self->modelScale);
07282                 ri->handRPoint[0] = boltMatrix.matrix[0][3];
07283                 ri->handRPoint[1] = boltMatrix.matrix[1][3];
07284                 ri->handRPoint[2] = boltMatrix.matrix[2][3];
07285 
07286                 //left hand
07287                 trap_G2API_GetBoltMatrix(self->ghoul2, 0, ri->handLBolt, &boltMatrix, renderAngles, renderOrigin, level.time, NULL, self->modelScale);
07288                 ri->handLPoint[0] = boltMatrix.matrix[0][3];
07289                 ri->handLPoint[1] = boltMatrix.matrix[1][3];
07290                 ri->handLPoint[2] = boltMatrix.matrix[2][3];
07291 
07292                 //chest
07293                 trap_G2API_GetBoltMatrix(self->ghoul2, 0, ri->torsoBolt, &boltMatrix, renderAngles, renderOrigin, level.time, NULL, self->modelScale);
07294                 ri->torsoPoint[0] = boltMatrix.matrix[0][3];
07295                 ri->torsoPoint[1] = boltMatrix.matrix[1][3];
07296                 ri->torsoPoint[2] = boltMatrix.matrix[2][3];
07297 
07298                 //crotch
07299                 trap_G2API_GetBoltMatrix(self->ghoul2, 0, ri->crotchBolt, &boltMatrix, renderAngles, renderOrigin, level.time, NULL, self->modelScale);
07300                 ri->crotchPoint[0] = boltMatrix.matrix[0][3];
07301                 ri->crotchPoint[1] = boltMatrix.matrix[1][3];
07302                 ri->crotchPoint[2] = boltMatrix.matrix[2][3];
07303 
07304                 //right foot
07305                 trap_G2API_GetBoltMatrix(self->ghoul2, 0, ri->footRBolt, &boltMatrix, renderAngles, renderOrigin, level.time, NULL, self->modelScale);
07306                 ri->footRPoint[0] = boltMatrix.matrix[0][3];
07307                 ri->footRPoint[1] = boltMatrix.matrix[1][3];
07308                 ri->footRPoint[2] = boltMatrix.matrix[2][3];
07309 
07310                 //left foot
07311                 trap_G2API_GetBoltMatrix(self->ghoul2, 0, ri->footLBolt, &boltMatrix, renderAngles, renderOrigin, level.time, NULL, self->modelScale);
07312                 ri->footLPoint[0] = boltMatrix.matrix[0][3];
07313                 ri->footLPoint[1] = boltMatrix.matrix[1][3];
07314                 ri->footLPoint[2] = boltMatrix.matrix[2][3];
07315         }
07316 
07317         self->client->renderInfo.boltValidityTime = level.time;
07318 }

void UpdateClientRenderinfo gentity_t self,
vec3_t  renderOrigin,
vec3_t  renderAngles
 

Definition at line 7320 of file w_saber.c.

References AngleVectors(), bgAllAnims, gentity_s::client, renderInfo_s::crotchBolt, renderInfo_s::crotchPoint, renderInfo_s::customAlpha, renderInfo_s::customRGB, renderInfo_s::eyeAngles, renderInfo_s::eyePoint, renderInfo_s::footLBolt, renderInfo_s::footLPoint, renderInfo_s::footRBolt, renderInfo_s::footRPoint, g_debugServerSkel, G_TestLine(), gentity_t, gentity_s::ghoul2, renderInfo_s::handLBolt, renderInfo_s::handLPoint, renderInfo_s::handRBolt, renderInfo_s::handRPoint, renderInfo_s::headAngles, renderInfo_s::headBolt, renderInfo_s::headPitchRangeDown, renderInfo_s::headPitchRangeUp, renderInfo_s::headPoint, renderInfo_s::headYawRangeLeft, renderInfo_s::headYawRangeRight, vmCvar_t::integer, renderInfo_s::lastG2, playerState_s::legsAnim, renderInfo_s::legsFpsMod, renderInfo_s::legsFrame, renderInfo_s::legsYaw, level, gentity_s::localAnimIndex, renderInfo_s::lockYaw, mdxaBone_t::matrix, gentity_s::modelScale, renderInfo_s::motionBolt, renderInfo_s::mPCalcTime, renderInfo_s::muzzleDir, renderInfo_s::muzzleDirOld, renderInfo_s::muzzlePoint, renderInfo_s::muzzlePointOld, NULL, playerState_s::origin, gclient_s::ps, renderInfo_s::renderFlags, gclient_s::renderInfo, renderInfo_t, level_locals_t::time, renderInfo_s::torsoAngles, playerState_s::torsoAnim, renderInfo_s::torsoBolt, renderInfo_s::torsoFpsMod, renderInfo_s::torsoFrame, renderInfo_s::torsoPitchRangeDown, renderInfo_s::torsoPitchRangeUp, renderInfo_s::torsoPoint, renderInfo_s::torsoYawRangeLeft, renderInfo_s::torsoYawRangeRight, trap_G2API_AddBolt(), trap_G2API_GetBoltMatrix(), vec3_t, VectorClear, VectorCopy, playerState_s::viewangles, and playerState_s::viewheight.

Referenced by WP_SaberPositionUpdate().

07321 {
07322         renderInfo_t *ri = &self->client->renderInfo;
07323         if ( ri->mPCalcTime < level.time )
07324         {
07325                 //We're just going to give rough estimates on most of this stuff,
07326                 //it's not like most of it matters.
07327 
07328         #if 0 //#if 0'd since it's a waste setting all this to 0 each frame.
07329                 //Should you wish to make any of this valid then feel free to do so.
07330                 ri->headYawRangeLeft = ri->headYawRangeRight = ri->headPitchRangeUp = ri->headPitchRangeDown = 0;
07331                 ri->torsoYawRangeLeft = ri->torsoYawRangeRight = ri->torsoPitchRangeUp = ri->torsoPitchRangeDown = 0;
07332 
07333                 ri->torsoFpsMod = ri->legsFpsMod = 0;
07334 
07335                 VectorClear(ri->customRGB);
07336                 ri->customAlpha = 0;
07337                 ri->renderFlags = 0;
07338                 ri->lockYaw = 0;
07339 
07340                 VectorClear(ri->headAngles);
07341                 VectorClear(ri->torsoAngles);
07342 
07343                 //VectorClear(ri->eyeAngles);
07344 
07345                 ri->legsYaw = 0;
07346         #endif
07347 
07348                 if (self->ghoul2 &&
07349                         self->ghoul2 != ri->lastG2)
07350                 { //the g2 instance changed, so update all the bolts.
07351                         //rwwFIXMEFIXME: Base on skeleton used? Assuming humanoid currently.
07352                         ri->lastG2 = self->ghoul2;
07353 
07354                         if (self->localAnimIndex <= 1)
07355                         {
07356                                 ri->headBolt = trap_G2API_AddBolt(self->ghoul2, 0, "*head_eyes");
07357                                 ri->handRBolt = trap_G2API_AddBolt(self->ghoul2, 0, "*r_hand");
07358                                 ri->handLBolt = trap_G2API_AddBolt(self->ghoul2, 0, "*l_hand");
07359                                 ri->torsoBolt = trap_G2API_AddBolt(self->ghoul2, 0, "thoracic");
07360                                 ri->crotchBolt = trap_G2API_AddBolt(self->ghoul2, 0, "pelvis");
07361                                 ri->footRBolt = trap_G2API_AddBolt(self->ghoul2, 0, "*r_leg_foot");
07362                                 ri->footLBolt = trap_G2API_AddBolt(self->ghoul2, 0, "*l_leg_foot");
07363                                 ri->motionBolt = trap_G2API_AddBolt(self->ghoul2, 0, "Motion");
07364                         }
07365                         else
07366                         {
07367                                 ri->headBolt = -1;
07368                                 ri->handRBolt = -1;
07369                                 ri->handLBolt = -1;
07370                                 ri->torsoBolt = -1;
07371                                 ri->crotchBolt = -1;
07372                                 ri->footRBolt = -1;
07373                                 ri->footLBolt = -1;
07374                                 ri->motionBolt = -1;
07375                         }
07376 
07377                         ri->lastG2 = self->ghoul2;
07378                 }
07379 
07380                 VectorCopy( self->client->ps.viewangles, self->client->renderInfo.eyeAngles );
07381 
07382                 //we'll just say the legs/torso are whatever the first frame of our current anim is.
07383                 ri->torsoFrame = bgAllAnims[self->localAnimIndex].anims[self->client->ps.torsoAnim].firstFrame;
07384                 ri->legsFrame = bgAllAnims[self->localAnimIndex].anims[self->client->ps.legsAnim].firstFrame;
07385                 if (g_debugServerSkel.integer)
07386                 {       //Alright, I was doing this, but it's just too slow to do every frame.
07387                         //From now on if we want this data to be valid we're going to have to make a verify call for it before
07388                         //accessing it. I'm only doing this now if we want to debug the server skel by drawing lines from bolt
07389                         //positions every frame.
07390                         mdxaBone_t boltMatrix;
07391 
07392                         if (!self->ghoul2)
07393                         {
07394                                 VectorCopy(self->client->ps.origin, ri->headPoint);
07395                                 VectorCopy(self->client->ps.origin, ri->handRPoint);
07396                                 VectorCopy(self->client->ps.origin, ri->handLPoint);
07397                                 VectorCopy(self->client->ps.origin, ri->torsoPoint);
07398                                 VectorCopy(self->client->ps.origin, ri->crotchPoint);
07399                                 VectorCopy(self->client->ps.origin, ri->footRPoint);
07400                                 VectorCopy(self->client->ps.origin, ri->footLPoint);
07401                         }
07402                         else
07403                         {
07404                                 //head
07405                                 trap_G2API_GetBoltMatrix(self->ghoul2, 0, ri->headBolt, &boltMatrix, renderAngles, renderOrigin, level.time, NULL, self->modelScale);
07406                                 ri->headPoint[0] = boltMatrix.matrix[0][3];
07407                                 ri->headPoint[1] = boltMatrix.matrix[1][3];
07408                                 ri->headPoint[2] = boltMatrix.matrix[2][3];
07409 
07410                                 //right hand
07411                                 trap_G2API_GetBoltMatrix(self->ghoul2, 0, ri->handRBolt, &boltMatrix, renderAngles, renderOrigin, level.time, NULL, self->modelScale);
07412                                 ri->handRPoint[0] = boltMatrix.matrix[0][3];
07413                                 ri->handRPoint[1] = boltMatrix.matrix[1][3];
07414                                 ri->handRPoint[2] = boltMatrix.matrix[2][3];
07415 
07416                                 //left hand
07417                                 trap_G2API_GetBoltMatrix(self->ghoul2, 0, ri->handLBolt, &boltMatrix, renderAngles, renderOrigin, level.time, NULL, self->modelScale);
07418                                 ri->handLPoint[0] = boltMatrix.matrix[0][3];
07419                                 ri->handLPoint[1] = boltMatrix.matrix[1][3];
07420                                 ri->handLPoint[2] = boltMatrix.matrix[2][3];
07421 
07422                                 //chest
07423                                 trap_G2API_GetBoltMatrix(self->ghoul2, 0, ri->torsoBolt, &boltMatrix, renderAngles, renderOrigin, level.time, NULL, self->modelScale);
07424                                 ri->torsoPoint[0] = boltMatrix.matrix[0][3];
07425                                 ri->torsoPoint[1] = boltMatrix.matrix[1][3];
07426                                 ri->torsoPoint[2] = boltMatrix.matrix[2][3];
07427 
07428                                 //crotch
07429                                 trap_G2API_GetBoltMatrix(self->ghoul2, 0, ri->crotchBolt, &boltMatrix, renderAngles, renderOrigin, level.time, NULL, self->modelScale);
07430                                 ri->crotchPoint[0] = boltMatrix.matrix[0][3];
07431                                 ri->crotchPoint[1] = boltMatrix.matrix[1][3];
07432                                 ri->crotchPoint[2] = boltMatrix.matrix[2][3];
07433 
07434                                 //right foot
07435                                 trap_G2API_GetBoltMatrix(self->ghoul2, 0, ri->footRBolt, &boltMatrix, renderAngles, renderOrigin, level.time, NULL, self->modelScale);
07436                                 ri->footRPoint[0] = boltMatrix.matrix[0][3];
07437                                 ri->footRPoint[1] = boltMatrix.matrix[1][3];
07438                                 ri->footRPoint[2] = boltMatrix.matrix[2][3];
07439 
07440                                 //left foot
07441                                 trap_G2API_GetBoltMatrix(self->ghoul2, 0, ri->footLBolt, &boltMatrix, renderAngles, renderOrigin, level.time, NULL, self->modelScale);
07442                                 ri->footLPoint[0] = boltMatrix.matrix[0][3];
07443                                 ri->footLPoint[1] = boltMatrix.matrix[1][3];
07444                                 ri->footLPoint[2] = boltMatrix.matrix[2][3];
07445                         }
07446 
07447                         //Now draw the skel for debug
07448                         G_TestLine(ri->headPoint, ri->torsoPoint, 0x000000ff, 50);
07449                         G_TestLine(ri->torsoPoint, ri->handRPoint, 0x000000ff, 50);
07450                         G_TestLine(ri->torsoPoint, ri->handLPoint, 0x000000ff, 50);
07451                         G_TestLine(ri->torsoPoint, ri->crotchPoint, 0x000000ff, 50);
07452                         G_TestLine(ri->crotchPoint, ri->footRPoint, 0x000000ff, 50);
07453                         G_TestLine(ri->crotchPoint, ri->footLPoint, 0x000000ff, 50);
07454                 }
07455 
07456                 //muzzle point calc (we are going to be cheap here)
07457                 VectorCopy(ri->muzzlePoint, ri->muzzlePointOld);
07458                 VectorCopy(self->client->ps.origin, ri->muzzlePoint);
07459                 VectorCopy(ri->muzzleDir, ri->muzzleDirOld);
07460                 AngleVectors(self->client->ps.viewangles, ri->muzzleDir, 0, 0);
07461                 ri->mPCalcTime = level.time;
07462 
07463                 VectorCopy(self->client->ps.origin, ri->eyePoint);
07464                 ri->eyePoint[2] += self->client->ps.viewheight;
07465         }
07466 }

GAME_INLINE int VectorCompare2 const vec3_t  v1,
const vec3_t  v2
 

Definition at line 5273 of file w_saber.c.

References GAME_INLINE, and vec3_t.

Referenced by G_SPSaberDamageTraceLerped().

05273                                                                    {
05274         if ( v1[0] > v2[0]+0.0001f || v1[0] < v2[0]-0.0001f
05275                 || v1[1] > v2[1]+0.0001f || v1[1] < v2[1]-0.0001f
05276                 || v1[2] > v2[2]+0.0001f || v1[2] < v2[2]-0.0001f ) {
05277                 return 0;
05278         }                       
05279         return 1;
05280 }

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_ForcePowerUsable gentity_t self,
forcePowers_t  forcePower
 

Definition at line 813 of file w_force.c.

References BG_CanUseFPNow(), BG_HasYsalamiri(), gentity_s::client, EF_DEAD, playerState_s::eFlags, playerState_s::fd, gclient_s::fjDidJump, forcedata_s::forcePowerLevel, forcePowers_t, forcedata_s::forcePowersActive, forcedata_s::forcePowersKnown, saberInfo_t::forceRestrictions, FP_DRAIN, FP_GRIP, FP_LEVITATION, FP_LIGHTNING, FP_PULL, FP_PUSH, FP_SABER_DEFENSE, FP_SABER_OFFENSE, FP_SABERTHROW, FP_TELEPATHY, g_debugMelee, g_gametype, g_saberRestrictForce, gentity_t, gentity_s::health, vmCvar_t::integer, level, saberInfo_t::model, playerState_s::pm_flags, PMF_FOLLOW, PMF_STUCK_TO_WALL, gclient_s::ps, qboolean, qfalse, gclient_s::saber, saberInfo_t::saberFlags, playerState_s::saberHolstered, gclient_s::sess, clientSession_t::sessionTeam, SFL_TWO_HANDED, STAT_HEALTH, playerState_s::stats, TEAM_SPECTATOR, gclient_s::tempSpectate, level_locals_t::time, and WP_ForcePowerAvailable().

Referenced by CanCounterThrow(), ForceAbsorb(), ForceDrain(), ForceGrip(), ForceHeal(), ForceJump(), ForceLightning(), ForceProtect(), ForceRage(), ForceSeeing(), ForceSpeed(), ForceTeamForceReplenish(), ForceTeamHeal(), ForceTelepathy(), ForceThrow(), Jedi_DodgeEvasion(), and WP_SaberStartMissileBlockCheck().

00814 {
00815         if (BG_HasYsalamiri(g_gametype.integer, &self->client->ps))
00816         {
00817                 return qfalse;
00818         }
00819 
00820         if (self->health <= 0 || self->client->ps.stats[STAT_HEALTH] <= 0 ||
00821                 (self->client->ps.eFlags & EF_DEAD))
00822         {
00823                 return qfalse;
00824         }
00825 
00826         if (self->client->ps.pm_flags & PMF_FOLLOW)
00827         { //specs can't use powers through people
00828                 return qfalse;
00829         }
00830         if (self->client->sess.sessionTeam == TEAM_SPECTATOR)
00831         {
00832                 return qfalse;
00833         }
00834         if (self->client->tempSpectate >= level.time)
00835         {
00836                 return qfalse;
00837         }
00838 
00839         if (!BG_CanUseFPNow(g_gametype.integer, &self->client->ps, level.time, forcePower))
00840         {
00841                 return qfalse;
00842         }
00843 
00844         if ( !(self->client->ps.fd.forcePowersKnown & ( 1 << forcePower )) )
00845         {//don't know this power
00846                 return qfalse;
00847         }
00848         
00849         if ( (self->client->ps.fd.forcePowersActive & ( 1 << forcePower )) )
00850         {//already using this power
00851                 if (forcePower != FP_LEVITATION)
00852                 {
00853                         return qfalse;
00854                 }
00855         }
00856 
00857         if (forcePower == FP_LEVITATION && self->client->fjDidJump)
00858         {
00859                 return qfalse;
00860         }
00861 
00862         if (!self->client->ps.fd.forcePowerLevel[forcePower])
00863         {
00864                 return qfalse;
00865         }
00866 
00867         if ( g_debugMelee.integer )
00868         {
00869                 if ( (self->client->ps.pm_flags&PMF_STUCK_TO_WALL) )
00870                 {//no offensive force powers when stuck to wall
00871                         switch ( forcePower )
00872                         {
00873                         case FP_GRIP:
00874                         case FP_LIGHTNING:
00875                         case FP_DRAIN:
00876                         case FP_SABER_OFFENSE:
00877                         case FP_SABER_DEFENSE:
00878                         case FP_SABERTHROW:
00879                                 return qfalse;
00880                                 break;
00881                         }
00882                 }
00883         }
00884 
00885         if ( !self->client->ps.saberHolstered )
00886         {
00887                 if ( (self->client->saber[0].saberFlags&SFL_TWO_HANDED) )
00888                 {
00889                         if ( g_saberRestrictForce.integer )
00890                         {
00891                                 switch ( forcePower )
00892                                 {
00893                                 case FP_PUSH:
00894                                 case FP_PULL:
00895                                 case FP_TELEPATHY:
00896                                 case FP_GRIP:
00897                                 case FP_LIGHTNING:
00898                                 case FP_DRAIN:
00899                                         return qfalse;
00900                                         break;
00901                                 }
00902                         }
00903                 }
00904 
00905                 if ( (self->client->saber[0].saberFlags&SFL_TWO_HANDED)
00906                         || (self->client->saber[0].model && self->client->saber[0].model[0]) )
00907                 {//this saber requires the use of two hands OR our other hand is using an active saber too
00908                         if ( (self->client->saber[0].forceRestrictions&(1<<forcePower)) )
00909                         {//this power is verboten when using this saber
00910                                 return qfalse;
00911                         }
00912                 }
00913 
00914                 if ( self->client->saber[0].model 
00915                         && self->client->saber[0].model[0] )
00916                 {//both sabers on
00917                         if ( g_saberRestrictForce.integer )
00918                         {
00919                                 switch ( forcePower )
00920                                 {
00921                                 case FP_PUSH:
00922                                 case FP_PULL:
00923                                 case FP_TELEPATHY:
00924                                 case FP_GRIP:
00925                                 case FP_LIGHTNING:
00926                                 case FP_DRAIN:
00927                                         return qfalse;
00928                                         break;
00929                                 }
00930                         }
00931                         if ( (self->client->saber[1].forceRestrictions&(1<<forcePower)) )
00932                         {//this power is verboten when using this saber
00933                                 return qfalse;
00934                         }
00935                 }
00936         }
00937         return WP_ForcePowerAvailable( self, forcePower, 0 );   // OVERRIDEFIXME
00938 }

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_SaberAddG2Model gentity_t saberent,
const char *  saberModel,
qhandle_t  saberSkin
 

Referenced by MakeDeadSaber(), saberKnockDown(), saberKnockOutOfHand(), ThrowSaberToAttacker(), and WP_SaberPositionUpdate().

void WP_SaberApplyDamage gentity_t self  ) 
 

Definition at line 3575 of file w_saber.c.

References gentity_s::client, DAMAGE_NO_DISMEMBER, G_Damage(), g_entities, g_saberWallDamageScale, gentity_t, MOD_SABER, NULL, and vmCvar_t::value.

Referenced by WP_SaberPositionUpdate().

03576 {
03577         int i;
03578         if ( !numVictims )
03579         {
03580                 return;
03581         }
03582         for ( i = 0; i < numVictims; i++ )
03583         {
03584                 gentity_t *victim = NULL;
03585                 int dflags = 0;
03586 
03587                 victim = &g_entities[victimEntityNum[i]];
03588 
03589 // nmckenzie: SABER_DAMAGE_WALLS
03590                 if ( !victim->client )
03591                 {
03592                         totalDmg[i] *= g_saberWallDamageScale.value;
03593                 }
03594 
03595                 if ( !dismemberDmg[i] )
03596                 {//don't do dismemberment!
03597                         dflags |= DAMAGE_NO_DISMEMBER;
03598                 }
03599                 dflags |= saberKnockbackFlags[i];
03600 
03601                 G_Damage( victim, self, self, dmgDir[i], dmgSpot[i], totalDmg[i], dflags, MOD_SABER );
03602         }
03603 }

qboolean WP_SaberBladeDoTransitionDamage saberInfo_t saber,
int  bladeNum
 

Definition at line 230 of file bg_saberLoad.c.

References qboolean, qfalse, qtrue, saberInfo_t::saberFlags2, SFL2_TRANSITION_DAMAGE, SFL2_TRANSITION_DAMAGE2, and WP_SaberBladeUseSecondBladeStyle().

00231 {
00232         if ( !WP_SaberBladeUseSecondBladeStyle( saber, bladeNum )
00233                 && (saber->saberFlags2&SFL2_TRANSITION_DAMAGE) )
00234         {//use first blade style for this blade
00235                 return qtrue;
00236         }
00237         else if ( WP_SaberBladeUseSecondBladeStyle( saber, bladeNum )
00238                 && (saber->saberFlags2&SFL2_TRANSITION_DAMAGE2) )
00239         {//use second blade style for this blade
00240                 return qtrue;
00241         }
00242         return qfalse;
00243 }

float WP_SaberBladeLength saberInfo_t saber  ) 
 

Definition at line 2777 of file w_saber.c.

References saberInfo_t::blade, bladeInfo_t::lengthMax, and saberInfo_t::numBlades.

Referenced by WP_SaberLength().

02778 {//return largest length
02779         int     i;
02780         float len = 0.0f;
02781         for ( i = 0; i < saber->numBlades; i++ )
02782         {
02783                 if ( saber->blade[i].lengthMax > len )
02784                 {
02785                         len = saber->blade[i].lengthMax; 
02786                 }
02787         }
02788         return len;
02789 }

qboolean WP_SaberBladeUseSecondBladeStyle saberInfo_t saber,
int  bladeNum
 

Definition at line 215 of file bg_saberLoad.c.

References saberInfo_t::bladeStyle2Start, qboolean, qfalse, and qtrue.

Referenced by CG_AddSaberBlade(), CG_EntityEvent(), CG_SaberCompWork(), WP_SaberBladeDoTransitionDamage(), WP_SaberBounceSound(), and WP_SaberDoHit().

00216 {
00217         if ( saber )
00218         {
00219                 if ( saber->bladeStyle2Start > 0 )
00220                 {
00221                         if ( bladeNum >= saber->bladeStyle2Start )
00222                         {
00223                                 return qtrue;
00224                         }
00225                 }
00226         }
00227         return qfalse;
00228 }

void WP_SaberBlock gentity_t playerent,
vec3_t  hitloc,
qboolean  missileBlock
 

Definition at line 9195 of file w_saber.c.

References AngleVectors(), BLOCKED_LOWER_LEFT, BLOCKED_LOWER_RIGHT, BLOCKED_TOP, BLOCKED_UPPER_LEFT, BLOCKED_UPPER_RIGHT, gentity_s::client, DotProduct, gentity_t, NULL, playerState_s::origin, gclient_s::ps, Q_irand(), RandFloat(), playerState_s::saberBlocked, vec3_t, VectorNormalize(), VectorSubtract, playerState_s::viewangles, and WP_MissileBlockForBlock().

09196 {
09197         vec3_t diff, fwdangles={0,0,0}, right;
09198         float rightdot;
09199         float zdiff;
09200 
09201         VectorSubtract(hitloc, playerent->client->ps.origin, diff);
09202         VectorNormalize(diff);
09203 
09204         fwdangles[1] = playerent->client->ps.viewangles[1];
09205         // Ultimately we might care if the shot was ahead or behind, but for now, just quadrant is fine.
09206         AngleVectors( fwdangles, NULL, right, NULL );
09207 
09208         rightdot = DotProduct(right, diff) + RandFloat(-0.2f,0.2f);
09209         zdiff = hitloc[2] - playerent->client->ps.origin[2] + Q_irand(-8,8);
09210         
09211         // Figure out what quadrant the block was in.
09212         if (zdiff > 24)
09213         {       // Attack from above
09214                 if (Q_irand(0,1))
09215                 {
09216                         playerent->client->ps.saberBlocked = BLOCKED_TOP;
09217                 }
09218                 else
09219                 {
09220                         playerent->client->ps.saberBlocked = BLOCKED_UPPER_LEFT;
09221                 }
09222         }
09223         else if (zdiff > 13)
09224         {       // The upper half has three viable blocks...
09225                 if (rightdot > 0.25)
09226                 {       // In the right quadrant...
09227                         if (Q_irand(0,1))
09228                         {
09229                                 playerent->client->ps.saberBlocked = BLOCKED_UPPER_LEFT;
09230                         }
09231                         else
09232                         {
09233                                 playerent->client->ps.saberBlocked = BLOCKED_LOWER_LEFT;
09234                         }
09235                 }
09236                 else
09237                 {
09238                         switch(Q_irand(0,3))
09239                         {
09240                         case 0:
09241                                 playerent->client->ps.saberBlocked = BLOCKED_UPPER_RIGHT;
09242                                 break;
09243                         case 1:
09244                         case 2:
09245                                 playerent->client->ps.saberBlocked = BLOCKED_LOWER_RIGHT;
09246                                 break;
09247                         case 3:
09248                                 playerent->client->ps.saberBlocked = BLOCKED_TOP;
09249                                 break;
09250                         }
09251                 }
09252         }
09253         else
09254         {       // The lower half is a bit iffy as far as block coverage.  Pick one of the "low" ones at random.
09255                 if (Q_irand(0,1))
09256                 {
09257                         playerent->client->ps.saberBlocked = BLOCKED_LOWER_RIGHT;
09258                 }
09259                 else
09260                 {
09261                         playerent->client->ps.saberBlocked = BLOCKED_LOWER_LEFT;
09262                 }
09263         }
09264 
09265         if ( missileBlock )
09266         {
09267                 playerent->client->ps.saberBlocked = WP_MissileBlockForBlock( playerent->client->ps.saberBlocked );
09268         }
09269 }

void WP_SaberBlockNonRandom gentity_t self,
vec3_t  hitloc,
qboolean  missileBlock
 

Referenced by G_MissileImpact(), WP_SaberCanBlock(), and WP_SaberStartMissileBlockCheck().

void WP_SaberBounceSound gentity_t ent,
int  saberNum,
int  bladeNum
 

Definition at line 3810 of file w_saber.c.

References saberInfo_t::block2Sound, saberInfo_t::blockSound, saberInfo_t::bounce2Sound, saberInfo_t::bounceSound, CHAN_AUTO, gentity_s::client, G_Sound(), G_SoundIndex(), gentity_t, Q_irand(), gclient_s::saber, va(), and WP_SaberBladeUseSecondBladeStyle().

03811 {
03812         int index = 1;
03813         if ( !ent || !ent->client )
03814         {
03815                 return;
03816         }
03817         index = Q_irand( 1, 9 );
03818         if ( !WP_SaberBladeUseSecondBladeStyle( &ent->client->saber[saberNum], bladeNum )
03819                 && ent->client->saber[saberNum].bounceSound[0] )
03820         {
03821                 G_Sound( ent, CHAN_AUTO, ent->client->saber[saberNum].bounceSound[Q_irand( 0, 2 )] );
03822         }
03823         else if ( WP_SaberBladeUseSecondBladeStyle( &ent->client->saber[saberNum], bladeNum )
03824                 && ent->client->saber[saberNum].bounce2Sound[0] )
03825         {
03826                 G_Sound( ent, CHAN_AUTO, ent->client->saber[saberNum].bounce2Sound[Q_irand( 0, 2 )] );
03827         }
03828         else if ( !WP_SaberBladeUseSecondBladeStyle( &ent->client->saber[saberNum], bladeNum )
03829                 && ent->client->saber[saberNum].blockSound[0] )
03830         {
03831                 G_Sound( ent, CHAN_AUTO, ent->client->saber[saberNum].blockSound[Q_irand( 0, 2 )] );
03832         }
03833         else if ( WP_SaberBladeUseSecondBladeStyle( &ent->client->saber[saberNum], bladeNum )
03834                 && ent->client->saber[saberNum].block2Sound[0] )
03835         {
03836                 G_Sound( ent, CHAN_AUTO, ent->client->saber[saberNum].block2Sound[Q_irand( 0, 2 )] );
03837         }
03838         else
03839         {       
03840                 G_Sound( ent, CHAN_AUTO, G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", index ) ) );
03841         }
03842 }

int WP_SaberCanBlock gentity_t self,
vec3_t  point,
int  dflags,
int  mod,
qboolean  projectile,
int  attackStr
 

Definition at line 9271 of file w_saber.c.

References BG_SaberInAttack(), BG_SabersOff(), BUTTON_ATTACK, usercmd_s::buttons, gentity_s::client, clientPersistant_t::cmd, d_saberGhoul2Collision, playerState_s::fd, FORCE_LEVEL_1, FORCE_LEVEL_2, FORCE_LEVEL_3, playerState_s::forceHandExtend, forcedata_s::forcePowerLevel, FP_SABER_DEFENSE, gentity_t, HANDEXTEND_NONE, InFront(), vmCvar_t::integer, level, LS_NONE, LS_PARRY_UP, LS_READY, LS_REFLECT_LL, playerState_s::origin, gclient_s::pers, PM_InSaberAnim(), PM_SaberInBrokenParry(), gclient_s::ps, qboolean, qfalse, qtrue, playerState_s::saberBlocked, playerState_s::saberBlocking, playerState_s::saberBlockTime, playerState_s::saberEntityNum, playerState_s::saberInFlight, playerState_s::saberMove, level_locals_t::time, playerState_s::torsoAnim, vec3_t, playerState_s::viewangles, playerState_s::weapon, WEAPON_RAISING, playerState_s::weaponstate, WP_SABER, and WP_SaberBlockNonRandom().

Referenced by G_MissileImpact(), and WP_DisruptorAltFire().

09272 {
09273         qboolean thrownSaber = qfalse;
09274         float blockFactor = 0;
09275 
09276         if (!self || !self->client || !point)
09277         {
09278                 return 0;
09279         }
09280 
09281         if (attackStr == 999)
09282         {
09283                 attackStr = 0;
09284                 thrownSaber = qtrue;
09285         }
09286 
09287         if (BG_SaberInAttack(self->client->ps.saberMove))
09288         {
09289                 return 0;
09290         }
09291 
09292         if (PM_InSaberAnim(self->client->ps.torsoAnim) && !self->client->ps.saberBlocked &&
09293                 self->client->ps.saberMove != LS_READY && self->client->ps.saberMove != LS_NONE)
09294         {
09295                 if ( self->client->ps.saberMove < LS_PARRY_UP || self->client->ps.saberMove > LS_REFLECT_LL )
09296                 {
09297                         return 0;
09298                 }
09299         }
09300 
09301         if (PM_SaberInBrokenParry(self->client->ps.saberMove))
09302         {
09303                 return 0;
09304         }
09305 
09306         if (!self->client->ps.saberEntityNum)
09307         { //saber is knocked away
09308                 return 0;
09309         }
09310 
09311         if (BG_SabersOff( &self->client->ps ))
09312         {
09313                 return 0;
09314         }
09315 
09316         if (self->client->ps.weapon != WP_SABER)
09317         {
09318                 return 0;
09319         }
09320 
09321         if (self->client->ps.weaponstate == WEAPON_RAISING)
09322         {
09323                 return 0;
09324         }
09325 
09326         if (self->client->ps.saberInFlight)
09327         {
09328                 return 0;
09329         }
09330 
09331         if ((self->client->pers.cmd.buttons & BUTTON_ATTACK)/* &&
09332                 (projectile || attackStr == FORCE_LEVEL_3)*/)
09333         { //don't block when the player is trying to slash, if it's a projectile or he's doing a very strong attack
09334                 return 0;
09335         }
09336 
09337         //Removed this for now, the new broken parry stuff should handle it. This is how
09338         //blocks were decided before the 1.03 patch (as you can see, it was STUPID.. for the most part)
09339         /*
09340         if (attackStr == FORCE_LEVEL_3)
09341         {
09342                 if (self->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE] >= FORCE_LEVEL_3)
09343                 {
09344                         if (Q_irand(1, 10) < 3)
09345                         {
09346                                 return 0;
09347                         }
09348                 }
09349                 else
09350                 {
09351                         return 0;
09352                 }
09353         }
09354 
09355         if (attackStr == FORCE_LEVEL_2 && Q_irand(1, 10) < 3)
09356         {
09357                 if (self->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE] >= FORCE_LEVEL_3)
09358                 {
09359                         //do nothing for now
09360                 }
09361                 else if (self->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE] >= FORCE_LEVEL_2)
09362                 {
09363                         if (Q_irand(1, 10) < 5)
09364                         {
09365                                 return 0;
09366                         }
09367                 }
09368                 else
09369                 {
09370                         return 0;
09371                 }
09372         }
09373         
09374         if (attackStr == FORCE_LEVEL_1 && !self->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE] &&
09375                 Q_irand(1, 40) < 3)
09376         { //if I have no defense level at all then I might be unable to block a level 1 attack (but very rarely)
09377                 return 0;
09378         }
09379         */
09380 
09381         if (SaberAttacking(self))
09382         { //attacking, can't block now
09383                 return 0;
09384         }
09385 
09386         if (self->client->ps.saberMove != LS_READY &&
09387                 !self->client->ps.saberBlocking)
09388         {
09389                 return 0;
09390         }
09391 
09392         if (self->client->ps.saberBlockTime >= level.time)
09393         {
09394                 return 0;
09395         }
09396 
09397         if (self->client->ps.forceHandExtend != HANDEXTEND_NONE)
09398         {
09399                 return 0;
09400         }
09401 
09402         if (self->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE] == FORCE_LEVEL_3)
09403         {
09404                 if (d_saberGhoul2Collision.integer)
09405                 {
09406                         blockFactor = 0.3f;
09407                 }
09408                 else
09409                 {
09410                         blockFactor = 0.05f;
09411                 }
09412         }
09413         else if (self->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE] == FORCE_LEVEL_2)
09414         {
09415                 blockFactor = 0.6f;
09416         }
09417         else if (self->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE] == FORCE_LEVEL_1)
09418         {
09419                 blockFactor = 0.9f;
09420         }
09421         else
09422         { //for now we just don't get to autoblock with no def
09423                 return 0;
09424         }
09425 
09426         if (thrownSaber)
09427         {
09428                 blockFactor -= 0.25f;
09429         }
09430 
09431         if (attackStr)
09432         { //blocking a saber, not a projectile.
09433                 blockFactor -= 0.25f;
09434         }
09435 
09436         if (!InFront( point, self->client->ps.origin, self->client->ps.viewangles, blockFactor )) //orig 0.2f
09437         {
09438                 return 0;
09439         }
09440 
09441         if (projectile)
09442         {
09443                 WP_SaberBlockNonRandom(self, point, projectile);
09444         }
09445         return 1;
09446 }

void WP_SaberClearDamage void   ) 
 

Definition at line 3510 of file w_saber.c.

References ENTITYNUM_NONE, MAX_SABER_VICTIMS, and memset().

Referenced by WP_SaberPositionUpdate().

03511 {
03512         int ven;
03513         for ( ven = 0; ven < MAX_SABER_VICTIMS; ven++ )
03514         {
03515                 victimEntityNum[ven] = ENTITYNUM_NONE;
03516         }
03517         memset( victimHitEffectDone, 0, sizeof( victimHitEffectDone ) );
03518         memset( totalDmg, 0, sizeof( totalDmg ) );
03519         memset( dmgDir, 0, sizeof( dmgDir ) );
03520         memset( dmgSpot, 0, sizeof( dmgSpot ) );
03521         memset( dismemberDmg, 0, sizeof( dismemberDmg ) );
03522         memset( saberKnockbackFlags, 0, sizeof( saberKnockbackFlags ) );
03523         numVictims = 0;
03524 }

void WP_SaberDamageAdd int  trVictimEntityNum,
vec3_t  trDmgDir,
vec3_t  trDmgSpot,
int  trDmg,
qboolean  doDismemberment,
int  knockBackFlags
 

Definition at line 3526 of file w_saber.c.

References ENTITYNUM_WORLD, MAX_SABER_VICTIMS, qtrue, vec3_origin, vec3_t, and VectorCopy.

03528 {
03529         if ( trVictimEntityNum < 0 || trVictimEntityNum >= ENTITYNUM_WORLD )
03530         {
03531                 return;
03532         }
03533         
03534         if ( trDmg )
03535         {//did some damage to something
03536                 int curVictim = 0;
03537                 int i;
03538 
03539                 for ( i = 0; i < numVictims; i++ )
03540                 {
03541                         if ( victimEntityNum[i] == trVictimEntityNum )
03542                         {//already hit this guy before
03543                                 curVictim = i;
03544                                 break;
03545                         }
03546                 }
03547                 if ( i == numVictims )
03548                 {//haven't hit his guy before
03549                         if ( numVictims + 1 >= MAX_SABER_VICTIMS )
03550                         {//can't add another victim at this time
03551                                 return;
03552                         }
03553                         //add a new victim to the list
03554                         curVictim = numVictims;
03555                         victimEntityNum[numVictims++] = trVictimEntityNum;
03556                 }
03557 
03558                 totalDmg[curVictim] += trDmg;
03559                 if ( VectorCompare( dmgDir[curVictim], vec3_origin ) )
03560                 {
03561                         VectorCopy( trDmgDir, dmgDir[curVictim] );
03562                 }
03563                 if ( VectorCompare( dmgSpot[curVictim], vec3_origin ) )
03564                 {
03565                         VectorCopy( trDmgSpot, dmgSpot[curVictim] );
03566                 }
03567                 if ( doDismemberment )
03568                 {
03569                         dismemberDmg[curVictim] = qtrue;
03570                 }
03571                 saberKnockbackFlags[curVictim] |= knockBackFlags;
03572         }
03573 }

void WP_SaberDoClash gentity_t self,
int  saberNum,
int  bladeNum
 

Definition at line 3796 of file w_saber.c.

References entityState_s::angles, EV_SABER_BLOCK, entityState_s::eventParm, G_TempEntity(), gentity_t, entityState_s::legsAnim, entityState_s::number, entityState_s::origin, entityState_s::otherEntityNum2, gentity_s::s, VectorCopy, and entityState_s::weapon.

Referenced by WP_SaberPositionUpdate().

03797 {
03798         if ( saberDoClashEffect )
03799         {
03800                 gentity_t *te = G_TempEntity( saberClashPos, EV_SABER_BLOCK );
03801                 VectorCopy(saberClashPos, te->s.origin);
03802                 VectorCopy(saberClashNorm, te->s.angles);
03803                 te->s.eventParm = saberClashEventParm;
03804                 te->s.otherEntityNum2 = self->s.number;
03805                 te->s.weapon = saberNum;
03806                 te->s.legsAnim = bladeNum;
03807         }
03808 }

void WP_SaberDoHit gentity_t self,
int  saberNum,
int  bladeNum
 

Definition at line 3606 of file w_saber.c.

References entityState_s::angles, CLASS_ATST, CLASS_GONK, CLASS_INTERROGATOR, CLASS_MARK1, CLASS_MARK2, CLASS_MOUSE, CLASS_PROBE, CLASS_PROTOCOL, CLASS_R2D2, CLASS_R5D2, CLASS_REMOTE, CLASS_SEEKER, CLASS_SENTRY, class_t, gentity_s::client, ET_BODY, ET_NPC, entityState_s::eType, EV_SABER_CLASHFLARE, EV_SABER_HIT, entityState_s::eventParm, g_entities, G_TempEntity(), gentity_t, entityState_s::legsAnim, gclient_s::NPC_class, NULL, entityState_s::number, entityState_s::origin, entityState_s::otherEntityNum, entityState_s::otherEntityNum2, qboolean, qfalse, qtrue, gentity_s::s, gclient_s::saber, SABER_NONATTACK_DAMAGE, saberInfo_t::saberFlags2, SFL2_NO_CLASH_FLARE, SFL2_NO_CLASH_FLARE2, VectorCopy, VectorScale, entityState_s::weapon, and WP_SaberBladeUseSecondBladeStyle().

Referenced by WP_SaberPositionUpdate().

03607 {
03608         int i;
03609         if ( !numVictims )
03610         {
03611                 return;
03612         }
03613         for ( i = 0; i < numVictims; i++ )
03614         {
03615                 gentity_t *te = NULL, *victim = NULL;
03616                 qboolean isDroid = qfalse;
03617 
03618                 if ( victimHitEffectDone[i] )
03619                 {
03620                         continue;
03621                 }
03622 
03623                 victimHitEffectDone[i] = qtrue;
03624 
03625                 victim = &g_entities[victimEntityNum[i]];
03626 
03627                 if ( victim->client )
03628                 {
03629                         class_t npc_class = victim->client->NPC_class;
03630 
03631                         if ( npc_class == CLASS_SEEKER || npc_class == CLASS_PROBE || npc_class == CLASS_MOUSE || npc_class == CLASS_REMOTE ||
03632                                         npc_class == CLASS_GONK || npc_class == CLASS_R2D2 || npc_class == CLASS_R5D2 ||
03633                                         npc_class == CLASS_PROTOCOL || npc_class == CLASS_MARK1 || npc_class == CLASS_MARK2 ||
03634                                         npc_class == CLASS_INTERROGATOR || npc_class == CLASS_ATST || npc_class == CLASS_SENTRY )  
03635                         { //don't make "blood" sparks for droids.
03636                                 isDroid = qtrue;
03637                         }
03638                 }
03639 
03640                 te = G_TempEntity( dmgSpot[i], EV_SABER_HIT );
03641                 if ( te )
03642                 {
03643                         te->s.otherEntityNum = victimEntityNum[i];
03644                         te->s.otherEntityNum2 = self->s.number;
03645                         te->s.weapon = saberNum;
03646                         te->s.legsAnim = bladeNum;
03647 
03648                         VectorCopy(dmgSpot[i], te->s.origin);
03649                         //VectorCopy(tr.plane.normal, te->s.angles);
03650                         VectorScale( dmgDir[i], -1, te->s.angles);
03651                         
03652                         if (!te->s.angles[0] && !te->s.angles[1] && !te->s.angles[2])
03653                         { //don't let it play with no direction
03654                                 te->s.angles[1] = 1;
03655                         }
03656 
03657                         if (!isDroid && (victim->client || victim->s.eType == ET_NPC ||
03658                                 victim->s.eType == ET_BODY))
03659                         {
03660                                 if ( totalDmg[i] < 5 )
03661                                 {
03662                                         te->s.eventParm = 3;
03663                                 }
03664                                 else if (totalDmg[i] < 20 )
03665                                 {
03666                                         te->s.eventParm = 2;
03667                                 }
03668                                 else
03669                                 {
03670                                         te->s.eventParm = 1;
03671                                 }
03672                         }
03673                         else
03674                         {
03675                                 if ( !WP_SaberBladeUseSecondBladeStyle( &self->client->saber[saberNum], bladeNum )
03676                                         && (self->client->saber[saberNum].saberFlags2&SFL2_NO_CLASH_FLARE) )
03677                                 {//don't do clash flare
03678                                 }
03679                                 else if ( WP_SaberBladeUseSecondBladeStyle( &self->client->saber[saberNum], bladeNum )
03680                                         && (self->client->saber[saberNum].saberFlags2&SFL2_NO_CLASH_FLARE2) )
03681                                 {//don't do clash flare
03682                                 }
03683                                 else
03684                                 {
03685                                         if (totalDmg[i] > SABER_NONATTACK_DAMAGE)
03686                                         { //I suppose I could tie this into the saberblock event, but I'm tired of adding flags to that thing.
03687                                                 gentity_t *teS = G_TempEntity( te->s.origin, EV_SABER_CLASHFLARE );
03688                                                 VectorCopy(te->s.origin, teS->s.origin);
03689                                         }
03690                                         te->s.eventParm = 0;
03691                                 }
03692                         }
03693                 }
03694         }
03695 }

void WP_SaberInitBladeData gentity_t ent  ) 
 

Definition at line 564 of file w_saber.c.

References gentity_s::classname, gentity_s::client, gentity_s::clipmask, entityShared_t::contents, CONTENTS_LIGHTSABER, EF_NODRAW, entityState_s::eFlags, g_entities, G_FreeEntity(), G_InitGentity(), G_SoundIndex(), G_Spawn(), gentity_s::genericValue5, gentity_t, gentity_s::inuse, level, MASK_PLAYERSOLID, gentity_s::mass, entityState_s::modelGhoul2, gentity_s::neverFree, gentity_s::nextthink, NULL, level_locals_t::num_entities, entityState_s::number, entityShared_t::ownerNum, gclient_s::ps, Q_stricmp(), qfalse, qtrue, gentity_s::r, gentity_s::s, playerState_s::saberEntityNum, SaberGotHit(), saberSpinSound, gclient_s::saberStoredIndex, SaberUpdateSelf(), SVF_NOCLIENT, SVF_USE_CURRENT_ORIGIN, entityShared_t::svFlags, gentity_s::think, level_locals_t::time, and gentity_s::touch.

Referenced by ClientBegin(), and NPC_SetMiscDefaultData().

00565 {
00566         gentity_t *saberent = NULL;
00567         gentity_t *checkEnt;
00568         int i = 0;
00569 
00570         while (i < level.num_entities)
00571         { //make sure there are no other saber entities floating around that think they belong to this client.
00572                 checkEnt = &g_entities[i];
00573 
00574                 if (checkEnt->inuse && checkEnt->neverFree &&
00575                         checkEnt->r.ownerNum == ent->s.number &&
00576                         checkEnt->classname && checkEnt->classname[0] &&
00577                         !Q_stricmp(checkEnt->classname, "lightsaber"))
00578                 {
00579                         if (saberent)
00580                         { //already have one
00581                                 checkEnt->neverFree = qfalse;
00582                                 checkEnt->think = G_FreeEntity;
00583                                 checkEnt->nextthink = level.time;
00584                         }
00585                         else
00586                         { //hmm.. well then, take it as my own.
00587                                 //free the bitch but don't issue a kg2 to avoid overflowing clients.
00588                                 checkEnt->s.modelGhoul2 = 0;
00589                                 G_FreeEntity(checkEnt);
00590 
00591                                 //now init it manually and reuse this ent slot.
00592                                 G_InitGentity(checkEnt);
00593                                 saberent = checkEnt;
00594                         }
00595                 }
00596 
00597                 i++;
00598         }
00599 
00600         //We do not want the client to have any real knowledge of the entity whatsoever. It will only
00601         //ever be used on the server.
00602         if (!saberent)
00603         { //ok, make one then
00604                 saberent = G_Spawn();
00605         }
00606         ent->client->ps.saberEntityNum = ent->client->saberStoredIndex = saberent->s.number;
00607         saberent->classname = "lightsaber";
00608         
00609         saberent->neverFree = qtrue; //the saber being removed would be a terrible thing.
00610 
00611         saberent->r.svFlags = SVF_USE_CURRENT_ORIGIN;
00612         saberent->r.ownerNum = ent->s.number;
00613 
00614         saberent->clipmask = MASK_PLAYERSOLID | CONTENTS_LIGHTSABER;
00615         saberent->r.contents = CONTENTS_LIGHTSABER;
00616 
00617         SetSaberBoxSize(saberent);
00618 
00619         saberent->mass = 10;
00620 
00621         saberent->s.eFlags |= EF_NODRAW;
00622         saberent->r.svFlags |= SVF_NOCLIENT;
00623 
00624         saberent->s.modelGhoul2 = 1;
00625         //should we happen to be removed (we belong to an NPC and he is removed) then
00626         //we want to attempt to remove our g2 instance on the client in case we had one.
00627 
00628         saberent->touch = SaberGotHit;
00629 
00630         saberent->think = SaberUpdateSelf;
00631         saberent->genericValue5 = 0;
00632         saberent->nextthink = level.time + 50;
00633 
00634         saberSpinSound = G_SoundIndex("sound/weapons/saber/saberspin.wav");
00635 }

float WP_SaberLength gentity_t ent  ) 
 

Definition at line 2791 of file w_saber.c.

References gentity_s::client, gentity_t, MAX_SABERS, gclient_s::saber, and WP_SaberBladeLength().

02792 {//return largest length
02793         if ( !ent || !ent->client )
02794         {
02795                 return 0.0f;
02796         }
02797         else
02798         {
02799                 int i;
02800                 float len, bestLen = 0.0f;
02801                 for ( i = 0; i < MAX_SABERS; i++ )
02802                 {
02803                         len = WP_SaberBladeLength( &ent->client->saber[i] );
02804                         if ( len > bestLen )
02805                         {
02806                                 bestLen = len;
02807                         }
02808                 }
02809                 return bestLen;
02810         }
02811 }

void WP_SaberPositionUpdate gentity_t self,
usercmd_t ucmd
 

Definition at line 8079 of file w_saber.c.

References trace_t::allsolid, AngleDelta(), entityState_s::angles, AnglesToAxis(), AngleVectors(), entityState_s::apos, saberTrail_t::base, BG_EvaluateTrajectory(), BG_InGrappleMove(), BG_KickingAnim(), BG_SaberInAttack(), BG_SabersOff(), BG_SuperBreakWinAnim(), saberInfo_t::blade, BLOCKED_NONE, BOTH_DEADFLOP1, BOTH_KYLE_GRAB, BOTH_KYLE_MISS, BOTH_KYLE_PA_1, BOTH_KYLE_PA_2, BROKENLIMB_LARM, playerState_s::brokenLimbs, CHAN_AUTO, CHAN_VOICE, gentity_s::client, gentity_s::clipmask, clientPersistant_t::cmd, entityShared_t::contents, CONTENTS_BODY, CONTENTS_LIGHTSABER, entityShared_t::currentOrigin, d_saberInterpolate, d_saberSPStyleDamage, gentity_s::damage, gclient_s::dangerTime, playerState_s::duelInProgress, EF_INVULNERABLE, playerState_s::eFlags, entityState_s::eFlags, ET_GENERAL, entityState_s::eType, EV_SABER_BLOCK, entityState_s::eventParm, playerState_s::fd, playerState_s::forceHandExtend, playerState_s::forceHandExtendTime, forcedata_s::forcePowersActive, FP_RAGE, trace_t::fraction, FRAMETIME, g2SaberInstance, G_Damage(), g_entities, G_EntitySound(), g_gametype, g_saberTraceSaberFirst, G_SetAnim(), G_SetOrigin(), G_Sound(), G_SoundIndex(), G_SPSaberDamageTraceLerped(), g_svfps, G_TempEntity(), G_UpdateClientAnims(), entityState_s::genericenemyindex, gentity_s::genericValue5, gentity_t, gentity_s::ghoul2, gclient_s::grappleIndex, gclient_s::grappleState, GT_DUEL, GT_POWERDUEL, HANDEXTEND_KNOCKDOWN, gclient_s::hasCurrentPosition, gentity_s::health, vmCvar_t::integer, gentity_s::inuse, gclient_s::invulnerableTimer, gclient_s::lastSaberBase_Always, gclient_s::lastSaberDir_Always, gclient_s::lastSaberStorageTime, saberTrail_t::lastTime, entityState_s::legsAnim, playerState_s::legsAnim, playerState_s::legsTimer, bladeInfo_t::lengthMax, level, entityShared_t::linked, entityState_s::loopIsSoundset, entityState_s::loopSound, playerState_s::m_iVehicleNum, gentity_s::m_pVehicle, Vehicle_s::m_vOrientation, MASK_PLAYERSOLID, MASK_SHOT, MAX_CLIENTS, MAX_SABERS, entityShared_t::maxs, gentity_s::methodOfDeath, entityShared_t::mins, MOD_MELEE, MOD_SABER, saberInfo_t::model, entityState_s::modelGhoul2, gentity_s::modelScale, bladeInfo_t::muzzleDir, bladeInfo_t::muzzleDirOld, bladeInfo_t::muzzlePoint, bladeInfo_t::muzzlePointOld, NEGATIVE_Y, gentity_s::nextthink, NULL, entityState_s::number, saberInfo_t::numBlades, gclient_s::olderIsValid, gclient_s::olderSaberBase, entityState_s::origin, ORIGIN, playerState_s::origin, gentity_s::parent, gclient_s::pers, PM_SaberInTransition(), entityState_s::pos, gentity_s::pos1, PROPER_THROWN_VALUE, gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, gclient_s::saber, SABER_THROWN_HIT_DAMAGE, forcedata_s::saberAnimLevel, playerState_s::saberBlocked, playerState_s::saberCanThrow, gclient_s::saberCycleQueue, playerState_s::saberDidThrowTime, forcedata_s::saberDrawAnimLevel, playerState_s::saberEntityNum, playerState_s::saberEntityState, saberFirstThrown(), saberInfo_t::saberFlags, playerState_s::saberHolstered, playerState_s::saberIdleWound, entityState_s::saberInFlight, playerState_s::saberInFlight, playerState_s::saberLockTime, SABERMAXS_X, SABERMAXS_Y, SABERMAXS_Z, SABERMINS_X, SABERMINS_Y, SABERMINS_Z, playerState_s::saberMove, saberSpinSound, gclient_s::saberStoredIndex, playerState_s::saberThrowDelay, SaberUpdateSelf(), SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, SetClientViewAngle(), SFL_NOT_THROWABLE, SFL_SINGLE_BLADE_THROWABLE, saberInfo_t::skin, entityState_s::solid, saberInfo_t::soundOff, saberInfo_t::spinSound, gentity_s::splashMethodOfDeath, trace_t::startsolid, bladeInfo_t::storageTime, SVF_NOCLIENT, entityShared_t::svFlags, gentity_s::think, thrownSaberTouch(), level_locals_t::time, saberTrail_t::tip, playerState_s::torsoAnim, playerState_s::torsoTimer, gentity_s::touch, TR_LINEAR, bladeInfo_t::trail, trap_G2API_GetBoltMatrix(), trap_G2API_OverrideServer(), trap_LinkEntity(), trap_Trace(), trajectory_t::trBase, trajectory_t::trDelta, trajectory_t::trTime, trajectory_t::trType, UpdateClientRenderinfo(), usercmd_t, vmCvar_t::value, vec3_t, vectoangles(), VectorAdd, VectorCopy, VectorMA, VectorNormalize(), VectorScale, VectorSet, VectorSubtract, playerState_s::velocity, playerState_s::viewangles, entityState_s::weapon, playerState_s::weapon, WEAPON_DROPPING, WEAPON_FIRING, WEAPON_RAISING, playerState_s::weaponstate, playerState_s::weaponTime, WP_SABER, WP_SaberAddG2Model(), WP_SaberApplyDamage(), WP_SaberClearDamage(), WP_SaberDoClash(), WP_SaberDoHit(), WP_SaberRemoveG2Model(), and YAW.

Referenced by G_RunFrame().

08080 { //rww - keep the saber position as updated as possible on the server so that we can try to do realistic-looking contact stuff
08081   //Note that this function also does the majority of working in maintaining the server g2 client instance (updating angles/anims/etc)
08082         gentity_t *mySaber = NULL;
08083         mdxaBone_t      boltMatrix;
08084         vec3_t properAngles, properOrigin;
08085         vec3_t boltAngles, boltOrigin;
08086         vec3_t end;
08087         vec3_t legAxis[3];
08088         vec3_t addVel;
08089         vec3_t rawAngles;
08090         float fVSpeed = 0;
08091         int returnAfterUpdate = 0;
08092         float animSpeedScale = 1.0f;
08093         int saberNum;
08094         qboolean clientOverride;
08095         gentity_t *vehEnt = NULL;
08096         int rSaberNum = 0;
08097         int rBladeNum = 0;
08098 
08099 #ifdef _DEBUG
08100         if (g_disableServerG2.integer)
08101         {
08102                 return;
08103         }
08104 #endif
08105 
08106         if (self && self->inuse && self->client)
08107         {
08108                 if (self->client->saberCycleQueue)
08109                 {
08110                         self->client->ps.fd.saberDrawAnimLevel = self->client->saberCycleQueue;
08111                 }
08112                 else
08113                 {
08114                         self->client->ps.fd.saberDrawAnimLevel = self->client->ps.fd.saberAnimLevel;
08115                 }
08116         }
08117 
08118         if (self &&
08119                 self->inuse &&
08120                 self->client &&
08121                 self->client->saberCycleQueue &&
08122                 (self->client->ps.weaponTime <= 0 || self->health < 1))
08123         { //we cycled attack levels while we were busy, so update now that we aren't (even if that means we're dead)
08124                 self->client->ps.fd.saberAnimLevel = self->client->saberCycleQueue;
08125                 self->client->saberCycleQueue = 0;
08126         }
08127 
08128         if (!self ||
08129                 !self->inuse ||
08130                 !self->client ||
08131                 !self->ghoul2 ||
08132                 !g2SaberInstance)
08133         {
08134                 return;
08135         }
08136 
08137         if (BG_KickingAnim(self->client->ps.legsAnim))
08138         { //do some kick traces and stuff if we're in the appropriate anim
08139                 G_KickSomeMofos(self);
08140         }
08141         else if (self->client->ps.torsoAnim == BOTH_KYLE_GRAB)
08142         { //try to grab someone
08143                 G_GrabSomeMofos(self);
08144         }
08145         else if (self->client->grappleState)
08146         {
08147                 gentity_t *grappler = &g_entities[self->client->grappleIndex];
08148 
08149                 if (!grappler->inuse || !grappler->client || grappler->client->grappleIndex != self->s.number ||
08150                         !BG_InGrappleMove(grappler->client->ps.torsoAnim) || !BG_InGrappleMove(grappler->client->ps.legsAnim) ||
08151                         !BG_InGrappleMove(self->client->ps.torsoAnim) || !BG_InGrappleMove(self->client->ps.legsAnim) ||
08152                         !self->client->grappleState || !grappler->client->grappleState ||
08153                         grappler->health < 1 || self->health < 1 ||
08154                         !G_PrettyCloseIGuess(self->client->ps.origin[2], grappler->client->ps.origin[2], 4.0f))
08155                 {
08156                         self->client->grappleState = 0;
08157                         if ((BG_InGrappleMove(self->client->ps.torsoAnim) && self->client->ps.torsoTimer > 100) ||
08158                                 (BG_InGrappleMove(self->client->ps.legsAnim) && self->client->ps.legsTimer > 100))
08159                         { //if they're pretty far from finishing the anim then shove them into another anim
08160                                 G_SetAnim(self, &self->client->pers.cmd, SETANIM_BOTH, BOTH_KYLE_MISS, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0);
08161                                 if (self->client->ps.torsoAnim == BOTH_KYLE_MISS)
08162                                 { //providing the anim set succeeded..
08163                                         self->client->ps.weaponTime = self->client->ps.torsoTimer;
08164                                 }
08165                         }
08166                 }
08167                 else
08168                 {
08169                         vec3_t grapAng;
08170 
08171                         VectorSubtract(grappler->client->ps.origin, self->client->ps.origin, grapAng);
08172 
08173                         if (VectorLength(grapAng) > 64.0f)
08174                         { //too far away, break it off
08175                                 if ((BG_InGrappleMove(self->client->ps.torsoAnim) && self->client->ps.torsoTimer > 100) ||
08176                                         (BG_InGrappleMove(self->client->ps.legsAnim) && self->client->ps.legsTimer > 100))
08177                                 {
08178                                         self->client->grappleState = 0;
08179 
08180                                         G_SetAnim(self, &self->client->pers.cmd, SETANIM_BOTH, BOTH_KYLE_MISS, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0);
08181                                         if (self->client->ps.torsoAnim == BOTH_KYLE_MISS)
08182                                         { //providing the anim set succeeded..
08183                                                 self->client->ps.weaponTime = self->client->ps.torsoTimer;
08184                                         }
08185                                 }
08186                         }
08187                         else
08188                         {
08189                                 vectoangles(grapAng, grapAng);
08190                                 SetClientViewAngle(self, grapAng);
08191 
08192                                 if (self->client->grappleState >= 20)
08193                                 { //grapplee
08194                                         //try to position myself at the correct distance from my grappler
08195                                         float idealDist;
08196                                         vec3_t gFwd, idealSpot;
08197                                         trace_t trace;
08198 
08199                                         if (grappler->client->ps.torsoAnim == BOTH_KYLE_PA_1)
08200                                         { //grab punch
08201                                                 idealDist = 46.0f;
08202                                         }
08203                                         else
08204                                         { //knee-throw
08205                                                 idealDist = 34.0f;
08206                                         }
08207 
08208                                         AngleVectors(grappler->client->ps.viewangles, gFwd, 0, 0);
08209                                         VectorMA(grappler->client->ps.origin, idealDist, gFwd, idealSpot);
08210 
08211                                         trap_Trace(&trace, self->client->ps.origin, self->r.mins, self->r.maxs, idealSpot, self->s.number, self->clipmask);
08212                                         if (!trace.startsolid && !trace.allsolid && trace.fraction == 1.0f)
08213                                         { //go there
08214                                                 G_SetOrigin(self, idealSpot);
08215                                                 VectorCopy(idealSpot, self->client->ps.origin);
08216                                         }
08217                                 }
08218                                 else if (self->client->grappleState >= 1)
08219                                 { //grappler
08220                                         if (grappler->client->ps.weapon == WP_SABER)
08221                                         { //make sure their saber is shut off
08222                                                 if (!grappler->client->ps.saberHolstered)
08223                                                 {
08224                                                         grappler->client->ps.saberHolstered = 2;
08225                                                         if (grappler->client->saber[0].soundOff)
08226                                                         {
08227                                                                 G_Sound(grappler, CHAN_AUTO, grappler->client->saber[0].soundOff);
08228                                                         }
08229                                                         if (grappler->client->saber[1].soundOff &&
08230                                                                 grappler->client->saber[1].model[0])
08231                                                         {
08232                                                                 G_Sound(grappler, CHAN_AUTO, grappler->client->saber[1].soundOff);
08233                                                         }
08234                                                 }
08235                                         }
08236 
08237                                         //check for smashy events
08238                                         if (self->client->ps.torsoAnim == BOTH_KYLE_PA_1)
08239                                         { //grab punch
08240                         if (self->client->grappleState == 1)
08241                                                 { //smack
08242                                                         if (self->client->ps.torsoTimer < 3400)
08243                                                         {
08244                                                                 int grapplerAnim = grappler->client->ps.torsoAnim;
08245                                                                 int grapplerTime = grappler->client->ps.torsoTimer;
08246 
08247                                                                 G_Damage(grappler, self, self, NULL, self->client->ps.origin, 10, 0, MOD_MELEE);
08248                                                                 //G_Sound( grappler, CHAN_AUTO, G_SoundIndex( va( "sound/weapons/melee/punch%d", Q_irand( 1, 4 ) ) ) );
08249 
08250                                                                 //it might try to put them into a pain anim or something, so override it back again
08251                                                                 if (grappler->health > 0)
08252                                                                 {
08253                                                                         grappler->client->ps.torsoAnim = grapplerAnim;
08254                                                                         grappler->client->ps.torsoTimer = grapplerTime;
08255                                                                         grappler->client->ps.legsAnim = grapplerAnim;
08256                                                                         grappler->client->ps.legsTimer = grapplerTime;
08257                                                                         grappler->client->ps.weaponTime = grapplerTime;
08258                                                                 }
08259                                                                 self->client->grappleState++;
08260                                                         }
08261                                                 }
08262                                                 else if (self->client->grappleState == 2)
08263                                                 { //smack!
08264                                                         if (self->client->ps.torsoTimer < 2550)
08265                                                         {
08266                                                                 int grapplerAnim = grappler->client->ps.torsoAnim;
08267                                                                 int grapplerTime = grappler->client->ps.torsoTimer;
08268 
08269                                                                 G_Damage(grappler, self, self, NULL, self->client->ps.origin, 10, 0, MOD_MELEE);
08270                                                                 //G_Sound( grappler, CHAN_AUTO, G_SoundIndex( va( "sound/weapons/melee/punch%d", Q_irand( 1, 4 ) ) ) );
08271 
08272                                                                 //it might try to put them into a pain anim or something, so override it back again
08273                                                                 if (grappler->health > 0)
08274                                                                 {
08275                                                                         grappler->client->ps.torsoAnim = grapplerAnim;
08276                                                                         grappler->client->ps.torsoTimer = grapplerTime;
08277                                                                         grappler->client->ps.legsAnim = grapplerAnim;
08278                                                                         grappler->client->ps.legsTimer = grapplerTime;
08279                                                                         grappler->client->ps.weaponTime = grapplerTime;
08280                                                                 }
08281                                                                 self->client->grappleState++;
08282                                                         }
08283                                                 }
08284                                                 else
08285                                                 { //SMACK!
08286                                                         if (self->client->ps.torsoTimer < 1300)
08287                                                         {
08288                                                                 vec3_t tossDir;
08289 
08290                                                                 G_Damage(grappler, self, self, NULL, self->client->ps.origin, 30, 0, MOD_MELEE);
08291                                                                 //G_Sound( grappler, CHAN_AUTO, G_SoundIndex( va( "sound/weapons/melee/punch%d", Q_irand( 1, 4 ) ) ) );
08292 
08293                                                                 self->client->grappleState = 0;
08294 
08295                                                                 VectorSubtract(grappler->client->ps.origin, self->client->ps.origin, tossDir);
08296                                                                 VectorNormalize(tossDir);
08297                                                                 VectorScale(tossDir, 500.0f, tossDir);
08298                                                                 tossDir[2] = 200.0f;
08299 
08300                                                                 VectorAdd(grappler->client->ps.velocity, tossDir, grappler->client->ps.velocity);
08301 
08302                                                                 if (grappler->health > 0)
08303                                                                 { //if still alive knock them down
08304                                                                         grappler->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
08305                                                                         grappler->client->ps.forceHandExtendTime = level.time + 1300;
08306                                                                 }
08307                                                         }
08308                                                 }
08309                                         }
08310                                         else if (self->client->ps.torsoAnim == BOTH_KYLE_PA_2)
08311                                         { //knee throw
08312                         if (self->client->grappleState == 1)
08313                                                 { //knee to the face
08314                                                         if (self->client->ps.torsoTimer < 3200)
08315                                                         {
08316                                                                 int grapplerAnim = grappler->client->ps.torsoAnim;
08317                                                                 int grapplerTime = grappler->client->ps.torsoTimer;
08318 
08319                                                                 G_Damage(grappler, self, self, NULL, self->client->ps.origin, 20, 0, MOD_MELEE);
08320                                                                 //G_Sound( grappler, CHAN_AUTO, G_SoundIndex( va( "sound/weapons/melee/punch%d", Q_irand( 1, 4 ) ) ) );
08321 
08322                                                                 //it might try to put them into a pain anim or something, so override it back again
08323                                                                 if (grappler->health > 0)
08324                                                                 {
08325                                                                         grappler->client->ps.torsoAnim = grapplerAnim;
08326                                                                         grappler->client->ps.torsoTimer = grapplerTime;
08327                                                                         grappler->client->ps.legsAnim = grapplerAnim;
08328                                                                         grappler->client->ps.legsTimer = grapplerTime;
08329                                                                         grappler->client->ps.weaponTime = grapplerTime;
08330                                                                 }
08331                                                                 self->client->grappleState++;
08332                                                         }
08333                                                 }
08334                                                 else if (self->client->grappleState == 2)
08335                                                 { //smashed on the ground
08336                                                         if (self->client->ps.torsoTimer < 2000)
08337                                                         {
08338                                                                 //G_Damage(grappler, self, self, NULL, self->client->ps.origin, 10, 0, MOD_MELEE);
08339                                                                 //don't do damage on this one, it would look very freaky if they died
08340                                                                 G_EntitySound( grappler, CHAN_VOICE, G_SoundIndex("*pain100.wav") );
08341                                                                 //G_Sound( grappler, CHAN_AUTO, G_SoundIndex( va( "sound/weapons/melee/punch%d", Q_irand( 1, 4 ) ) ) );
08342                                                                 self->client->grappleState++;
08343                                                         }
08344                                                 }
08345                                                 else
08346                                                 { //and another smash
08347                                                         if (self->client->ps.torsoTimer < 1000)
08348                                                         {
08349                                                                 G_Damage(grappler, self, self, NULL, self->client->ps.origin, 30, 0, MOD_MELEE);
08350                                                                 //G_Sound( grappler, CHAN_AUTO, G_SoundIndex( va( "sound/weapons/melee/punch%d", Q_irand( 1, 4 ) ) ) );
08351 
08352                                                                 //it might try to put them into a pain anim or something, so override it back again
08353                                                                 if (grappler->health > 0)
08354                                                                 {
08355                                                                         grappler->client->ps.torsoTimer = 1000;
08356                                                                         //G_SetAnim(grappler, &grappler->client->pers.cmd, SETANIM_BOTH, BOTH_GETUP3, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0);
08357                                                                         grappler->client->grappleState = 0;
08358                                                                 }
08359                                                                 else
08360                                                                 { //override death anim
08361                                                                         grappler->client->ps.torsoAnim = BOTH_DEADFLOP1;
08362                                                                         grappler->client->ps.legsAnim = BOTH_DEADFLOP1;
08363                                                                 }
08364 
08365                                                                 self->client->grappleState = 0;
08366                                                         }
08367                                                 }
08368                                         }
08369                                         else
08370                                         { //?
08371                                         }
08372                                 }
08373                         }
08374                 }
08375         }
08376 
08377         //If this is a listen server (client+server running on same machine),
08378         //then lets try to steal the skeleton/etc data off the client instance
08379         //for this entity to save us processing time.
08380         clientOverride = trap_G2API_OverrideServer(self->ghoul2);
08381 
08382         saberNum = self->client->ps.saberEntityNum;
08383 
08384         if (!saberNum)
08385         {
08386                 saberNum = self->client->saberStoredIndex;
08387         }
08388 
08389         if (!saberNum)
08390         {
08391                 returnAfterUpdate = 1;
08392                 goto nextStep;
08393         }
08394 
08395         mySaber = &g_entities[saberNum];
08396 
08397         if (self->health < 1)
08398         { //we don't want to waste precious CPU time calculating saber positions for corpses. But we want to avoid the saber ent position lagging on spawn, so..
08399                 //I guess it's good to keep the position updated even when contents are 0
08400                 if (mySaber && ((mySaber->r.contents & CONTENTS_LIGHTSABER) || mySaber->r.contents == 0) && !self->client->ps.saberInFlight)
08401                 { //Since we haven't got a bolt position, place it on top of the player origin.
08402                         VectorCopy(self->client->ps.origin, mySaber->r.currentOrigin);
08403                 }
08404         
08405                 //I don't want to return now actually, I want to keep g2 instances for corpses up to
08406                 //date because I'm doing better corpse hit detection/dismem (particularly for the
08407                 //npc's)
08408                 //return;
08409         }
08410 
08411         if ( BG_SuperBreakWinAnim( self->client->ps.torsoAnim ) )
08412         {
08413                 self->client->ps.weaponstate = WEAPON_FIRING;
08414         }
08415         if (self->client->ps.weapon != WP_SABER ||
08416                 self->client->ps.weaponstate == WEAPON_RAISING ||
08417                 self->client->ps.weaponstate == WEAPON_DROPPING ||
08418                 self->health < 1)
08419         {
08420                 if (!self->client->ps.saberInFlight)
08421                 {
08422                         returnAfterUpdate = 1;
08423                 }
08424         }
08425 
08426         if (self->client->ps.saberThrowDelay < level.time)
08427         {
08428                 if ( (self->client->saber[0].saberFlags&SFL_NOT_THROWABLE) )
08429                 {//cant throw it normally!
08430                         if ( (self->client->saber[0].saberFlags&SFL_SINGLE_BLADE_THROWABLE) )
08431                         {//but can throw it if only have 1 blade on
08432                                 if ( self->client->saber[0].numBlades > 1
08433                                         && self->client->ps.saberHolstered == 1 )
08434                                 {//have multiple blades and only one blade on
08435                                         self->client->ps.saberCanThrow = qtrue;//qfalse;
08436                                         //huh? want to be able to throw then right?
08437                                 }
08438                                 else
08439                                 {//multiple blades on, can't throw
08440                                         self->client->ps.saberCanThrow = qfalse;
08441                                 }
08442                         }
08443                         else
08444                         {//never can throw it
08445                                 self->client->ps.saberCanThrow = qfalse;
08446                         }
08447                 }
08448                 else
08449                 {//can throw it!
08450                         self->client->ps.saberCanThrow = qtrue;
08451                 }
08452         }
08453 nextStep:
08454         if (self->client->ps.fd.forcePowersActive & (1 << FP_RAGE))
08455         {
08456                 animSpeedScale = 2;
08457         }
08458         
08459         VectorCopy(self->client->ps.origin, properOrigin);
08460 
08461         //try to predict the origin based on velocity so it's more like what the client is seeing
08462         VectorCopy(self->client->ps.velocity, addVel);
08463         VectorNormalize(addVel);
08464 
08465         if (self->client->ps.velocity[0] < 0)
08466         {
08467                 fVSpeed += (-self->client->ps.velocity[0]);
08468         }
08469         else
08470         {
08471                 fVSpeed += self->client->ps.velocity[0];
08472         }
08473         if (self->client->ps.velocity[1] < 0)
08474         {
08475                 fVSpeed += (-self->client->ps.velocity[1]);
08476         }
08477         else
08478         {
08479                 fVSpeed += self->client->ps.velocity[1];
08480         }
08481         if (self->client->ps.velocity[2] < 0)
08482         {
08483                 fVSpeed += (-self->client->ps.velocity[2]);
08484         }
08485         else
08486         {
08487                 fVSpeed += self->client->ps.velocity[2];
08488         }
08489 
08490         //fVSpeed *= 0.08;
08491         fVSpeed *= 1.6f/g_svfps.value;
08492 
08493         //Cap it off at reasonable values so the saber box doesn't go flying ahead of us or
08494         //something if we get a big speed boost from something.
08495         if (fVSpeed > 70)
08496         {
08497                 fVSpeed = 70;
08498         }
08499         if (fVSpeed < -70)
08500         {
08501                 fVSpeed = -70;
08502         }
08503 
08504         properOrigin[0] += addVel[0]*fVSpeed;
08505         properOrigin[1] += addVel[1]*fVSpeed;
08506         properOrigin[2] += addVel[2]*fVSpeed;
08507 
08508         properAngles[0] = 0;
08509         if (self->s.number < MAX_CLIENTS && self->client->ps.m_iVehicleNum)
08510         {
08511                 vehEnt = &g_entities[self->client->ps.m_iVehicleNum];
08512                 if (vehEnt->inuse && vehEnt->client && vehEnt->m_pVehicle)
08513                 {
08514                         properAngles[1] = vehEnt->m_pVehicle->m_vOrientation[YAW];
08515                 }
08516                 else
08517                 {
08518                         properAngles[1] = self->client->ps.viewangles[YAW];
08519                         vehEnt = NULL;
08520                 }
08521         }
08522         else
08523         {
08524                 properAngles[1] = self->client->ps.viewangles[YAW];
08525         }
08526         properAngles[2] = 0;
08527 
08528         AnglesToAxis( properAngles, legAxis );
08529 
08530         UpdateClientRenderinfo(self, properOrigin, properAngles);
08531 
08532         if (!clientOverride)
08533         { //if we get the client instance we don't need to do this
08534                 G_G2PlayerAngles( self, legAxis, properAngles );
08535         }
08536 
08537         if (vehEnt)
08538         {
08539                 properAngles[1] = vehEnt->m_pVehicle->m_vOrientation[YAW];
08540         }
08541 
08542         if (returnAfterUpdate && saberNum)
08543         { //We don't even need to do GetBoltMatrix if we're only in here to keep the g2 server instance in sync
08544                 //but keep our saber entity in sync too, just copy it over our origin.
08545 
08546                 //I guess it's good to keep the position updated even when contents are 0
08547                 if (mySaber && ((mySaber->r.contents & CONTENTS_LIGHTSABER) || mySaber->r.contents == 0) && !self->client->ps.saberInFlight)
08548                 { //Since we haven't got a bolt position, place it on top of the player origin.
08549                         VectorCopy(self->client->ps.origin, mySaber->r.currentOrigin);
08550                 }
08551 
08552                 goto finalUpdate;
08553         }
08554 
08555         if (returnAfterUpdate)
08556         {
08557                 goto finalUpdate;
08558         }
08559 
08560         //We'll get data for blade 0 first no matter what it is and stick them into
08561         //the constant ("_Always") values. Later we will handle going through each blade.
08562         trap_G2API_GetBoltMatrix(self->ghoul2, 1, 0, &boltMatrix, properAngles, properOrigin, level.time, NULL, self->modelScale);
08563         BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, boltOrigin);
08564         BG_GiveMeVectorFromMatrix(&boltMatrix, NEGATIVE_Y, boltAngles);
08565 
08566         //immediately store these values so we don't have to recalculate this again
08567         if (self->client->lastSaberStorageTime && (level.time - self->client->lastSaberStorageTime) < 200)
08568         { //alright
08569                 VectorCopy(self->client->lastSaberBase_Always, self->client->olderSaberBase);
08570                 self->client->olderIsValid = qtrue;
08571         }
08572         else
08573         {
08574                 self->client->olderIsValid = qfalse;
08575         }
08576 
08577         VectorCopy(boltOrigin, self->client->lastSaberBase_Always);
08578         VectorCopy(boltAngles, self->client->lastSaberDir_Always);
08579         self->client->lastSaberStorageTime = level.time;
08580 
08581         VectorCopy(boltAngles, rawAngles);
08582 
08583         VectorMA( boltOrigin, self->client->saber[0].blade[0].lengthMax, boltAngles, end );
08584 
08585         if (self->client->ps.saberEntityNum)
08586         {
08587                 //I guess it's good to keep the position updated even when contents are 0
08588                 if (mySaber && ((mySaber->r.contents & CONTENTS_LIGHTSABER) || mySaber->r.contents == 0) && !self->client->ps.saberInFlight)
08589                 { //place it roughly in the middle of the saber..
08590                         VectorMA( boltOrigin, self->client->saber[0].blade[0].lengthMax, boltAngles, mySaber->r.currentOrigin );
08591                 }
08592         }
08593 
08594         boltAngles[YAW] = self->client->ps.viewangles[YAW];
08595 
08596 /*      {
08597                 static int lastDTime = 0;
08598                 if (lastDTime < level.time)
08599                 {
08600                         G_TestLine(boltOrigin, end, 0x0000ff, 200);
08601                         lastDTime = level.time + 200;
08602                 }
08603         }
08604 */
08605         if (self->client->ps.saberInFlight)
08606         { //do the thrown-saber stuff
08607                 gentity_t *saberent = &g_entities[saberNum];
08608 
08609                 if (saberent)
08610                 {
08611                         if (!self->client->ps.saberEntityState && self->client->ps.saberEntityNum)
08612                         {
08613                                 vec3_t startorg, startang, dir;
08614 
08615                                 VectorCopy(boltOrigin, saberent->r.currentOrigin);
08616 
08617                                 VectorCopy(boltOrigin, startorg);
08618                                 VectorCopy(boltAngles, startang);
08619 
08620                                 //startang[0] = 90;
08621                                 //Instead of this we'll sort of fake it and slowly tilt it down on the client via
08622                                 //a perframe method (which doesn't actually affect where or how the saber hits)
08623 
08624                                 saberent->r.svFlags &= ~(SVF_NOCLIENT);
08625                                 VectorCopy(startorg, saberent->s.pos.trBase);
08626                                 VectorCopy(startang, saberent->s.apos.trBase);
08627 
08628                                 VectorCopy(startorg, saberent->s.origin);
08629                                 VectorCopy(startang, saberent->s.angles);
08630 
08631                                 saberent->s.saberInFlight = qtrue;
08632 
08633                                 saberent->s.apos.trType = TR_LINEAR;
08634                                 saberent->s.apos.trDelta[0] = 0;
08635                                 saberent->s.apos.trDelta[1] = 800;
08636                                 saberent->s.apos.trDelta[2] = 0;
08637 
08638                                 saberent->s.pos.trType = TR_LINEAR;
08639                                 saberent->s.eType = ET_GENERAL;
08640                                 saberent->s.eFlags = 0;
08641 
08642                                 WP_SaberAddG2Model( saberent, self->client->saber[0].model, self->client->saber[0].skin );
08643 
08644                                 saberent->s.modelGhoul2 = 127;
08645 
08646                                 saberent->parent = self;
08647 
08648                                 self->client->ps.saberEntityState = 1;
08649 
08650                                 //Projectile stuff:
08651                                 AngleVectors(self->client->ps.viewangles, dir, NULL, NULL);
08652 
08653                                 saberent->nextthink = level.time + FRAMETIME;
08654                                 saberent->think = saberFirstThrown;
08655 
08656                                 saberent->damage = SABER_THROWN_HIT_DAMAGE;
08657                                 saberent->methodOfDeath = MOD_SABER;
08658                                 saberent->splashMethodOfDeath = MOD_SABER;
08659                                 saberent->s.solid = 2;
08660                                 saberent->r.contents = CONTENTS_LIGHTSABER;
08661 
08662                                 saberent->genericValue5 = 0;
08663 
08664                                 VectorSet( saberent->r.mins, SABERMINS_X, SABERMINS_Y, SABERMINS_Z );
08665                                 VectorSet( saberent->r.maxs, SABERMAXS_X, SABERMAXS_Y, SABERMAXS_Z );
08666 
08667                                 saberent->s.genericenemyindex = self->s.number+1024;
08668 
08669                                 saberent->touch = thrownSaberTouch;
08670 
08671                                 saberent->s.weapon = WP_SABER;
08672 
08673                                 VectorScale(dir, 400, saberent->s.pos.trDelta );
08674                                 saberent->s.pos.trTime = level.time;
08675 
08676                                 if ( self->client->saber[0].spinSound )
08677                                 {
08678                                         saberent->s.loopSound = self->client->saber[0].spinSound;
08679                                 }
08680                                 else
08681                                 {
08682                                         saberent->s.loopSound = saberSpinSound;
08683                                 }
08684                                 saberent->s.loopIsSoundset = qfalse;
08685 
08686                                 self->client->ps.saberDidThrowTime = level.time;
08687 
08688                                 self->client->dangerTime = level.time;
08689                                 self->client->ps.eFlags &= ~EF_INVULNERABLE;
08690                                 self->client->invulnerableTimer = 0;
08691 
08692                                 trap_LinkEntity(saberent);
08693                         }
08694                         else if (self->client->ps.saberEntityNum) //only do this stuff if your saber is active and has not been knocked out of the air.
08695                         {
08696                                 VectorCopy(boltOrigin, saberent->pos1);
08697                                 trap_LinkEntity(saberent);
08698 
08699                                 if (saberent->genericValue5 == PROPER_THROWN_VALUE)
08700                                 { //return to the owner now, this is a bad state to be in for here..
08701                                         saberent->genericValue5 = 0;
08702                                         saberent->think = SaberUpdateSelf;
08703                                         saberent->nextthink = level.time;
08704                                         WP_SaberRemoveG2Model( saberent );
08705                                         
08706                                         self->client->ps.saberInFlight = qfalse;
08707                                         self->client->ps.saberEntityState = 0;
08708                                         self->client->ps.saberThrowDelay = level.time + 500;
08709                                         self->client->ps.saberCanThrow = qfalse;
08710                                 }
08711                         }
08712                 }
08713         }
08714 
08715         /*
08716         if (self->client->ps.saberInFlight)
08717         { //if saber is thrown then only do the standard stuff for the left hand saber
08718                 rSaberNum = 1;
08719         }
08720         */
08721 
08722         if (!BG_SabersOff(&self->client->ps))
08723         {
08724                 gentity_t *saberent = &g_entities[saberNum];
08725 
08726                 if (!self->client->ps.saberInFlight && saberent)
08727                 {
08728                         saberent->r.svFlags |= (SVF_NOCLIENT);
08729                         saberent->r.contents = CONTENTS_LIGHTSABER;
08730                         SetSaberBoxSize(saberent);
08731                         saberent->s.loopSound = 0;
08732                         saberent->s.loopIsSoundset = qfalse;
08733                 }
08734 
08735                 if (self->client->ps.saberLockTime > level.time && self->client->ps.saberEntityNum)
08736                 {
08737                         if (self->client->ps.saberIdleWound < level.time)
08738                         {
08739                                 gentity_t *te;
08740                                 vec3_t dir;
08741                                 te = G_TempEntity( g_entities[saberNum].r.currentOrigin, EV_SABER_BLOCK );
08742                                 VectorSet( dir, 0, 1, 0 );
08743                                 VectorCopy(g_entities[saberNum].r.currentOrigin, te->s.origin);
08744                                 VectorCopy(dir, te->s.angles);
08745                                 te->s.eventParm = 1;
08746                                 te->s.weapon = 0;//saberNum
08747                                 te->s.legsAnim = 0;//bladeNum
08748 
08749                                 self->client->ps.saberIdleWound = level.time + Q_irand(400, 600);
08750                         }
08751 
08752                         while (rSaberNum < MAX_SABERS)
08753                         {
08754                                 rBladeNum = 0;
08755                                 while (rBladeNum < self->client->saber[rSaberNum].numBlades)
08756                                 { //Don't bother updating the bolt for each blade for this, it's just a very rough fallback method for during saberlocks
08757                                         VectorCopy(boltOrigin, self->client->saber[saberNum].blade[rBladeNum].trail.base);
08758                                         VectorCopy(end, self->client->saber[saberNum].blade[rBladeNum].trail.tip);
08759                                         self->client->saber[saberNum].blade[rBladeNum].trail.lastTime = level.time;
08760 
08761                                         rBladeNum++;
08762                                 }
08763 
08764                                 rSaberNum++;
08765                         }
08766                         self->client->hasCurrentPosition = qtrue;
08767 
08768                         self->client->ps.saberBlocked = BLOCKED_NONE;
08769 
08770                         goto finalUpdate;
08771                 }
08772 
08773                 //reset it in case we used it for cycling before
08774                 rSaberNum = rBladeNum = 0;
08775 
08776                 if (self->client->ps.saberInFlight)
08777                 { //if saber is thrown then only do the standard stuff for the left hand saber
08778                         if (!self->client->ps.saberEntityNum)
08779                         { //however, if saber is not in flight but rather knocked away, our left saber is off, and thus we may do nothing.
08780                                 rSaberNum = 1;//was 2?
08781                         }
08782                         else
08783                         {//thrown saber still in flight, so do damage
08784                                 rSaberNum = 0;//was 1?
08785                         }
08786                 }
08787 
08788                 WP_SaberClearDamage();
08789                 saberDoClashEffect = qfalse;
08790 
08791                 //Now cycle through each saber and each blade on the saber and do damage traces.
08792                 while (rSaberNum < MAX_SABERS)
08793                 {
08794                         if (!self->client->saber[rSaberNum].model[0])
08795                         {
08796                                 rSaberNum++;
08797                                 continue;
08798                         }
08799 
08800                         /*
08801                         if (rSaberNum == 0 && (self->client->ps.brokenLimbs & (1 << BROKENLIMB_RARM)))
08802                         { //don't do saber 0 is the right arm is broken
08803                                 rSaberNum++;
08804                                 continue;
08805                         }
08806                         */
08807                         //for now I'm keeping a broken right arm swingable, it will just look and act damaged
08808                         //but still be useable
08809                         
08810                         if (rSaberNum == 1 && (self->client->ps.brokenLimbs & (1 << BROKENLIMB_LARM)))
08811                         { //don't to saber 1 if the left arm is broken
08812                                 break;
08813                         }
08814                         if (rSaberNum > 0 
08815                                 && self->client->saber[1].model
08816                                 && self->client->saber[1].model[0]
08817                                 && self->client->ps.saberHolstered == 1 )
08818                         { //don't to saber 2 if it's off
08819                                 break;
08820                         }
08821                         rBladeNum = 0;
08822                         while (rBladeNum < self->client->saber[rSaberNum].numBlades)
08823                         {
08824                                 //update muzzle data for the blade
08825                                 VectorCopy(self->client->saber[rSaberNum].blade[rBladeNum].muzzlePoint, self->client->saber[rSaberNum].blade[rBladeNum].muzzlePointOld);
08826                                 VectorCopy(self->client->saber[rSaberNum].blade[rBladeNum].muzzleDir, self->client->saber[rSaberNum].blade[rBladeNum].muzzleDirOld);
08827 
08828                                 if ( rBladeNum > 0 //more than one blade
08829                                         && (!self->client->saber[1].model||!self->client->saber[1].model[0])//not using dual blades
08830                                         && self->client->saber[rSaberNum].numBlades > 1//using a multi-bladed saber
08831                                         && self->client->ps.saberHolstered == 1 )//
08832                                 { //don't to extra blades if they're off
08833                                         break;
08834                                 }
08835                                 //get the new data
08836                                 //then update the bolt pos/dir. rBladeNum corresponds to the bolt index because blade bolts are added in order.
08837                                 if ( rSaberNum == 0 && self->client->ps.saberInFlight )
08838                                 {
08839                                         if ( !self->client->ps.saberEntityNum )
08840                                         {//dropped it... shouldn't get here, but...
08841                                                 //assert(0);
08842                                                 //FIXME: It's getting here a lot actually....
08843                                                 rSaberNum++;
08844                                                 rBladeNum = 0;
08845                                                 continue;
08846                                         }
08847                                         else
08848                                         {
08849                                                 gentity_t *saberEnt = &g_entities[self->client->ps.saberEntityNum];
08850                                                 vec3_t saberOrg, saberAngles;
08851                                                 if ( !saberEnt 
08852                                                         || !saberEnt->inuse
08853                                                         || !saberEnt->ghoul2 )
08854                                                 {//wtf?
08855                                                         rSaberNum++;
08856                                                         rBladeNum = 0;
08857                                                         continue;
08858                                                 }
08859                                                 if ( saberent->s.saberInFlight )
08860                                                 {//spinning
08861                                                         BG_EvaluateTrajectory( &saberEnt->s.pos, level.time+50, saberOrg );
08862                                                         BG_EvaluateTrajectory( &saberEnt->s.apos, level.time+50, saberAngles );
08863                                                 }
08864                                                 else
08865                                                 {//coming right back
08866                                                         vec3_t saberDir;
08867                                                         BG_EvaluateTrajectory( &saberEnt->s.pos, level.time, saberOrg );
08868                                                         VectorSubtract( self->r.currentOrigin, saberOrg, saberDir );
08869                                                         vectoangles( saberDir, saberAngles );
08870                                                 }
08871                                                 trap_G2API_GetBoltMatrix(saberEnt->ghoul2, 0, rBladeNum, &boltMatrix, saberAngles, saberOrg, level.time, NULL, self->modelScale);
08872                                                 BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, self->client->saber[rSaberNum].blade[rBladeNum].muzzlePoint);
08873                                                 BG_GiveMeVectorFromMatrix(&boltMatrix, NEGATIVE_Y, self->client->saber[rSaberNum].blade[rBladeNum].muzzleDir);
08874                                                 VectorCopy( self->client->saber[rSaberNum].blade[rBladeNum].muzzlePoint, boltOrigin );
08875                                                 VectorMA( boltOrigin, self->client->saber[rSaberNum].blade[rBladeNum].lengthMax, self->client->saber[rSaberNum].blade[rBladeNum].muzzleDir, end );
08876                                         }
08877 
08878                                 }
08879                                 else
08880                                 {
08881                                         trap_G2API_GetBoltMatrix(self->ghoul2, rSaberNum+1, rBladeNum, &boltMatrix, properAngles, properOrigin, level.time, NULL, self->modelScale);
08882                                         BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, self->client->saber[rSaberNum].blade[rBladeNum].muzzlePoint);
08883                                         BG_GiveMeVectorFromMatrix(&boltMatrix, NEGATIVE_Y, self->client->saber[rSaberNum].blade[rBladeNum].muzzleDir);
08884                                         VectorCopy( self->client->saber[rSaberNum].blade[rBladeNum].muzzlePoint, boltOrigin );
08885                                         VectorMA( boltOrigin, self->client->saber[rSaberNum].blade[rBladeNum].lengthMax, self->client->saber[rSaberNum].blade[rBladeNum].muzzleDir, end );
08886                                 }
08887 
08888                                 self->client->saber[rSaberNum].blade[rBladeNum].storageTime = level.time;
08889 
08890                                 if (self->client->hasCurrentPosition && d_saberInterpolate.integer)
08891                                 {
08892                                         if (self->client->ps.weaponTime <= 0)
08893                                         { //rww - 07/17/02 - don't bother doing the extra stuff unless actually attacking. This is in attempt to save CPU.
08894                                                 CheckSaberDamage(self, rSaberNum, rBladeNum, boltOrigin, end, qfalse, (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER|MASK_SHOT), qfalse);
08895                                         }
08896                                         else if (d_saberInterpolate.integer == 1)
08897                                         {
08898                                                 int trMask = CONTENTS_LIGHTSABER|CONTENTS_BODY;
08899                                                 int sN = 0;
08900                                                 qboolean gotHit = qfalse;
08901                                                 qboolean clientUnlinked[MAX_CLIENTS];
08902                                                 qboolean skipSaberTrace = qfalse;
08903                                                 
08904                                                 if (!g_saberTraceSaberFirst.integer)
08905                                                 {
08906                                                         skipSaberTrace = qtrue;
08907                                                 }
08908                                                 else if (g_saberTraceSaberFirst.integer >= 2 &&
08909                                                         g_gametype.integer != GT_DUEL &&
08910                                                         g_gametype.integer != GT_POWERDUEL &&
08911                                                         !self->client->ps.duelInProgress)
08912                                                 { //if value is >= 2, and not in a duel, skip
08913                                                         skipSaberTrace = qtrue;
08914                                                 }
08915 
08916                                                 if (skipSaberTrace)
08917                                                 { //skip the saber-contents-only trace and get right to the full trace
08918                                                         trMask = (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER|MASK_SHOT);
08919                                                 }
08920                                                 else
08921                                                 {
08922                                                         while (sN < MAX_CLIENTS)
08923                                                         {
08924                                                                 if (g_entities[sN].inuse && g_entities[sN].client && g_entities[sN].r.linked && g_entities[sN].health > 0 && (g_entities[sN].r.contents & CONTENTS_BODY))
08925                                                                 { //Take this mask off before the saber trace, because we want to hit the saber first
08926                                                                         g_entities[sN].r.contents &= ~CONTENTS_BODY;
08927                                                                         clientUnlinked[sN] = qtrue;
08928                                                                 }
08929                                                                 else
08930                                                                 {
08931                                                                         clientUnlinked[sN] = qfalse;
08932                                                                 }
08933                                                                 sN++;
08934                                                         }
08935                                                 }
08936 
08937                                                 while (!gotHit)
08938                                                 {
08939                                                         if (!CheckSaberDamage(self, rSaberNum, rBladeNum, boltOrigin, end, qfalse, trMask, qfalse))
08940                                                         {
08941                                                                 if (!CheckSaberDamage(self, rSaberNum, rBladeNum, boltOrigin, end, qtrue, trMask, qfalse))
08942                                                                 {
08943                                                                         vec3_t oldSaberStart;
08944                                                                         vec3_t oldSaberEnd;
08945                                                                         vec3_t saberAngleNow;
08946                                                                         vec3_t saberAngleBefore;
08947                                                                         vec3_t saberMidDir;
08948                                                                         vec3_t saberMidAngle;
08949                                                                         vec3_t saberMidPoint;
08950                                                                         vec3_t saberMidEnd;
08951                                                                         vec3_t saberSubBase;
08952                                                                         float deltaX, deltaY, deltaZ;
08953 
08954                                                                         if ( (level.time-self->client->saber[rSaberNum].blade[rBladeNum].trail.lastTime) > 100 )
08955                                                                         {//no valid last pos, use current
08956                                                                                 VectorCopy(boltOrigin, oldSaberStart);
08957                                                                                 VectorCopy(end, oldSaberEnd);
08958                                                                         }
08959                                                                         else
08960                                                                         {//trace from last pos
08961                                                                                 VectorCopy(self->client->saber[rSaberNum].blade[rBladeNum].trail.base, oldSaberStart);
08962                                                                                 VectorCopy(self->client->saber[rSaberNum].blade[rBladeNum].trail.tip, oldSaberEnd);
08963                                                                         }
08964 
08965                                                                         VectorSubtract(oldSaberEnd, oldSaberStart, saberAngleBefore);
08966                                                                         vectoangles(saberAngleBefore, saberAngleBefore);
08967 
08968                                                                         VectorSubtract(end, boltOrigin, saberAngleNow);
08969                                                                         vectoangles(saberAngleNow, saberAngleNow);
08970 
08971                                                                         deltaX = AngleDelta(saberAngleBefore[0], saberAngleNow[0]);
08972                                                                         deltaY = AngleDelta(saberAngleBefore[1], saberAngleNow[1]);
08973                                                                         deltaZ = AngleDelta(saberAngleBefore[2], saberAngleNow[2]);
08974 
08975                                                                         if ( (deltaX != 0 || deltaY != 0 || deltaZ != 0) && deltaX < 180 && deltaY < 180 && deltaZ < 180 && (BG_SaberInAttack(self->client->ps.saberMove) || PM_SaberInTransition(self->client->ps.saberMove)) )
08976                                                                         { //don't go beyond here if we aren't attacking/transitioning or the angle is too large.
08977                                                                         //and don't bother if the angle is the same
08978                                                                                 saberMidAngle[0] = saberAngleBefore[0] + (deltaX/2);
08979                                                                                 saberMidAngle[1] = saberAngleBefore[1] + (deltaY/2);
08980                                                                                 saberMidAngle[2] = saberAngleBefore[2] + (deltaZ/2);
08981 
08982                                                                                 //Now that I have the angle, I'll just say the base for it is the difference between the two start
08983                                                                                 //points (even though that's quite possibly completely false)
08984                                                                                 VectorSubtract(boltOrigin, oldSaberStart, saberSubBase);
08985                                                                                 saberMidPoint[0] = boltOrigin[0] + (saberSubBase[0]*0.5);
08986                                                                                 saberMidPoint[1] = boltOrigin[1] + (saberSubBase[1]*0.5);
08987                                                                                 saberMidPoint[2] = boltOrigin[2] + (saberSubBase[2]*0.5);
08988 
08989                                                                                 AngleVectors(saberMidAngle, saberMidDir, 0, 0);
08990                                                                                 saberMidEnd[0] = saberMidPoint[0] + saberMidDir[0]*self->client->saber[rSaberNum].blade[rBladeNum].lengthMax;
08991                                                                                 saberMidEnd[1] = saberMidPoint[1] + saberMidDir[1]*self->client->saber[rSaberNum].blade[rBladeNum].lengthMax;
08992                                                                                 saberMidEnd[2] = saberMidPoint[2] + saberMidDir[2]*self->client->saber[rSaberNum].blade[rBladeNum].lengthMax;
08993 
08994                                                                                 //I'll just trace straight out and not even trace between positions to save speed.
08995                                                                                 if (CheckSaberDamage(self, rSaberNum, rBladeNum, saberMidPoint, saberMidEnd, qfalse, trMask, qfalse))
08996                                                                                 {
08997                                                                                         gotHit = qtrue;
08998                                                                                 }
08999                                                                         }
09000                                                                 }
09001                                                                 else
09002                                                                 {
09003                                                                         gotHit = qtrue;
09004                                                                 }
09005                                                         }
09006                                                         else
09007                                                         {
09008                                                                 gotHit = qtrue;
09009                                                         }
09010 
09011                                                         if (g_saberTraceSaberFirst.integer)
09012                                                         {
09013                                                                 sN = 0;
09014                                                                 while (sN < MAX_CLIENTS)
09015                                                                 {
09016                                                                         if (clientUnlinked[sN])
09017                                                                         { //Make clients clip properly again.
09018                                                                                 if (g_entities[sN].inuse && g_entities[sN].health > 0)
09019                                                                                 {
09020                                                                                         g_entities[sN].r.contents |= CONTENTS_BODY;
09021                                                                                 }
09022                                                                         }
09023                                                                         sN++;
09024                                                                 }
09025                                                         }
09026 
09027                                                         if (!gotHit)
09028                                                         {
09029                                                                 if (trMask != (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER|MASK_SHOT))
09030                                                                 {
09031                                                                         trMask = (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER|MASK_SHOT);
09032                                                                 }
09033                                                                 else
09034                                                                 {
09035                                                                         gotHit = qtrue; //break out of the loop
09036                                                                 }
09037                                                         }
09038                                                 }
09039                                         }
09040                                         else if (d_saberInterpolate.integer) //anything but 0 or 1, use the old plain method.
09041                                         {
09042                                                 if (!CheckSaberDamage(self, rSaberNum, rBladeNum, boltOrigin, end, qfalse, (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER|MASK_SHOT), qfalse))
09043                                                 {
09044                                                         CheckSaberDamage(self, rSaberNum, rBladeNum, boltOrigin, end, qtrue, (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER|MASK_SHOT), qfalse);
09045                                                 }
09046                                         }
09047                                 }
09048                                 else if ( d_saberSPStyleDamage.integer )
09049                                 {
09050                                         G_SPSaberDamageTraceLerped( self, rSaberNum, rBladeNum, boltOrigin, end, (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER|MASK_SHOT) );
09051                                 }
09052                                 else
09053                                 {
09054                                         CheckSaberDamage(self, rSaberNum, rBladeNum, boltOrigin, end, qfalse, (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER|MASK_SHOT), qfalse);
09055                                 }
09056 
09057                                 VectorCopy(boltOrigin, self->client->saber[rSaberNum].blade[rBladeNum].trail.base);
09058                                 VectorCopy(end, self->client->saber[rSaberNum].blade[rBladeNum].trail.tip);
09059                                 self->client->saber[rSaberNum].blade[rBladeNum].trail.lastTime = level.time;
09060                                 //VectorCopy(boltOrigin, self->client->lastSaberBase);
09061                                 //VectorCopy(end, self->client->lastSaberTip);
09062                                 self->client->hasCurrentPosition = qtrue;
09063 
09064                                 //do hit effects
09065                                 WP_SaberDoHit( self, rSaberNum, rBladeNum );
09066                                 WP_SaberDoClash( self, rSaberNum, rBladeNum );
09067 
09068                                 rBladeNum++;
09069                         }
09070 
09071                         rSaberNum++;
09072                 }
09073                 
09074                 WP_SaberApplyDamage( self );
09075                 //NOTE: doing one call like this after the 2 loops above is a bit cheaper, tempentity-wise... but won't use the correct saber and blade numbers...
09076                 //now actually go through and apply all the damage we did
09077                 //WP_SaberDoHit( self, 0, 0 );
09078                 //WP_SaberDoClash( self, 0, 0 );
09079 
09080                 if (mySaber && mySaber->inuse)
09081                 {
09082                         trap_LinkEntity(mySaber);
09083                 }
09084 
09085                 if (!self->client->ps.saberInFlight)
09086                 {
09087                         self->client->ps.saberEntityState = 0;
09088                 }
09089         }
09090 finalUpdate:
09091         if (clientOverride)
09092         { //if we get the client instance we don't even need to bother setting anims and stuff
09093                 return;
09094         }
09095 
09096         G_UpdateClientAnims(self, animSpeedScale);
09097 }

void WP_SaberRadiusDamage gentity_t ent,
vec3_t  point,
float  radius,
int  damage,
float  knockBack
 

Definition at line 3699 of file w_saber.c.

References ceil(), CLASS_ATST, CLASS_RANCOR, gentity_s::client, entityShared_t::currentOrigin, DAMAGE_NO_KNOCKBACK, EF2_HELD_BY_MONSTER, playerState_s::eFlags2, ENTITYNUM_NONE, FL_NO_KNOCKBACK, gentity_s::flags, G_Damage(), G_EntIsBreakable(), g_entities, G_Knockdown(), G_Throw(), gentity_t, playerState_s::groundEntityNum, gentity_s::health, gentity_s::inuse, MOD_MELEE, gclient_s::NPC_class, NULL, entityState_s::number, gclient_s::ps, gentity_s::r, gentity_s::s, trap_EntitiesInBox(), vec3_origin, vec3_t, VectorNormalize(), and VectorSubtract.

03700 {
03701         if ( !ent || !ent->client )
03702         {
03703                 return;
03704         }
03705         else if ( radius <= 0.0f || (damage <= 0 && knockBack <= 0) )
03706         {
03707                 return;
03708         }
03709         else
03710         {
03711                 vec3_t          mins, maxs, entDir;
03712                 int                     radiusEnts[128];
03713                 gentity_t       *radiusEnt = NULL;
03714                 int                     numEnts, i;
03715                 float           dist;
03716 
03717                 //Setup the bbox to search in
03718                 for ( i = 0; i < 3; i++ )
03719                 {
03720                         mins[i] = point[i] - radius;
03721                         maxs[i] = point[i] + radius;
03722                 }
03723 
03724                 //Get the number of entities in a given space
03725                 numEnts = trap_EntitiesInBox( mins, maxs, radiusEnts, 128 );
03726 
03727                 for ( i = 0; i < numEnts; i++ )
03728                 {
03729                         radiusEnt = &g_entities[radiusEnts[i]];
03730                         if ( !radiusEnt->inuse )
03731                         {
03732                                 continue;
03733                         }
03734                         
03735                         if ( radiusEnt == ent )
03736                         {//Skip myself
03737                                 continue;
03738                         }
03739                         
03740                         if ( radiusEnt->client == NULL )
03741                         {//must be a client
03742                                 if ( G_EntIsBreakable( radiusEnt->s.number ) )
03743                                 {//damage breakables within range, but not as much
03744                                         G_Damage( radiusEnt, ent, ent, vec3_origin, radiusEnt->r.currentOrigin, 10, 0, MOD_MELEE );
03745                                 }
03746                                 continue;
03747                         }
03748 
03749                         if ( (radiusEnt->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
03750                         {//can't be one being held
03751                                 continue;
03752                         }
03753                         
03754                         VectorSubtract( radiusEnt->r.currentOrigin, point, entDir );
03755                         dist = VectorNormalize( entDir );
03756                         if ( dist <= radius )
03757                         {//in range
03758                                 if ( damage > 0 )
03759                                 {//do damage
03760                                         int points = ceil((float)damage*dist/radius);
03761                                         G_Damage( radiusEnt, ent, ent, vec3_origin, radiusEnt->r.currentOrigin, points, DAMAGE_NO_KNOCKBACK, MOD_MELEE );
03762                                 }
03763                                 if ( knockBack > 0 )
03764                                 {//do knockback
03765                                         if ( radiusEnt->client
03766                                                 && radiusEnt->client->NPC_class != CLASS_RANCOR
03767                                                 && radiusEnt->client->NPC_class != CLASS_ATST
03768                                                 && !(radiusEnt->flags&FL_NO_KNOCKBACK) )//don't throw them back
03769                                         {
03770                                                 float knockbackStr = knockBack*dist/radius;
03771                                                 entDir[2] += 0.1f;
03772                                                 VectorNormalize( entDir );
03773                                                 G_Throw( radiusEnt, entDir, knockbackStr );
03774                                                 if ( radiusEnt->health > 0 )
03775                                                 {//still alive
03776                                                         if ( knockbackStr > 50 )
03777                                                         {//close enough and knockback high enough to possibly knock down
03778                                                                 if ( dist < (radius*0.5f)
03779                                                                         || radiusEnt->client->ps.groundEntityNum != ENTITYNUM_NONE )
03780                                                                 {//within range of my fist or within ground-shaking range and not in the air
03781                                                                         G_Knockdown( radiusEnt );//, ent, entDir, 500, qtrue );
03782                                                                 }
03783                                                         }
03784                                                 }
03785                                         }
03786                                 }
03787                         }
03788                 }
03789         }
03790 }

void WP_SaberRemoveG2Model gentity_t saberent  ) 
 

Referenced by DownedSaberThink(), saberBackToOwner(), saberFirstThrown(), WP_SaberAddG2Model(), and WP_SaberPositionUpdate().

qboolean WP_SabersCheckLock gentity_t ent1,
gentity_t ent2
 

Definition at line 1460 of file w_saber.c.

References BG_InRoll(), BG_InSpecialJump(), BLK_WIDE, BOTH_A1__L__R, BOTH_A1__R__L, BOTH_A1_BL_TR, BOTH_A1_BR_TL, BOTH_A1_T__B_, BOTH_A1_TL_BR, BOTH_A1_TR_BL, BOTH_A2__L__R, BOTH_A2__R__L, BOTH_A2_BL_TR, BOTH_A2_BR_TL, BOTH_A2_T__B_, BOTH_A2_TL_BR, BOTH_A2_TR_BL, BOTH_A3__L__R, BOTH_A3__R__L, BOTH_A3_BL_TR, BOTH_A3_BR_TL, BOTH_A3_T__B_, BOTH_A3_TL_BR, BOTH_A3_TR_BL, BOTH_A4__L__R, BOTH_A4__R__L, BOTH_A4_BL_TR, BOTH_A4_BR_TL, BOTH_A4_T__B_, BOTH_A4_TL_BR, BOTH_A4_TR_BL, BOTH_A5__L__R, BOTH_A5__R__L, BOTH_A5_BL_TR, BOTH_A5_BR_TL, BOTH_A5_T__B_, BOTH_A5_TL_BR, BOTH_A5_TR_BL, BOTH_A6__L__R, BOTH_A6__R__L, BOTH_A6_BL_TR, BOTH_A6_BR_TL, BOTH_A6_T__B_, BOTH_A6_TL_BR, BOTH_A6_TR_BL, BOTH_A7__L__R, BOTH_A7__R__L, BOTH_A7_BL_TR, BOTH_A7_BR_TL, BOTH_A7_T__B_, BOTH_A7_TL_BR, BOTH_A7_TR_BL, BOTH_P1_S1_BL, BOTH_P1_S1_BR, BOTH_P1_S1_TL, BOTH_P1_S1_TR, gentity_s::client, entityShared_t::currentOrigin, playerState_s::duelIndex, playerState_s::duelInProgress, ENTITYNUM_NONE, ET_NPC, entityState_s::eType, fabs(), playerState_s::forceHandExtend, g_debugSaberLocks, g_gametype, g_saberLocking, gentity_t, playerState_s::groundEntityNum, GT_DUEL, GT_POWERDUEL, HANDEXTEND_NONE, InFront(), vmCvar_t::integer, playerState_s::legsAnim, LOCK_DIAG_BL, LOCK_DIAG_BR, LOCK_DIAG_TL, LOCK_DIAG_TR, LOCK_L, LOCK_R, LOCK_RANDOM, LOCK_TOP, saberInfo_t::model, entityState_s::number, playerState_s::origin, gclient_s::playerTeam, playerState_s::pm_flags, PMF_DUCKED, gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, gclient_s::saber, playerState_s::saberBlocking, playerState_s::saberEntityNum, saberInfo_t::saberFlags, playerState_s::saberHolstered, playerState_s::saberInFlight, SFL_NOT_LOCKABLE, playerState_s::torsoAnim, playerState_s::viewangles, and playerState_s::weaponTime.

01461 {
01462         float dist;
01463         qboolean        ent1BlockingPlayer = qfalse;
01464         qboolean        ent2BlockingPlayer = qfalse;
01465 
01466         if ( g_debugSaberLocks.integer )
01467         {
01468                 WP_SabersCheckLock2( ent1, ent2, LOCK_RANDOM );
01469                 return qtrue;
01470         }
01471         //for now.. it's not fair to the lone duelist.
01472         //we need dual saber lock animations.
01473         if (g_gametype.integer == GT_POWERDUEL)
01474         {
01475                 return qfalse;
01476         }
01477 
01478         if (!g_saberLocking.integer)
01479         {
01480                 return qfalse;
01481         }
01482 
01483         if (!ent1->client || !ent2->client)
01484         {
01485                 return qfalse;
01486         }
01487 
01488         if (ent1->s.eType == ET_NPC ||
01489                 ent2->s.eType == ET_NPC)
01490         { //if either ents is NPC, then never let an NPC lock with someone on the same playerTeam
01491                 if (ent1->client->playerTeam == ent2->client->playerTeam)
01492                 {
01493                         return qfalse;
01494                 }
01495         }
01496 
01497         if (!ent1->client->ps.saberEntityNum ||
01498                 !ent2->client->ps.saberEntityNum ||
01499                 ent1->client->ps.saberInFlight ||
01500                 ent2->client->ps.saberInFlight)
01501         { //can't get in lock if one of them has had the saber knocked out of his hand
01502                 return qfalse;
01503         }
01504 
01505         if (ent1->s.eType != ET_NPC && ent2->s.eType != ET_NPC)
01506         { //can always get into locks with NPCs
01507                 if (!ent1->client->ps.duelInProgress ||
01508                         !ent2->client->ps.duelInProgress ||
01509                         ent1->client->ps.duelIndex != ent2->s.number ||
01510                         ent2->client->ps.duelIndex != ent1->s.number)
01511                 { //only allow saber locking if two players are dueling with each other directly
01512                         if (g_gametype.integer != GT_DUEL && g_gametype.integer != GT_POWERDUEL)
01513                         {
01514                                 return qfalse;
01515                         }
01516                 }
01517         }
01518 
01519         if ( fabs( ent1->r.currentOrigin[2]-ent2->r.currentOrigin[2] ) > 16 )
01520         {
01521                 return qfalse;
01522         }
01523         if ( ent1->client->ps.groundEntityNum == ENTITYNUM_NONE ||
01524                 ent2->client->ps.groundEntityNum == ENTITYNUM_NONE )
01525         {
01526                 return qfalse;
01527         }
01528         dist = DistanceSquared(ent1->r.currentOrigin,ent2->r.currentOrigin);
01529         if ( dist < 64 || dist > 6400 )
01530         {//between 8 and 80 from each other
01531                 return qfalse;
01532         }
01533 
01534         if (BG_InSpecialJump(ent1->client->ps.legsAnim))
01535         {
01536                 return qfalse;
01537         }
01538         if (BG_InSpecialJump(ent2->client->ps.legsAnim))
01539         {
01540                 return qfalse;
01541         }
01542 
01543         if (BG_InRoll(&ent1->client->ps, ent1->client->ps.legsAnim))
01544         {
01545                 return qfalse;
01546         }
01547         if (BG_InRoll(&ent2->client->ps, ent2->client->ps.legsAnim))
01548         {
01549                 return qfalse;
01550         }
01551 
01552         if (ent1->client->ps.forceHandExtend != HANDEXTEND_NONE ||
01553                 ent2->client->ps.forceHandExtend != HANDEXTEND_NONE)
01554         {
01555                 return qfalse;
01556         }
01557 
01558         if ((ent1->client->ps.pm_flags & PMF_DUCKED) ||
01559                 (ent2->client->ps.pm_flags & PMF_DUCKED))
01560         {
01561                 return qfalse;
01562         }
01563 
01564         if ( (ent1->client->saber[0].saberFlags&SFL_NOT_LOCKABLE)
01565                 || (ent2->client->saber[0].saberFlags&SFL_NOT_LOCKABLE) )
01566         {
01567                 return qfalse;
01568         }
01569         if ( ent1->client->saber[1].model
01570                 && ent1->client->saber[1].model[0]
01571                 && !ent1->client->ps.saberHolstered
01572                 && (ent1->client->saber[1].saberFlags&SFL_NOT_LOCKABLE) )
01573         {
01574                 return qfalse;
01575         }
01576         if ( ent2->client->saber[1].model
01577                 && ent2->client->saber[1].model[0]
01578                 && !ent2->client->ps.saberHolstered
01579                 && (ent2->client->saber[1].saberFlags&SFL_NOT_LOCKABLE) )
01580         {
01581                 return qfalse;
01582         }
01583 
01584         if (!InFront( ent1->client->ps.origin, ent2->client->ps.origin, ent2->client->ps.viewangles, 0.4f ))
01585         {
01586                 return qfalse;
01587         }
01588         if (!InFront( ent2->client->ps.origin, ent1->client->ps.origin, ent1->client->ps.viewangles, 0.4f ))
01589         {
01590                 return qfalse;
01591         }
01592 
01593         //T to B lock
01594         if ( ent1->client->ps.torsoAnim == BOTH_A1_T__B_ ||
01595                 ent1->client->ps.torsoAnim == BOTH_A2_T__B_ ||
01596                 ent1->client->ps.torsoAnim == BOTH_A3_T__B_ ||
01597                 ent1->client->ps.torsoAnim == BOTH_A4_T__B_ ||
01598                 ent1->client->ps.torsoAnim == BOTH_A5_T__B_ ||
01599                 ent1->client->ps.torsoAnim == BOTH_A6_T__B_ ||
01600                 ent1->client->ps.torsoAnim == BOTH_A7_T__B_)
01601         {//ent1 is attacking top-down
01602                 return WP_SabersCheckLock2( ent1, ent2, LOCK_TOP );
01603         }
01604 
01605         if ( ent2->client->ps.torsoAnim == BOTH_A1_T__B_ ||
01606                 ent2->client->ps.torsoAnim == BOTH_A2_T__B_ ||
01607                 ent2->client->ps.torsoAnim == BOTH_A3_T__B_ ||
01608                 ent2->client->ps.torsoAnim == BOTH_A4_T__B_ ||
01609                 ent2->client->ps.torsoAnim == BOTH_A5_T__B_ ||
01610                 ent2->client->ps.torsoAnim == BOTH_A6_T__B_ ||
01611                 ent2->client->ps.torsoAnim == BOTH_A7_T__B_)
01612         {//ent2 is attacking top-down
01613                 return WP_SabersCheckLock2( ent2, ent1, LOCK_TOP );
01614         }
01615 
01616         if ( ent1->s.number == 0 &&
01617                 ent1->client->ps.saberBlocking == BLK_WIDE && ent1->client->ps.weaponTime <= 0 )
01618         {
01619                 ent1BlockingPlayer = qtrue;
01620         }
01621         if ( ent2->s.number == 0 &&
01622                 ent2->client->ps.saberBlocking == BLK_WIDE && ent2->client->ps.weaponTime <= 0 )
01623         {
01624                 ent2BlockingPlayer = qtrue;
01625         }
01626 
01627         //TR to BL lock
01628         if ( ent1->client->ps.torsoAnim == BOTH_A1_TR_BL ||
01629                 ent1->client->ps.torsoAnim == BOTH_A2_TR_BL ||
01630                 ent1->client->ps.torsoAnim == BOTH_A3_TR_BL ||
01631                 ent1->client->ps.torsoAnim == BOTH_A4_TR_BL ||
01632                 ent1->client->ps.torsoAnim == BOTH_A5_TR_BL ||
01633                 ent1->client->ps.torsoAnim == BOTH_A6_TR_BL ||
01634                 ent1->client->ps.torsoAnim == BOTH_A7_TR_BL)
01635         {//ent1 is attacking diagonally
01636                 if ( ent2BlockingPlayer )
01637                 {//player will block this anyway
01638                         return WP_SabersCheckLock2( ent1, ent2, LOCK_DIAG_TR );
01639                 }
01640                 if ( ent2->client->ps.torsoAnim == BOTH_A1_TR_BL ||
01641                         ent2->client->ps.torsoAnim == BOTH_A2_TR_BL ||
01642                         ent2->client->ps.torsoAnim == BOTH_A3_TR_BL ||
01643                         ent2->client->ps.torsoAnim == BOTH_A4_TR_BL ||
01644                         ent2->client->ps.torsoAnim == BOTH_A5_TR_BL ||
01645                         ent2->client->ps.torsoAnim == BOTH_A6_TR_BL ||
01646                         ent2->client->ps.torsoAnim == BOTH_A7_TR_BL ||
01647                         ent2->client->ps.torsoAnim == BOTH_P1_S1_TL )
01648                 {//ent2 is attacking in the opposite diagonal
01649                         return WP_SabersCheckLock2( ent1, ent2, LOCK_DIAG_TR );
01650                 }
01651                 if ( ent2->client->ps.torsoAnim == BOTH_A1_BR_TL ||
01652                         ent2->client->ps.torsoAnim == BOTH_A2_BR_TL ||
01653                         ent2->client->ps.torsoAnim == BOTH_A3_BR_TL ||
01654                         ent2->client->ps.torsoAnim == BOTH_A4_BR_TL ||
01655                         ent2->client->ps.torsoAnim == BOTH_A5_BR_TL ||
01656                         ent2->client->ps.torsoAnim == BOTH_A6_BR_TL ||
01657                         ent2->client->ps.torsoAnim == BOTH_A7_BR_TL ||
01658                         ent2->client->ps.torsoAnim == BOTH_P1_S1_BL )
01659                 {//ent2 is attacking in the opposite diagonal
01660                         return WP_SabersCheckLock2( ent1, ent2, LOCK_DIAG_BL );
01661                 }
01662                 return qfalse;
01663         }
01664 
01665         if ( ent2->client->ps.torsoAnim == BOTH_A1_TR_BL ||
01666                 ent2->client->ps.torsoAnim == BOTH_A2_TR_BL ||
01667                 ent2->client->ps.torsoAnim == BOTH_A3_TR_BL ||
01668                 ent2->client->ps.torsoAnim == BOTH_A4_TR_BL ||
01669                 ent2->client->ps.torsoAnim == BOTH_A5_TR_BL ||
01670                 ent2->client->ps.torsoAnim == BOTH_A6_TR_BL ||
01671                 ent2->client->ps.torsoAnim == BOTH_A7_TR_BL)
01672         {//ent2 is attacking diagonally
01673                 if ( ent1BlockingPlayer )
01674                 {//player will block this anyway
01675                         return WP_SabersCheckLock2( ent2, ent1, LOCK_DIAG_TR );
01676                 }
01677                 if ( ent1->client->ps.torsoAnim == BOTH_A1_TR_BL ||
01678                         ent1->client->ps.torsoAnim == BOTH_A2_TR_BL ||
01679                         ent1->client->ps.torsoAnim == BOTH_A3_TR_BL ||
01680                         ent1->client->ps.torsoAnim == BOTH_A4_TR_BL ||
01681                         ent1->client->ps.torsoAnim == BOTH_A5_TR_BL ||
01682                         ent1->client->ps.torsoAnim == BOTH_A6_TR_BL ||
01683                         ent1->client->ps.torsoAnim == BOTH_A7_TR_BL ||
01684                         ent1->client->ps.torsoAnim == BOTH_P1_S1_TL )
01685                 {//ent1 is attacking in the opposite diagonal
01686                         return WP_SabersCheckLock2( ent2, ent1, LOCK_DIAG_TR );
01687                 }
01688                 if ( ent1->client->ps.torsoAnim == BOTH_A1_BR_TL ||
01689                         ent1->client->ps.torsoAnim == BOTH_A2_BR_TL ||
01690                         ent1->client->ps.torsoAnim == BOTH_A3_BR_TL ||
01691                         ent1->client->ps.torsoAnim == BOTH_A4_BR_TL ||
01692                         ent1->client->ps.torsoAnim == BOTH_A5_BR_TL ||
01693                         ent1->client->ps.torsoAnim == BOTH_A6_BR_TL ||
01694                         ent1->client->ps.torsoAnim == BOTH_A7_BR_TL ||
01695                         ent1->client->ps.torsoAnim == BOTH_P1_S1_BL )
01696                 {//ent1 is attacking in the opposite diagonal
01697                         return WP_SabersCheckLock2( ent2, ent1, LOCK_DIAG_BL );
01698                 }
01699                 return qfalse;
01700         }
01701 
01702         //TL to BR lock
01703         if ( ent1->client->ps.torsoAnim == BOTH_A1_TL_BR ||
01704                 ent1->client->ps.torsoAnim == BOTH_A2_TL_BR ||
01705                 ent1->client->ps.torsoAnim == BOTH_A3_TL_BR ||
01706                 ent1->client->ps.torsoAnim == BOTH_A4_TL_BR ||
01707                 ent1->client->ps.torsoAnim == BOTH_A5_TL_BR ||
01708                 ent1->client->ps.torsoAnim == BOTH_A6_TL_BR ||
01709                 ent1->client->ps.torsoAnim == BOTH_A7_TL_BR)
01710         {//ent1 is attacking diagonally
01711                 if ( ent2BlockingPlayer )
01712                 {//player will block this anyway
01713                         return WP_SabersCheckLock2( ent1, ent2, LOCK_DIAG_TL );
01714                 }
01715                 if ( ent2->client->ps.torsoAnim == BOTH_A1_TL_BR ||
01716                         ent2->client->ps.torsoAnim == BOTH_A2_TL_BR ||
01717                         ent2->client->ps.torsoAnim == BOTH_A3_TL_BR ||
01718                         ent2->client->ps.torsoAnim == BOTH_A4_TL_BR ||
01719                         ent2->client->ps.torsoAnim == BOTH_A5_TL_BR ||
01720                         ent2->client->ps.torsoAnim == BOTH_A6_TL_BR ||
01721                         ent2->client->ps.torsoAnim == BOTH_A7_TL_BR ||
01722                         ent2->client->ps.torsoAnim == BOTH_P1_S1_TR )
01723                 {//ent2 is attacking in the opposite diagonal
01724                         return WP_SabersCheckLock2( ent1, ent2, LOCK_DIAG_TL );
01725                 }
01726                 if ( ent2->client->ps.torsoAnim == BOTH_A1_BL_TR ||
01727                         ent2->client->ps.torsoAnim == BOTH_A2_BL_TR ||
01728                         ent2->client->ps.torsoAnim == BOTH_A3_BL_TR ||
01729                         ent2->client->ps.torsoAnim == BOTH_A4_BL_TR ||
01730                         ent2->client->ps.torsoAnim == BOTH_A5_BL_TR ||
01731                         ent2->client->ps.torsoAnim == BOTH_A6_BL_TR ||
01732                         ent2->client->ps.torsoAnim == BOTH_A7_BL_TR ||
01733                         ent2->client->ps.torsoAnim == BOTH_P1_S1_BR )
01734                 {//ent2 is attacking in the opposite diagonal
01735                         return WP_SabersCheckLock2( ent1, ent2, LOCK_DIAG_BR );
01736                 }
01737                 return qfalse;
01738         }
01739 
01740         if ( ent2->client->ps.torsoAnim == BOTH_A1_TL_BR ||
01741                 ent2->client->ps.torsoAnim == BOTH_A2_TL_BR ||
01742                 ent2->client->ps.torsoAnim == BOTH_A3_TL_BR ||
01743                 ent2->client->ps.torsoAnim == BOTH_A4_TL_BR ||
01744                 ent2->client->ps.torsoAnim == BOTH_A5_TL_BR ||
01745                 ent2->client->ps.torsoAnim == BOTH_A6_TL_BR ||
01746                 ent2->client->ps.torsoAnim == BOTH_A7_TL_BR)
01747         {//ent2 is attacking diagonally
01748                 if ( ent1BlockingPlayer )
01749                 {//player will block this anyway
01750                         return WP_SabersCheckLock2( ent2, ent1, LOCK_DIAG_TL );
01751                 }
01752                 if ( ent1->client->ps.torsoAnim == BOTH_A1_TL_BR ||
01753                         ent1->client->ps.torsoAnim == BOTH_A2_TL_BR ||
01754                         ent1->client->ps.torsoAnim == BOTH_A3_TL_BR ||
01755                         ent1->client->ps.torsoAnim == BOTH_A4_TL_BR ||
01756                         ent1->client->ps.torsoAnim == BOTH_A5_TL_BR ||
01757                         ent1->client->ps.torsoAnim == BOTH_A6_TL_BR ||
01758                         ent1->client->ps.torsoAnim == BOTH_A7_TL_BR ||
01759                         ent1->client->ps.torsoAnim == BOTH_P1_S1_TR )
01760                 {//ent1 is attacking in the opposite diagonal
01761                         return WP_SabersCheckLock2( ent2, ent1, LOCK_DIAG_TL );
01762                 }
01763                 if ( ent1->client->ps.torsoAnim == BOTH_A1_BL_TR ||
01764                         ent1->client->ps.torsoAnim == BOTH_A2_BL_TR ||
01765                         ent1->client->ps.torsoAnim == BOTH_A3_BL_TR ||
01766                         ent1->client->ps.torsoAnim == BOTH_A4_BL_TR ||
01767                         ent1->client->ps.torsoAnim == BOTH_A5_BL_TR ||
01768                         ent1->client->ps.torsoAnim == BOTH_A6_BL_TR ||
01769                         ent1->client->ps.torsoAnim == BOTH_A7_BL_TR ||
01770                         ent1->client->ps.torsoAnim == BOTH_P1_S1_BR )
01771                 {//ent1 is attacking in the opposite diagonal
01772                         return WP_SabersCheckLock2( ent2, ent1, LOCK_DIAG_BR );
01773                 }
01774                 return qfalse;
01775         }
01776         //L to R lock
01777         if ( ent1->client->ps.torsoAnim == BOTH_A1__L__R ||
01778                 ent1->client->ps.torsoAnim == BOTH_A2__L__R ||
01779                 ent1->client->ps.torsoAnim == BOTH_A3__L__R ||
01780                 ent1->client->ps.torsoAnim == BOTH_A4__L__R ||
01781                 ent1->client->ps.torsoAnim == BOTH_A5__L__R ||
01782                 ent1->client->ps.torsoAnim == BOTH_A6__L__R ||
01783                 ent1->client->ps.torsoAnim == BOTH_A7__L__R)
01784         {//ent1 is attacking l to r
01785                 if ( ent2BlockingPlayer )
01786                 {//player will block this anyway
01787                         return WP_SabersCheckLock2( ent1, ent2, LOCK_L );
01788                 }
01789                 if ( ent2->client->ps.torsoAnim == BOTH_A1_TL_BR ||
01790                         ent2->client->ps.torsoAnim == BOTH_A2_TL_BR ||
01791                         ent2->client->ps.torsoAnim == BOTH_A3_TL_BR ||
01792                         ent2->client->ps.torsoAnim == BOTH_A4_TL_BR ||
01793                         ent2->client->ps.torsoAnim == BOTH_A5_TL_BR ||
01794                         ent2->client->ps.torsoAnim == BOTH_A6_TL_BR ||
01795                         ent2->client->ps.torsoAnim == BOTH_A7_TL_BR ||
01796                         ent2->client->ps.torsoAnim == BOTH_P1_S1_TR ||
01797                         ent2->client->ps.torsoAnim == BOTH_P1_S1_BL )
01798                 {//ent2 is attacking or blocking on the r
01799                         return WP_SabersCheckLock2( ent1, ent2, LOCK_L );
01800                 }
01801                 return qfalse;
01802         }
01803         if ( ent2->client->ps.torsoAnim == BOTH_A1__L__R ||
01804                 ent2->client->ps.torsoAnim == BOTH_A2__L__R ||
01805                 ent2->client->ps.torsoAnim == BOTH_A3__L__R ||
01806                 ent2->client->ps.torsoAnim == BOTH_A4__L__R ||
01807                 ent2->client->ps.torsoAnim == BOTH_A5__L__R ||
01808                 ent2->client->ps.torsoAnim == BOTH_A6__L__R ||
01809                 ent2->client->ps.torsoAnim == BOTH_A7__L__R)
01810         {//ent2 is attacking l to r
01811                 if ( ent1BlockingPlayer )
01812                 {//player will block this anyway
01813                         return WP_SabersCheckLock2( ent2, ent1, LOCK_L );
01814                 }
01815                 if ( ent1->client->ps.torsoAnim == BOTH_A1_TL_BR ||
01816                         ent1->client->ps.torsoAnim == BOTH_A2_TL_BR ||
01817                         ent1->client->ps.torsoAnim == BOTH_A3_TL_BR ||
01818                         ent1->client->ps.torsoAnim == BOTH_A4_TL_BR ||
01819                         ent1->client->ps.torsoAnim == BOTH_A5_TL_BR ||
01820                         ent1->client->ps.torsoAnim == BOTH_A6_TL_BR ||
01821                         ent1->client->ps.torsoAnim == BOTH_A7_TL_BR ||
01822                         ent1->client->ps.torsoAnim == BOTH_P1_S1_TR ||
01823                         ent1->client->ps.torsoAnim == BOTH_P1_S1_BL )
01824                 {//ent1 is attacking or blocking on the r
01825                         return WP_SabersCheckLock2( ent2, ent1, LOCK_L );
01826                 }
01827                 return qfalse;
01828         }
01829         //R to L lock
01830         if ( ent1->client->ps.torsoAnim == BOTH_A1__R__L ||
01831                 ent1->client->ps.torsoAnim == BOTH_A2__R__L ||
01832                 ent1->client->ps.torsoAnim == BOTH_A3__R__L ||
01833                 ent1->client->ps.torsoAnim == BOTH_A4__R__L ||
01834                 ent1->client->ps.torsoAnim == BOTH_A5__R__L ||
01835                 ent1->client->ps.torsoAnim == BOTH_A6__R__L ||
01836                 ent1->client->ps.torsoAnim == BOTH_A7__R__L)
01837         {//ent1 is attacking r to l
01838                 if ( ent2BlockingPlayer )
01839                 {//player will block this anyway
01840                         return WP_SabersCheckLock2( ent1, ent2, LOCK_R );
01841                 }
01842                 if ( ent2->client->ps.torsoAnim == BOTH_A1_TR_BL ||
01843                         ent2->client->ps.torsoAnim == BOTH_A2_TR_BL ||
01844                         ent2->client->ps.torsoAnim == BOTH_A3_TR_BL ||
01845                         ent2->client->ps.torsoAnim == BOTH_A4_TR_BL ||
01846                         ent2->client->ps.torsoAnim == BOTH_A5_TR_BL ||
01847                         ent2->client->ps.torsoAnim == BOTH_A6_TR_BL ||
01848                         ent2->client->ps.torsoAnim == BOTH_A7_TR_BL ||
01849                         ent2->client->ps.torsoAnim == BOTH_P1_S1_TL ||
01850                         ent2->client->ps.torsoAnim == BOTH_P1_S1_BR )
01851                 {//ent2 is attacking or blocking on the l
01852                         return WP_SabersCheckLock2( ent1, ent2, LOCK_R );
01853                 }
01854                 return qfalse;
01855         }
01856         if ( ent2->client->ps.torsoAnim == BOTH_A1__R__L ||
01857                 ent2->client->ps.torsoAnim == BOTH_A2__R__L ||
01858                 ent2->client->ps.torsoAnim == BOTH_A3__R__L ||
01859                 ent2->client->ps.torsoAnim == BOTH_A4__R__L ||
01860                 ent2->client->ps.torsoAnim == BOTH_A5__R__L ||
01861                 ent2->client->ps.torsoAnim == BOTH_A6__R__L ||
01862                 ent2->client->ps.torsoAnim == BOTH_A7__R__L)
01863         {//ent2 is attacking r to l
01864                 if ( ent1BlockingPlayer )
01865                 {//player will block this anyway
01866                         return WP_SabersCheckLock2( ent2, ent1, LOCK_R );
01867                 }
01868                 if ( ent1->client->ps.torsoAnim == BOTH_A1_TR_BL ||
01869                         ent1->client->ps.torsoAnim == BOTH_A2_TR_BL ||
01870                         ent1->client->ps.torsoAnim == BOTH_A3_TR_BL ||
01871                         ent1->client->ps.torsoAnim == BOTH_A4_TR_BL ||
01872                         ent1->client->ps.torsoAnim == BOTH_A5_TR_BL ||
01873                         ent1->client->ps.torsoAnim == BOTH_A6_TR_BL ||
01874                         ent1->client->ps.torsoAnim == BOTH_A7_TR_BL ||
01875                         ent1->client->ps.torsoAnim == BOTH_P1_S1_TL ||
01876                         ent1->client->ps.torsoAnim == BOTH_P1_S1_BR )
01877                 {//ent1 is attacking or blocking on the l
01878                         return WP_SabersCheckLock2( ent2, ent1, LOCK_R );
01879                 }
01880                 return qfalse;
01881         }
01882         if ( !Q_irand( 0, 10 ) )
01883         {
01884                 return WP_SabersCheckLock2( ent1, ent2, LOCK_RANDOM );
01885         }
01886         return qfalse;
01887 }

qboolean WP_SabersIntersect gentity_t ent1,
int  ent1SaberNum,
int  ent1BladeNum,
gentity_t ent2,
qboolean  checkDir
 

Definition at line 2849 of file w_saber.c.

References BG_SabersOff(), saberInfo_t::blade, gentity_s::client, bladeInfo_t::color, DotProduct, g_saberDebugBox, G_TestLine(), gentity_t, vmCvar_t::integer, bladeInfo_t::lengthMax, MAX_SABERS, bladeInfo_t::muzzleDir, bladeInfo_t::muzzleDirOld, bladeInfo_t::muzzlePoint, bladeInfo_t::muzzlePointOld, saberInfo_t::numBlades, gclient_s::ps, qboolean, qfalse, qtrue, gclient_s::saber, SABER_EXTRAPOLATE_DIST, SABER_NONE, tri_tri_intersect(), saberInfo_t::type, vec3_t, VectorCopy, VectorMA, VectorNormalize(), and VectorSubtract.

02850 {
02851         vec3_t  saberBase1, saberTip1, saberBaseNext1, saberTipNext1;
02852         vec3_t  saberBase2, saberTip2, saberBaseNext2, saberTipNext2;
02853         int             ent2SaberNum = 0, ent2BladeNum = 0;
02854         vec3_t  dir;
02855 
02856         if ( !ent1 || !ent2 )
02857         {
02858                 return qfalse;
02859         }
02860         if ( !ent1->client || !ent2->client )
02861         {
02862                 return qfalse;
02863         }
02864         if ( BG_SabersOff( &ent1->client->ps )
02865                 || BG_SabersOff( &ent2->client->ps ) )
02866         {
02867                 return qfalse;
02868         }
02869 
02870         for ( ent2SaberNum = 0; ent2SaberNum < MAX_SABERS; ent2SaberNum++ )
02871         {
02872                 if ( ent2->client->saber[ent2SaberNum].type != SABER_NONE )
02873                 {
02874                         for ( ent2BladeNum = 0; ent2BladeNum < ent2->client->saber[ent2SaberNum].numBlades; ent2BladeNum++ )
02875                         {
02876                                 if ( ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].lengthMax > 0 )
02877                                 {//valid saber and this blade is on
02878                                         //if ( ent1->client->saberInFlight )
02879                                         {
02880                                                 VectorCopy( ent1->client->saber[ent1SaberNum].blade[ent1BladeNum].muzzlePointOld, saberBase1 );
02881                                                 VectorCopy( ent1->client->saber[ent1SaberNum].blade[ent1BladeNum].muzzlePoint, saberBaseNext1 );
02882 
02883                                                 VectorSubtract( ent1->client->saber[ent1SaberNum].blade[ent1BladeNum].muzzlePoint, ent1->client->saber[ent1SaberNum].blade[ent1BladeNum].muzzlePointOld, dir );
02884                                                 VectorNormalize( dir );
02885                                                 VectorMA( saberBaseNext1, SABER_EXTRAPOLATE_DIST, dir, saberBaseNext1 );
02886 
02887                                                 VectorMA( saberBase1, ent1->client->saber[ent1SaberNum].blade[ent1BladeNum].lengthMax+SABER_EXTRAPOLATE_DIST, ent1->client->saber[ent1SaberNum].blade[ent1BladeNum].muzzleDirOld, saberTip1 );
02888                                                 VectorMA( saberBaseNext1, ent1->client->saber[ent1SaberNum].blade[ent1BladeNum].lengthMax+SABER_EXTRAPOLATE_DIST, ent1->client->saber[ent1SaberNum].blade[ent1BladeNum].muzzleDir, saberTipNext1 );
02889 
02890                                                 VectorSubtract( saberTipNext1, saberTip1, dir );
02891                                                 VectorNormalize( dir );
02892                                                 VectorMA( saberTipNext1, SABER_EXTRAPOLATE_DIST, dir, saberTipNext1 );
02893                                         }
02894                                         /*
02895                                         else
02896                                         {
02897                                                 VectorCopy( ent1->client->saber[ent1SaberNum].blade[ent1BladeNum].muzzlePoint, saberBase1 );
02898                                                 VectorCopy( ent1->client->saber[ent1SaberNum].blade[ent1BladeNum].muzzlePointNext, saberBaseNext1 );
02899                                                 VectorMA( saberBase1, ent1->client->saber[ent1SaberNum].blade[ent1BladeNum].lengthMax, ent1->client->saber[ent1SaberNum].blade[ent1BladeNum].muzzleDir, saberTip1 );
02900                                                 VectorMA( saberBaseNext1, ent1->client->saber[ent1SaberNum].blade[ent1BladeNum].lengthMax, ent1->client->saber[ent1SaberNum].blade[ent1BladeNum].muzzleDirNext, saberTipNext1 );
02901                                         }
02902                                         */
02903 
02904                                         //if ( ent2->client->saberInFlight )
02905                                         {
02906                                                 VectorCopy( ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].muzzlePointOld, saberBase2 );
02907                                                 VectorCopy( ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].muzzlePoint, saberBaseNext2 );
02908 
02909                                                 VectorSubtract( ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].muzzlePoint, ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].muzzlePointOld, dir );
02910                                                 VectorNormalize( dir );
02911                                                 VectorMA( saberBaseNext2, SABER_EXTRAPOLATE_DIST, dir, saberBaseNext2 );
02912 
02913                                                 VectorMA( saberBase2, ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].lengthMax+SABER_EXTRAPOLATE_DIST, ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].muzzleDirOld, saberTip2 );
02914                                                 VectorMA( saberBaseNext2, ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].lengthMax+SABER_EXTRAPOLATE_DIST, ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].muzzleDir, saberTipNext2 );
02915 
02916                                                 VectorSubtract( saberTipNext2, saberTip2, dir );
02917                                                 VectorNormalize( dir );
02918                                                 VectorMA( saberTipNext2, SABER_EXTRAPOLATE_DIST, dir, saberTipNext2 );
02919                                         }
02920                                         /*
02921                                         else
02922                                         {
02923                                                 VectorCopy( ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].muzzlePoint, saberBase2 );
02924                                                 VectorCopy( ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].muzzlePointNext, saberBaseNext2 );
02925                                                 VectorMA( saberBase2, ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].lengthMax, ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].muzzleDir, saberTip2 );
02926                                                 VectorMA( saberBaseNext2, ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].lengthMax, ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].muzzleDirNext, saberTipNext2 );
02927                                         }
02928                                         */
02929                                         if ( checkDir )
02930                                         {//check the direction of the two swings to make sure the sabers are swinging towards each other
02931                                                 vec3_t saberDir1, saberDir2;
02932                                                 float dot = 0.0f;
02933 
02934                                                 VectorSubtract( saberTipNext1, saberTip1, saberDir1 );
02935                                                 VectorSubtract( saberTipNext2, saberTip2, saberDir2 );
02936                                                 VectorNormalize( saberDir1 );
02937                                                 VectorNormalize( saberDir2 );
02938                                                 if ( DotProduct( saberDir1, saberDir2 ) > 0.6f )
02939                                                 {//sabers moving in same dir, probably didn't actually hit
02940                                                         continue;
02941                                                 }
02942                                                 //now check orientation of sabers, make sure they're not parallel or close to it
02943                                                 dot = DotProduct( ent1->client->saber[ent1SaberNum].blade[ent1BladeNum].muzzleDir, ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].muzzleDir );
02944                                                 if ( dot > 0.9f || dot < -0.9f )
02945                                                 {//too parallel to really block effectively?
02946                                                         continue;
02947                                                 }
02948                                         }
02949 
02950 #ifdef DEBUG_SABER_BOX
02951                                         if ( g_saberDebugBox.integer == 2 || g_saberDebugBox.integer == 4 )
02952                                         {
02953                                                 G_TestLine(saberBase1, saberTip1, ent1->client->saber[ent1SaberNum].blade[ent1BladeNum].color, 500);
02954                                                 G_TestLine(saberTip1, saberTipNext1, ent1->client->saber[ent1SaberNum].blade[ent1BladeNum].color, 500);
02955                                                 G_TestLine(saberTipNext1, saberBase1, ent1->client->saber[ent1SaberNum].blade[ent1BladeNum].color, 500);
02956 
02957                                                 G_TestLine(saberBase2, saberTip2, ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].color, 500);
02958                                                 G_TestLine(saberTip2, saberTipNext2, ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].color, 500);
02959                                                 G_TestLine(saberTipNext2, saberBase2, ent2->client->saber[ent2SaberNum].blade[ent2BladeNum].color, 500);
02960                                         }
02961 #endif
02962                                         if ( tri_tri_intersect( saberBase1, saberTip1, saberBaseNext1, saberBase2, saberTip2, saberBaseNext2 ) )
02963                                         {
02964                                                 return qtrue;
02965                                         }
02966                                         if ( tri_tri_intersect( saberBase1, saberTip1, saberBaseNext1, saberBase2, saberTip2, saberTipNext2 ) )
02967                                         {
02968                                                 return qtrue;
02969                                         }
02970                                         if ( tri_tri_intersect( saberBase1, saberTip1, saberTipNext1, saberBase2, saberTip2, saberBaseNext2 ) )
02971                                         {
02972                                                 return qtrue;
02973                                         }
02974                                         if ( tri_tri_intersect( saberBase1, saberTip1, saberTipNext1, saberBase2, saberTip2, saberTipNext2 ) )
02975                                         {
02976                                                 return qtrue;
02977                                         }
02978                                 }
02979                         }
02980                 }
02981         }
02982         return qfalse;
02983 }

void WP_SaberStartMissileBlockCheck gentity_t self,
usercmd_t ucmd
 

Definition at line 5490 of file w_saber.c.

References entityShared_t::absmax, trace_t::allsolid, AngleVectors(), BG_SaberInAttack(), BG_SaberInSpecialAttack(), BG_SaberInTransitionAny(), BG_SabersOff(), BUTTON_ATTACK, usercmd_s::buttons, CLASS_BOBAFETT, CLASS_VEHICLE, gentity_s::client, gentity_s::clipmask, gentity_s::count, entityShared_t::currentAngles, entityShared_t::currentOrigin, DotProduct, EF2_FLYING, EF2_HELD_BY_MONSTER, EF_MISSILE_STICK, entityState_s::eFlags, playerState_s::eFlags2, gentity_s::enemy, trace_t::entityNum, ENTITYNUM_NONE, ENTITYNUM_WORLD, ET_MISSILE, ET_NPC, ET_PLAYER, entityState_s::eType, EVASION_NONE, renderInfo_s::eyePoint, playerState_s::fd, FL_BOUNCE_HALF, gentity_s::flags, forcedata_s::forceJumpCharge, forcedata_s::forcePowerDebounce, forcedata_s::forcePowersActive, ForceThrow(), FP_DRAIN, FP_GRIP, FP_LIGHTNING, FP_PUSH, FP_SABER_DEFENSE, trace_t::fraction, G_ClearLOS4(), g_entities, G_SetEnemy(), gentity_t, playerState_s::groundEntityNum, playerState_s::hasLookTarget, gentity_s::health, InFOV3(), gentity_s::inuse, Jedi_Ambush(), Jedi_SaberBlockGo(), Jedi_WaitingAmbush(), gNPC_t::last_ucmd, level, gentity_s::localAnimIndex, playerState_s::lookTarget, renderInfo_s::lookTarget, MASK_PLAYERSOLID, MAX_GENTITIES, entityShared_t::maxs, gentity_s::methodOfDeath, entityShared_t::mins, MOD_ROCKET_HOMING, gentity_s::nextthink, gentity_s::NPC, entityState_s::NPC_class, gclient_s::NPC_class, NULL, entityState_s::number, OnSameTeam(), playerState_s::origin, entityShared_t::ownerNum, gclient_s::playerTeam, playerState_s::pm_flags, PM_InKnockDown(), PMF_FOLLOW, entityState_s::pos, gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, gclient_s::renderInfo, gentity_s::s, gclient_s::saber, SABER_REFLECT_MISSILE_CONE, playerState_s::saberEntityNum, saberInfo_t::saberFlags, playerState_s::saberInFlight, playerState_s::saberMove, gclient_s::sess, clientSession_t::sessionTeam, SFL_NOT_ACTIVE_BLOCKING, gentity_s::splashDamage, gentity_s::splashRadius, gNPC_t::standTime, trace_t::startsolid, TEAM_SPECTATOR, level_locals_t::time, TIMER_Set(), playerState_s::torsoAnim, TR_GRAVITY, TR_INTERPOLATE, TR_STATIONARY, trap_EntitiesInBox(), trap_Trace(), trajectory_t::trBase, trajectory_t::trDelta, trajectory_t::trTime, trajectory_t::trType, ucmd, usercmd_t, vec3_t, VectorCopy, VectorMA, VectorNormalize(), VectorNormalize2(), VectorScale, VectorSubtract, playerState_s::viewangles, playerState_s::viewheight, entityState_s::weapon, playerState_s::weapon, playerState_s::weaponTime, WP_ActivateSaber(), WP_ForcePowerUsable(), WP_SABER, WP_SaberBlockNonRandom(), and WP_THERMAL.

Referenced by G_RunFrame().

05491 {
05492         float           dist;
05493         gentity_t       *ent, *incoming = NULL;
05494         int                     entityList[MAX_GENTITIES];
05495         int                     numListedEntities;
05496         vec3_t          mins, maxs;
05497         int                     i, e;
05498         float           closestDist, radius = 256;
05499         vec3_t          forward, dir, missile_dir, fwdangles = {0};
05500         trace_t         trace;
05501         vec3_t          traceTo, entDir;
05502         float           dot1, dot2;
05503         float           lookTDist = -1;
05504         gentity_t       *lookT = NULL;
05505         qboolean        doFullRoutine = qtrue;
05506 
05507         //keep this updated even if we don't get below
05508         if ( !(self->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
05509         {//lookTarget is set by and to the monster that's holding you, no other operations can change that
05510                 self->client->ps.hasLookTarget = qfalse;
05511         }
05512 
05513         if ( self->client->ps.weapon != WP_SABER && self->client->NPC_class != CLASS_BOBAFETT )
05514         {
05515                 doFullRoutine = qfalse;
05516         }
05517         else if ( self->client->ps.saberInFlight )
05518         {
05519                 doFullRoutine = qfalse;
05520         }
05521         else if ( self->client->ps.fd.forcePowersActive&(1<<FP_LIGHTNING) )
05522         {//can't block while zapping
05523                 doFullRoutine = qfalse;
05524         }
05525         else if ( self->client->ps.fd.forcePowersActive&(1<<FP_DRAIN) )
05526         {//can't block while draining
05527                 doFullRoutine = qfalse;
05528         }
05529         else if ( self->client->ps.fd.forcePowersActive&(1<<FP_PUSH) )
05530         {//can't block while shoving
05531                 doFullRoutine = qfalse;
05532         }
05533         else if ( self->client->ps.fd.forcePowersActive&(1<<FP_GRIP) )
05534         {//can't block while gripping (FIXME: or should it break the grip?  Pain should break the grip, I think...)
05535                 doFullRoutine = qfalse;
05536         }
05537         
05538         if (self->client->ps.weaponTime > 0)
05539         { //don't autoblock while busy with stuff
05540                 return;
05541         }
05542 
05543         if ( (self->client->saber[0].saberFlags&SFL_NOT_ACTIVE_BLOCKING) )
05544         {//can't actively block with this saber type
05545                 return;
05546         }
05547 
05548         if ( self->health <= 0 )
05549         {//dead don't try to block (NOTE: actual deflection happens in missile code)
05550                 return;
05551         }
05552         if ( PM_InKnockDown( &self->client->ps ) )
05553         {//can't block when knocked down
05554                 return;
05555         }
05556 
05557         if ( BG_SabersOff( &self->client->ps ) && self->client->NPC_class != CLASS_BOBAFETT )
05558         {
05559                 if ( self->s.eType != ET_NPC )
05560                 {//player doesn't auto-activate
05561                         doFullRoutine = qfalse;
05562                 }
05563         }
05564 
05565         if ( self->s.eType == ET_PLAYER )
05566         {//don't do this if already attacking!
05567                 if ( ucmd->buttons & BUTTON_ATTACK 
05568                         || BG_SaberInAttack( self->client->ps.saberMove )
05569                         || BG_SaberInSpecialAttack( self->client->ps.torsoAnim )
05570                         || BG_SaberInTransitionAny( self->client->ps.saberMove ))
05571                 {
05572                         doFullRoutine = qfalse;
05573                 }
05574         }
05575 
05576         if ( self->client->ps.fd.forcePowerDebounce[FP_SABER_DEFENSE] > level.time )
05577         {//can't block while gripping (FIXME: or should it break the grip?  Pain should break the grip, I think...)
05578                 doFullRoutine = qfalse;
05579         }
05580 
05581         fwdangles[1] = self->client->ps.viewangles[1];
05582         AngleVectors( fwdangles, forward, NULL, NULL );
05583 
05584         for ( i = 0 ; i < 3 ; i++ ) 
05585         {
05586                 mins[i] = self->r.currentOrigin[i] - radius;
05587                 maxs[i] = self->r.currentOrigin[i] + radius;
05588         }
05589 
05590         numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
05591 
05592         closestDist = radius;
05593 
05594         for ( e = 0 ; e < numListedEntities ; e++ ) 
05595         {
05596                 ent = &g_entities[entityList[ e ]];
05597 
05598                 if (ent == self)
05599                         continue;
05600 
05601                 //as long as we're here I'm going to get a looktarget too, I guess. -rww
05602                 if (self->s.eType == ET_PLAYER &&
05603                         ent->client &&
05604                         (ent->s.eType == ET_NPC || ent->s.eType == ET_PLAYER) &&
05605                         !OnSameTeam(ent, self) &&
05606                         ent->client->sess.sessionTeam != TEAM_SPECTATOR &&
05607                         !(ent->client->ps.pm_flags & PMF_FOLLOW) &&
05608                         (ent->s.eType != ET_NPC || ent->s.NPC_class != CLASS_VEHICLE) && //don't look at vehicle NPCs
05609                         ent->health > 0)
05610                 { //seems like a valid enemy to look at.
05611                         vec3_t vecSub;
05612                         float vecLen;
05613 
05614                         VectorSubtract(self->client->ps.origin, ent->client->ps.origin, vecSub);
05615                         vecLen = VectorLength(vecSub);
05616 
05617                         if (lookTDist == -1 || vecLen < lookTDist)
05618                         {
05619                                 trace_t tr;
05620                                 vec3_t myEyes;
05621 
05622                                 VectorCopy(self->client->ps.origin, myEyes);
05623                                 myEyes[2] += self->client->ps.viewheight;
05624 
05625                                 trap_Trace(&tr, myEyes, NULL, NULL, ent->client->ps.origin, self->s.number, MASK_PLAYERSOLID);
05626 
05627                                 if (tr.fraction == 1.0f || tr.entityNum == ent->s.number)
05628                                 { //we have a clear line of sight to him, so it's all good.
05629                                         lookT = ent;
05630                                         lookTDist = vecLen;
05631                                 }
05632                         }
05633                 }
05634 
05635                 if (!doFullRoutine)
05636                 { //don't care about the rest then
05637                         continue;
05638                 }
05639 
05640                 if (ent->r.ownerNum == self->s.number)
05641                         continue;
05642                 if ( !(ent->inuse) )
05643                         continue;
05644                 if ( ent->s.eType != ET_MISSILE && !(ent->s.eFlags&EF_MISSILE_STICK) )
05645                 {//not a normal projectile
05646                         gentity_t *pOwner;
05647 
05648                         if (ent->r.ownerNum < 0 || ent->r.ownerNum >= ENTITYNUM_WORLD)
05649                         { //not going to be a client then.
05650                                 continue;
05651                         }
05652                                 
05653                         pOwner = &g_entities[ent->r.ownerNum];
05654 
05655                         if (!pOwner->inuse || !pOwner->client)
05656                         {
05657                                 continue; //not valid cl owner
05658                         }
05659 
05660                         if (!pOwner->client->ps.saberEntityNum ||
05661                                 !pOwner->client->ps.saberInFlight ||
05662                                 pOwner->client->ps.saberEntityNum != ent->s.number)
05663                         { //the saber is knocked away and/or not flying actively, or this ent is not the cl's saber ent at all
05664                                 continue;
05665                         }
05666 
05667                         //If we get here then it's ok to be treated as a thrown saber, I guess.
05668                 }
05669                 else
05670                 {
05671                         if ( ent->s.pos.trType == TR_STATIONARY && self->s.eType == ET_PLAYER )
05672                         {//nothing you can do with a stationary missile if you're the player
05673                                 continue;
05674                         }
05675                 }
05676 
05677                 //see if they're in front of me
05678                 VectorSubtract( ent->r.currentOrigin, self->r.currentOrigin, dir );
05679                 dist = VectorNormalize( dir );
05680                 //FIXME: handle detpacks, proximity mines and tripmines
05681                 if ( ent->s.weapon == WP_THERMAL )
05682                 {//thermal detonator!
05683                         if ( self->NPC && dist < ent->splashRadius )
05684                         {
05685                                 if ( dist < ent->splashRadius && 
05686                                         ent->nextthink < level.time + 600 && 
05687                                         ent->count && 
05688                                         self->client->ps.groundEntityNum != ENTITYNUM_NONE && 
05689                                                 (ent->s.pos.trType == TR_STATIONARY||
05690                                                 ent->s.pos.trType == TR_INTERPOLATE||
05691                                                 (dot1 = DotProduct( dir, forward )) < SABER_REFLECT_MISSILE_CONE||
05692                                                 !WP_ForcePowerUsable( self, FP_PUSH )) )
05693                                 {//TD is close enough to hurt me, I'm on the ground and the thing is at rest or behind me and about to blow up, or I don't have force-push so force-jump!
05694                                         //FIXME: sometimes this might make me just jump into it...?
05695                                         self->client->ps.fd.forceJumpCharge = 480;
05696                                 }
05697                                 else if ( self->client->NPC_class != CLASS_BOBAFETT )
05698                                 {//FIXME: check forcePushRadius[NPC->client->ps.forcePowerLevel[FP_PUSH]]
05699                                         ForceThrow( self, qfalse );
05700                                 }
05701                         }
05702                         continue;
05703                 }
05704                 else if ( ent->splashDamage && ent->splashRadius )
05705                 {//exploding missile
05706                         //FIXME: handle tripmines and detpacks somehow... 
05707                         //                      maybe do a force-gesture that makes them explode?  
05708                         //                      But what if we're within it's splashradius?
05709                         if ( self->s.eType == ET_PLAYER )
05710                         {//players don't auto-handle these at all
05711                                 continue;
05712                         }
05713                         else 
05714                         {
05715                                 //if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags&EF_MISSILE_STICK) 
05716                                 //      &&      self->client->NPC_class != CLASS_BOBAFETT )
05717                                 if (0) //Maybe handle this later?
05718                                 {//a placed explosive like a tripmine or detpack
05719                                         if ( InFOV3( ent->r.currentOrigin, self->client->renderInfo.eyePoint, self->client->ps.viewangles, 90, 90 ) )
05720                                         {//in front of me
05721                                                 if ( G_ClearLOS4( self, ent ) )
05722                                                 {//can see it
05723                                                         vec3_t throwDir;
05724                                                         //make the gesture
05725                                                         ForceThrow( self, qfalse );
05726                                                         //take it off the wall and toss it
05727                                                         ent->s.pos.trType = TR_GRAVITY;
05728                                                         ent->s.eType = ET_MISSILE;
05729                                                         ent->s.eFlags &= ~EF_MISSILE_STICK;
05730                                                         ent->flags |= FL_BOUNCE_HALF;
05731                                                         AngleVectors( ent->r.currentAngles, throwDir, NULL, NULL );
05732                                                         VectorMA( ent->r.currentOrigin, ent->r.maxs[0]+4, throwDir, ent->r.currentOrigin );
05733                                                         VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
05734                                                         VectorScale( throwDir, 300, ent->s.pos.trDelta );
05735                                                         ent->s.pos.trDelta[2] += 150;
05736                                                         VectorMA( ent->s.pos.trDelta, 800, dir, ent->s.pos.trDelta );
05737                                                         ent->s.pos.trTime = level.time;         // move a bit on the very first frame
05738                                                         VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
05739                                                         ent->r.ownerNum = self->s.number;
05740                                                         // make it explode, but with less damage
05741                                                         ent->splashDamage /= 3;
05742                                                         ent->splashRadius /= 3;
05743                                                         //ent->think = WP_Explode;
05744                                                         ent->nextthink =