#include "b_local.h"#include "g_nav.h"#include "anims.h"#include "w_saber.h"#include "../namespace_begin.h"#include "../namespace_end.h"Go to the source code of this file.
|
|
Definition at line 4469 of file NPC_AI_Jedi.c. Referenced by NPC_BSJump(). |
|
|
Definition at line 34 of file NPC_AI_Jedi.c. |
|
|
Definition at line 27 of file NPC_AI_Jedi.c. |
|
|
Definition at line 30 of file NPC_AI_Jedi.c. |
|
|
Definition at line 23 of file NPC_AI_Jedi.c. |
|
|
Definition at line 25 of file NPC_AI_Jedi.c. |
|
|
Definition at line 24 of file NPC_AI_Jedi.c. |
|
|
Definition at line 4471 of file NPC_AI_Jedi.c. |
|
|
Definition at line 31 of file NPC_AI_Jedi.c. |
|
|
Definition at line 36 of file NPC_AI_Jedi.c. |
|
|
Definition at line 21 of file NPC_AI_Jedi.c. |
|
|
Definition at line 22 of file NPC_AI_Jedi.c. |
|
|
Definition at line 4470 of file NPC_AI_Jedi.c. |
|
|
Definition at line 33 of file NPC_AI_Jedi.c. |
|
|
Definition at line 29 of file NPC_AI_Jedi.c. |
|
|
Definition at line 96 of file NPC_AI_Jedi.c.
00097 {
00098 LSTATE_NONE = 0,
00099 LSTATE_UNDERFIRE,
00100 LSTATE_INVESTIGATE,
00101 };
|
|
|
Definition at line 49 of file bg_panimate.c.
00050 {
00051 switch ( anim )
00052 {
00053 case BOTH_SIT1: //# Normal chair sit.
00054 case BOTH_SIT2: //# Lotus position.
00055 case BOTH_SIT3: //# Sitting in tired position: elbows on knees
00056 case BOTH_CROUCH1: //# Transition from standing to crouch
00057 case BOTH_CROUCH1IDLE: //# Crouching idle
00058 case BOTH_CROUCH1WALK: //# Walking while crouched
00059 case BOTH_CROUCH1WALKBACK: //# Walking while crouched
00060 case BOTH_CROUCH2TOSTAND1: //# going from crouch2 to stand1
00061 case BOTH_CROUCH3: //# Desann crouching down to Kyle (cin 9)
00062 case BOTH_KNEES1: //# Tavion on her knees
00063 case BOTH_CROUCHATTACKBACK1://FIXME: not if in middle of anim?
00064 case BOTH_ROLL_STAB:
00065 return qtrue;
00066 break;
00067 }
00068 return qfalse;
00069 }
|
|
|
Definition at line 1941 of file bg_misc.c.
|
|
|
Definition at line 433 of file bg_panimate.c.
00434 {
00435 switch ( anim )
00436 {
00437 case BOTH_FLIP_F: //# Flip forward
00438 case BOTH_FLIP_B: //# Flip backwards
00439 case BOTH_FLIP_L: //# Flip left
00440 case BOTH_FLIP_R: //# Flip right
00441 case BOTH_WALL_RUN_RIGHT_FLIP:
00442 case BOTH_WALL_RUN_LEFT_FLIP:
00443 case BOTH_WALL_FLIP_RIGHT:
00444 case BOTH_WALL_FLIP_LEFT:
00445 case BOTH_FLIP_BACK1:
00446 case BOTH_FLIP_BACK2:
00447 case BOTH_FLIP_BACK3:
00448 case BOTH_WALL_FLIP_BACK1:
00449 //Not really flips, but...
00450 case BOTH_WALL_RUN_RIGHT:
00451 case BOTH_WALL_RUN_LEFT:
00452 case BOTH_WALL_RUN_RIGHT_STOP:
00453 case BOTH_WALL_RUN_LEFT_STOP:
00454 case BOTH_BUTTERFLY_LEFT:
00455 case BOTH_BUTTERFLY_RIGHT:
00456 case BOTH_BUTTERFLY_FL1:
00457 case BOTH_BUTTERFLY_FR1:
00458 //
00459 case BOTH_ARIAL_LEFT:
00460 case BOTH_ARIAL_RIGHT:
00461 case BOTH_ARIAL_F1:
00462 case BOTH_CARTWHEEL_LEFT:
00463 case BOTH_CARTWHEEL_RIGHT:
00464 case BOTH_JUMPFLIPSLASHDOWN1:
00465 case BOTH_JUMPFLIPSTABDOWN:
00466 case BOTH_JUMPATTACK6:
00467 case BOTH_JUMPATTACK7:
00468 //JKA
00469 case BOTH_FORCEWALLRUNFLIP_END:
00470 case BOTH_FORCEWALLRUNFLIP_ALT:
00471 case BOTH_FLIP_ATTACK7:
00472 case BOTH_A7_SOULCAL:
00473 return qtrue;
00474 break;
00475 }
00476 return qfalse;
00477 }
|
|
||||||||||||
|
|
|
|
Definition at line 201 of file bg_pmove.c.
00202 {
00203 if ( !ps->saberHolstered )
00204 {
00205 return qfalse;
00206 }
00207 if ( ps->fd.saberAnimLevelBase == SS_DUAL
00208 || ps->fd.saberAnimLevelBase == SS_STAFF )
00209 {
00210 if ( ps->saberHolstered < 2 )
00211 {
00212 return qfalse;
00213 }
00214 }
00215 return qtrue;
00216 }
|
|
|
|
Definition at line 193 of file NPC_AI_Jedi.c. References EV_GENERAL_SOUND, G_AddEvent(), G_SoundIndex(), NPC, NPC_ChangeWeapon(), gentity_s::s, and entityState_s::weapon. Referenced by Boba_FireDecide(), and NPC_BSJedi_Default().
00194 {
00195 if ( NPC->s.weapon == wp )
00196 {
00197 return;
00198 }
00199 NPC_ChangeWeapon( wp );
00200 G_AddEvent( NPC, EV_GENERAL_SOUND, G_SoundIndex( "sound/weapons/change.wav" ));
00201 }
|
|
|
Definition at line 471 of file NPC_AI_Jedi.c. References Boba_FireFlameThrower(), Boba_StartFlameThrower(), BOTH_FORCELIGHTNING_HOLD, gentity_t, NPC_SetAnim(), SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, SETANIM_TORSO, and TIMER_Done(). Referenced by Boba_FireDecide().
00472 {
00473 NPC_SetAnim( self, SETANIM_TORSO, BOTH_FORCELIGHTNING_HOLD, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00474 if ( TIMER_Done( self, "nextAttackDelay" ) && TIMER_Done( self, "flameTime" ) )
00475 {
00476 Boba_StartFlameThrower( self );
00477 }
00478 Boba_FireFlameThrower( self );
00479 }
|
|
|
TIMER_Done( NPC, "stick" ) || Definition at line 481 of file NPC_AI_Jedi.c. References AngleVectors(), BG_FlippingAnim(), Boba_ChangeWeapon(), Boba_DoFlameThrower(), Boba_FlyStart(), gNPC_t::burstMax, gNPC_t::burstMean, gNPC_t::burstMin, gNPC_t::burstSpacing, BUTTON_ALT_ATTACK, BUTTON_ATTACK, usercmd_s::buttons, CalcEntitySpot(), gentity_s::client, entityShared_t::currentOrigin, gNPC_t::desiredPitch, gNPC_t::desiredYaw, DotProduct, trace_t::endpos, gentity_s::enemy, enemyDist, gNPC_t::enemyLastSeenLocation, gNPC_t::enemyLastSeenTime, gclient_s::enemyTeam, ENTITYNUM_NONE, playerState_s::fd, forcedata_s::forceJumpZStart, g_entities, gentity_t, playerState_s::groundEntityNum, gNPC_t::group, gentity_s::health, AIGroupInfo_s::lastSeenEnemyTime, playerState_s::legsAnim, level, MASK_SHOT, clientPersistant_t::maxHealth, MIN_ROCKET_DIST_SQUARED, NPC, NPC_ChangeWeapon(), NPC_ClearLOS4(), NPC_ShotEntity(), NPC_UpdateAngles(), NPCInfo, NULL, entityState_s::number, gclient_s::pers, PITCH, gclient_s::playerTeam, gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, SCF_ALT_FIRE, SCF_FIRE_WEAPON, gNPC_t::scriptFlags, SPOT_HEAD, SVF_GLASS_BRUSH, entityShared_t::svFlags, gentity_s::takedamage, level_locals_t::time, TIMER_Done(), TIMER_Set(), trap_InPVS(), trap_Trace(), ucmd, vec3_origin, vec3_t, vectoangles(), VectorClear, VectorCopy, VectorMA, VectorNormalize(), VectorSubtract, playerState_s::viewangles, entityState_s::weapon, playerState_s::weapon, WeaponThink(), playerState_s::weaponTime, WP_BLASTER, WP_DET_PACK, WP_DISRUPTOR, WP_EMPLACED_GUN, WP_FLECHETTE, WP_NONE, WP_REPEATER, WP_ROCKET_LAUNCHER, WP_SABER, WP_THERMAL, WP_TRIP_MINE, and YAW. Referenced by NPC_BSSeeker_Default().
00482 {
00483 qboolean enemyLOS = qfalse;
00484 qboolean enemyCS = qfalse;
00485 qboolean enemyInFOV = qfalse;
00486 //qboolean move = qtrue;
00487 qboolean faceEnemy = qfalse;
00488 qboolean shoot = qfalse;
00489 qboolean hitAlly = qfalse;
00490 vec3_t impactPos;
00491 float enemyDist;
00492 float dot;
00493 vec3_t enemyDir, shootDir;
00494
00495 if ( NPC->client->ps.groundEntityNum == ENTITYNUM_NONE
00496 && NPC->client->ps.fd.forceJumpZStart
00497 && !BG_FlippingAnim( NPC->client->ps.legsAnim )
00498 && !Q_irand( 0, 10 ) )
00499 {//take off
00500 Boba_FlyStart( NPC );
00501 }
00502
00503 if ( !NPC->enemy )
00504 {
00505 return;
00506 }
00507
00508 /*
00509 if ( NPC->enemy->enemy != NPC && NPC->health == NPC->client->pers.maxHealth )
00510 {
00511 NPCInfo->scriptFlags |= SCF_ALT_FIRE;
00512 Boba_ChangeWeapon( WP_DISRUPTOR );
00513 }
00514 else */if ( NPC->enemy->s.weapon == WP_SABER )
00515 {
00516 NPCInfo->scriptFlags &= ~SCF_ALT_FIRE;
00517 Boba_ChangeWeapon( WP_ROCKET_LAUNCHER );
00518 }
00519 else
00520 {
00521 if ( NPC->health < NPC->client->pers.maxHealth*0.5f )
00522 {
00523 NPCInfo->scriptFlags |= SCF_ALT_FIRE;
00524 Boba_ChangeWeapon( WP_BLASTER );
00525 NPCInfo->burstMin = 3;
00526 NPCInfo->burstMean = 12;
00527 NPCInfo->burstMax = 20;
00528 NPCInfo->burstSpacing = Q_irand( 300, 750 );//attack debounce
00529 }
00530 else
00531 {
00532 NPCInfo->scriptFlags &= ~SCF_ALT_FIRE;
00533 Boba_ChangeWeapon( WP_BLASTER );
00534 }
00535 }
00536
00537 VectorClear( impactPos );
00538 enemyDist = DistanceSquared( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin );
00539
00540 VectorSubtract( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, enemyDir );
00541 VectorNormalize( enemyDir );
00542 AngleVectors( NPC->client->ps.viewangles, shootDir, NULL, NULL );
00543 dot = DotProduct( enemyDir, shootDir );
00544 if ( dot > 0.5f ||( enemyDist * (1.0f-dot)) < 10000 )
00545 {//enemy is in front of me or they're very close and not behind me
00546 enemyInFOV = qtrue;
00547 }
00548
00549 if ( (enemyDist < (128*128)&&enemyInFOV) || !TIMER_Done( NPC, "flameTime" ) )
00550 {//flamethrower
00551 Boba_DoFlameThrower( NPC );
00552 enemyCS = qfalse;
00553 shoot = qfalse;
00554 NPCInfo->enemyLastSeenTime = level.time;
00555 faceEnemy = qtrue;
00556 ucmd.buttons &= ~(BUTTON_ATTACK|BUTTON_ALT_ATTACK);
00557 }
00558 else if ( enemyDist < MIN_ROCKET_DIST_SQUARED )//128
00559 {//enemy within 128
00560 if ( (NPC->client->ps.weapon == WP_FLECHETTE || NPC->client->ps.weapon == WP_REPEATER) &&
00561 (NPCInfo->scriptFlags & SCF_ALT_FIRE) )
00562 {//shooting an explosive, but enemy too close, switch to primary fire
00563 NPCInfo->scriptFlags &= ~SCF_ALT_FIRE;
00564 //FIXME: we can never go back to alt-fire this way since, after this, we don't know if we were initially supposed to use alt-fire or not...
00565 }
00566 }
00567 else if ( enemyDist > 65536 )//256 squared
00568 {
00569 if ( NPC->client->ps.weapon == WP_DISRUPTOR )
00570 {//sniping... should be assumed
00571 if ( !(NPCInfo->scriptFlags&SCF_ALT_FIRE) )
00572 {//use primary fire
00573 NPCInfo->scriptFlags |= SCF_ALT_FIRE;
00574 //reset fire-timing variables
00575 NPC_ChangeWeapon( WP_DISRUPTOR );
00576 NPC_UpdateAngles( qtrue, qtrue );
00577 return;
00578 }
00579 }
00580 }
00581
00582 //can we see our target?
00583 if ( TIMER_Done( NPC, "nextAttackDelay" ) && TIMER_Done( NPC, "flameTime" ) )
00584 {
00585 if ( NPC_ClearLOS4( NPC->enemy ) )
00586 {
00587 NPCInfo->enemyLastSeenTime = level.time;
00588 enemyLOS = qtrue;
00589
00590 if ( NPC->client->ps.weapon == WP_NONE )
00591 {
00592 enemyCS = qfalse;//not true, but should stop us from firing
00593 }
00594 else
00595 {//can we shoot our target?
00596 if ( (NPC->client->ps.weapon == WP_ROCKET_LAUNCHER || (NPC->client->ps.weapon == WP_FLECHETTE && (NPCInfo->scriptFlags&SCF_ALT_FIRE))) && enemyDist < MIN_ROCKET_DIST_SQUARED )//128*128
00597 {
00598 enemyCS = qfalse;//not true, but should stop us from firing
00599 hitAlly = qtrue;//us!
00600 //FIXME: if too close, run away!
00601 }
00602 else if ( enemyInFOV )
00603 {//if enemy is FOV, go ahead and check for shooting
00604 int hit = NPC_ShotEntity( NPC->enemy, impactPos );
00605 gentity_t *hitEnt = &g_entities[hit];
00606
00607 if ( hit == NPC->enemy->s.number
00608 || ( hitEnt && hitEnt->client && hitEnt->client->playerTeam == NPC->client->enemyTeam )
00609 || ( hitEnt && hitEnt->takedamage && ((hitEnt->r.svFlags&SVF_GLASS_BRUSH)||hitEnt->health < 40||NPC->s.weapon == WP_EMPLACED_GUN) ) )
00610 {//can hit enemy or enemy ally or will hit glass or other minor breakable (or in emplaced gun), so shoot anyway
00611 enemyCS = qtrue;
00612 //NPC_AimAdjust( 2 );//adjust aim better longer we have clear shot at enemy
00613 VectorCopy( NPC->enemy->r.currentOrigin, NPCInfo->enemyLastSeenLocation );
00614 }
00615 else
00616 {//Hmm, have to get around this bastard
00617 //NPC_AimAdjust( 1 );//adjust aim better longer we can see enemy
00618 if ( hitEnt && hitEnt->client && hitEnt->client->playerTeam == NPC->client->playerTeam )
00619 {//would hit an ally, don't fire!!!
00620 hitAlly = qtrue;
00621 }
00622 else
00623 {//Check and see where our shot *would* hit... if it's not close to the enemy (within 256?), then don't fire
00624 }
00625 }
00626 }
00627 else
00628 {
00629 enemyCS = qfalse;//not true, but should stop us from firing
00630 }
00631 }
00632 }
00633 else if ( trap_InPVS( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin ) )
00634 {
00635 NPCInfo->enemyLastSeenTime = level.time;
00636 faceEnemy = qtrue;
00637 //NPC_AimAdjust( -1 );//adjust aim worse longer we cannot see enemy
00638 }
00639
00640 if ( NPC->client->ps.weapon == WP_NONE )
00641 {
00642 faceEnemy = qfalse;
00643 shoot = qfalse;
00644 }
00645 else
00646 {
00647 if ( enemyLOS )
00648 {//FIXME: no need to face enemy if we're moving to some other goal and he's too far away to shoot?
00649 faceEnemy = qtrue;
00650 }
00651 if ( enemyCS )
00652 {
00653 shoot = qtrue;
00654 }
00655 }
00656
00657 if ( !enemyCS )
00658 {//if have a clear shot, always try
00659 //See if we should continue to fire on their last position
00661 if ( !hitAlly //we're not going to hit an ally
00662 && enemyInFOV //enemy is in our FOV //FIXME: or we don't have a clear LOS?
00663 && NPCInfo->enemyLastSeenTime > 0 )//we've seen the enemy
00664 {
00665 if ( level.time - NPCInfo->enemyLastSeenTime < 10000 )//we have seem the enemy in the last 10 seconds
00666 {
00667 if ( !Q_irand( 0, 10 ) )
00668 {
00669 //Fire on the last known position
00670 vec3_t muzzle, dir, angles;
00671 qboolean tooClose = qfalse;
00672 qboolean tooFar = qfalse;
00673 float distThreshold;
00674 float dist;
00675
00676 CalcEntitySpot( NPC, SPOT_HEAD, muzzle );
00677 if ( VectorCompare( impactPos, vec3_origin ) )
00678 {//never checked ShotEntity this frame, so must do a trace...
00679 trace_t tr;
00680 //vec3_t mins = {-2,-2,-2}, maxs = {2,2,2};
00681 vec3_t forward, end;
00682 AngleVectors( NPC->client->ps.viewangles, forward, NULL, NULL );
00683 VectorMA( muzzle, 8192, forward, end );
00684 trap_Trace( &tr, muzzle, vec3_origin, vec3_origin, end, NPC->s.number, MASK_SHOT );
00685 VectorCopy( tr.endpos, impactPos );
00686 }
00687
00688 //see if impact would be too close to me
00689 distThreshold = 16384/*128*128*/;//default
00690 switch ( NPC->s.weapon )
00691 {
00692 case WP_ROCKET_LAUNCHER:
00693 case WP_FLECHETTE:
00694 case WP_THERMAL:
00695 case WP_TRIP_MINE:
00696 case WP_DET_PACK:
00697 distThreshold = 65536/*256*256*/;
00698 break;
00699 case WP_REPEATER:
00700 if ( NPCInfo->scriptFlags&SCF_ALT_FIRE )
00701 {
00702 distThreshold = 65536/*256*256*/;
00703 }
00704 break;
00705 default:
00706 break;
00707 }
00708
00709 dist = DistanceSquared( impactPos, muzzle );
00710
00711 if ( dist < distThreshold )
00712 {//impact would be too close to me
00713 tooClose = qtrue;
00714 }
00715 else if ( level.time - NPCInfo->enemyLastSeenTime > 5000 ||
00716 (NPCInfo->group && level.time - NPCInfo->group->lastSeenEnemyTime > 5000 ))
00717 {//we've haven't seen them in the last 5 seconds
00718 //see if it's too far from where he is
00719 distThreshold = 65536/*256*256*/;//default
00720 switch ( NPC->s.weapon )
00721 {
00722 case WP_ROCKET_LAUNCHER:
00723 case WP_FLECHETTE:
00724 case WP_THERMAL:
00725 case WP_TRIP_MINE:
00726 case WP_DET_PACK:
00727 distThreshold = 262144/*512*512*/;
00728 break;
00729 case WP_REPEATER:
00730 if ( NPCInfo->scriptFlags&SCF_ALT_FIRE )
00731 {
00732 distThreshold = 262144/*512*512*/;
00733 }
00734 break;
00735 default:
00736 break;
00737 }
00738 dist = DistanceSquared( impactPos, NPCInfo->enemyLastSeenLocation );
00739 if ( dist > distThreshold )
00740 {//impact would be too far from enemy
00741 tooFar = qtrue;
00742 }
00743 }
00744
00745 if ( !tooClose && !tooFar )
00746 {//okay too shoot at last pos
00747 VectorSubtract( NPCInfo->enemyLastSeenLocation, muzzle, dir );
00748 VectorNormalize( dir );
00749 vectoangles( dir, angles );
00750
00751 NPCInfo->desiredYaw = angles[YAW];
00752 NPCInfo->desiredPitch = angles[PITCH];
00753
00754 shoot = qtrue;
00755 faceEnemy = qfalse;
00756 }
00757 }
00758 }
00759 }
00760 }
00761
00762 //FIXME: don't shoot right away!
00763 if ( NPC->client->ps.weaponTime > 0 )
00764 {
00765 if ( NPC->s.weapon == WP_ROCKET_LAUNCHER )
00766 {
00767 if ( !enemyLOS || !enemyCS )
00768 {//cancel it
00769 NPC->client->ps.weaponTime = 0;
00770 }
00771 else
00772 {//delay our next attempt
00773 TIMER_Set( NPC, "nextAttackDelay", Q_irand( 500, 1000 ) );
00774 }
00775 }
00776 }
00777 else if ( shoot )
00778 {//try to shoot if it's time
00779 if ( TIMER_Done( NPC, "nextAttackDelay" ) )
00780 {
00781 if( !(NPCInfo->scriptFlags & SCF_FIRE_WEAPON) ) // we've already fired, no need to do it again here
00782 {
00783 WeaponThink( qtrue );
00784 }
00785 //NASTY
00786 if ( NPC->s.weapon == WP_ROCKET_LAUNCHER
00787 && (ucmd.buttons&BUTTON_ATTACK)
00788 && !Q_irand( 0, 3 ) )
00789 {//every now and then, shoot a homing rocket
00790 ucmd.buttons &= ~BUTTON_ATTACK;
00791 ucmd.buttons |= BUTTON_ALT_ATTACK;
00792 NPC->client->ps.weaponTime = Q_irand( 500, 1500 );
00793 }
00794 }
00795 }
00796 }
00797 }
|
|
|
Definition at line 391 of file NPC_AI_Jedi.c. References gentity_s::client, entityShared_t::currentAngles, entityShared_t::currentOrigin, DAMAGE_IGNORE_TEAM, DAMAGE_NO_ARMOR, DAMAGE_NO_KNOCKBACK, trace_t::endpos, trace_t::entityNum, ENTITYNUM_WORLD, G_Damage(), g_entities, gentity_t, gentity_s::ghoul2, renderInfo_s::handLBolt, level, MASK_SHOT, MOD_LAVA, gentity_s::modelScale, NEGATIVE_Y, NULL, entityState_s::number, ORIGIN, Q_irand(), gentity_s::r, gclient_s::renderInfo, gentity_s::s, gentity_s::takedamage, level_locals_t::time, trap_G2API_GetBoltMatrix(), trap_Trace(), vec3_t, and VectorMA. Referenced by Boba_DoFlameThrower().
00392 {
00393 int damage = Q_irand( 20, 30 );
00394 trace_t tr;
00395 gentity_t *traceEnt = NULL;
00396 mdxaBone_t boltMatrix;
00397 vec3_t start, end, dir, traceMins = {-4, -4, -4}, traceMaxs = {4, 4, 4};
00398
00399 trap_G2API_GetBoltMatrix( self->ghoul2, 0, self->client->renderInfo.handLBolt,
00400 &boltMatrix, self->r.currentAngles, self->r.currentOrigin, level.time,
00401 NULL, self->modelScale );
00402
00403 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, start );
00404 BG_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_Y, dir );
00405 //G_PlayEffect( "boba/fthrw", start, dir );
00406 VectorMA( start, 128, dir, end );
00407
00408 trap_Trace( &tr, start, traceMins, traceMaxs, end, self->s.number, MASK_SHOT );
00409
00410 traceEnt = &g_entities[tr.entityNum];
00411 if ( tr.entityNum < ENTITYNUM_WORLD && traceEnt->takedamage )
00412 {
00413 G_Damage( traceEnt, self, self, dir, tr.endpos, damage, DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK|/*DAMAGE_NO_HIT_LOC|*/DAMAGE_IGNORE_TEAM, MOD_LAVA );
00414 //rwwFIXMEFIXME: add DAMAGE_NO_HIT_LOC?
00415 }
00416 }
|
|
|
Definition at line 386 of file NPC_AI_Jedi.c. References gentity_s::client, EF2_FLYING, playerState_s::eFlags2, gentity_t, gclient_s::ps, and qboolean. Referenced by NPC_RunBehavior().
00387 {
00388 return ((qboolean)(self->client->ps.eFlags2&EF2_FLYING));//moveType==MT_FLYSWIM));
00389 }
|
|
|
Definition at line 345 of file NPC_AI_Jedi.c. References gNPC_t::aiFlags, CHAN_ITEM, gentity_s::client, gentity_s::count, EF2_FLYING, playerState_s::eFlags2, G_SoundIndex(), G_SoundOnEnt(), gentity_t, playerState_s::gravity, gclient_s::jetPackTime, level, entityState_s::loopSound, gentity_s::NPC, NPCAI_CUSTOM_GRAVITY, gclient_s::ps, Q3_INFINITE, Q_irand(), gentity_s::s, level_locals_t::time, and TIMER_Done(). Referenced by Boba_FireDecide().
00346 {//switch to seeker AI for a while
00347 if ( TIMER_Done( self, "jetRecharge" ) )
00348 {
00349 self->client->ps.gravity = 0;
00350 if ( self->NPC )
00351 {
00352 self->NPC->aiFlags |= NPCAI_CUSTOM_GRAVITY;
00353 }
00354 self->client->ps.eFlags2 |= EF2_FLYING;//moveType = MT_FLYSWIM;
00355 self->client->jetPackTime = level.time + Q_irand( 3000, 10000 );
00356 //take-off sound
00357 G_SoundOnEnt( self, CHAN_ITEM, "sound/boba/jeton.wav" );
00358 //jet loop sound
00359 self->s.loopSound = G_SoundIndex( "sound/boba/jethover.wav" );
00360 if ( self->NPC )
00361 {
00362 self->count = Q3_INFINITE; // SEEKER shot ammo count
00363 }
00364 }
00365 }
|
|
|
Definition at line 367 of file NPC_AI_Jedi.c. References gNPC_t::aiFlags, gentity_s::client, gentity_s::count, EF2_FLYING, playerState_s::eFlags2, g_gravity, gentity_t, playerState_s::gravity, gclient_s::jetPackTime, entityState_s::loopSound, gentity_s::NPC, NPCAI_CUSTOM_GRAVITY, gclient_s::ps, Q_irand(), gentity_s::s, TIMER_Set(), and vmCvar_t::value. Referenced by player_die().
00368 {
00369 self->client->ps.gravity = g_gravity.value;
00370 if ( self->NPC )
00371 {
00372 self->NPC->aiFlags &= ~NPCAI_CUSTOM_GRAVITY;
00373 }
00374 self->client->ps.eFlags2 &= ~EF2_FLYING;
00375 self->client->jetPackTime = 0;
00376 //stop jet loop sound
00377 self->s.loopSound = 0;
00378 if ( self->NPC )
00379 {
00380 self->count = 0; // SEEKER shot ammo count
00381 TIMER_Set( self, "jetRecharge", Q_irand( 1000, 5000 ) );
00382 TIMER_Set( self, "jumpChaseDebounce", Q_irand( 500, 2000 ) );
00383 }
00384 }
|
|
|
Definition at line 182 of file NPC_AI_Jedi.c. References G_EffectIndex(), and G_SoundIndex(). Referenced by NPC_SetMiscDefaultData().
00183 {
00184 G_SoundIndex( "sound/boba/jeton.wav" );
00185 G_SoundIndex( "sound/boba/jethover.wav" );
00186 G_SoundIndex( "sound/effects/combustfire.mp3" );
00187 G_EffectIndex( "boba/jet" );
00188 G_EffectIndex( "boba/fthrw" );
00189 }
|
|
|
Definition at line 419 of file NPC_AI_Jedi.c. References CHAN_WEAPON, gentity_s::client, entityShared_t::currentAngles, entityShared_t::currentOrigin, G_EffectIndex(), G_PlayEffectID(), G_SoundOnEnt(), gentity_t, gentity_s::ghoul2, renderInfo_s::handRBolt, level, gentity_s::modelScale, NEGATIVE_Y, NPC, gentity_s::NPC, NULL, ORIGIN, gclient_s::ps, gentity_s::r, gclient_s::renderInfo, level_locals_t::time, TIMER_Set(), playerState_s::torsoTimer, trap_G2API_GetBoltMatrix(), and vec3_t. Referenced by Boba_DoFlameThrower().
00420 {
00421 int flameTime = 4000;//Q_irand( 1000, 3000 );
00422 mdxaBone_t boltMatrix;
00423 vec3_t org, dir;
00424
00425 self->client->ps.torsoTimer = flameTime;//+1000;
00426 if ( self->NPC )
00427 {
00428 TIMER_Set( self, "nextAttackDelay", flameTime );
00429 TIMER_Set( self, "walking", 0 );
00430 }
00431 TIMER_Set( self, "flameTime", flameTime );
00432 /*
00433 gentity_t *fire = G_Spawn();
00434 if ( fire != NULL )
00435 {
00436 mdxaBone_t boltMatrix;
00437 vec3_t org, dir, ang;
00438 gi.G2API_GetBoltMatrix( NPC->ghoul2, NPC->playerModel, NPC->handRBolt,
00439 &boltMatrix, NPC->r.currentAngles, NPC->r.currentOrigin, (cg.time?cg.time:level.time),
00440 NULL, NPC->s.modelScale );
00441
00442 gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, org );
00443 gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, dir );
00444 vectoangles( dir, ang );
00445
00446 VectorCopy( org, fire->s.origin );
00447 VectorCopy( ang, fire->s.angles );
00448
00449 fire->targetname = "bobafire";
00450 SP_fx_explosion_trail( fire );
00451 fire->damage = 1;
00452 fire->radius = 10;
00453 fire->speed = 200;
00454 fire->fxID = G_EffectIndex( "boba/fthrw" );//"env/exp_fire_trail" );//"env/small_fire"
00455 fx_explosion_trail_link( fire );
00456 fx_explosion_trail_use( fire, NPC, NPC );
00457
00458 }
00459 */
00460 G_SoundOnEnt( self, CHAN_WEAPON, "sound/effects/combustfire.mp3" );
00461
00462 trap_G2API_GetBoltMatrix(NPC->ghoul2, 0, NPC->client->renderInfo.handRBolt, &boltMatrix, NPC->r.currentAngles,
00463 NPC->r.currentOrigin, level.time, NULL, NPC->modelScale);
00464
00465 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, org );
00466 BG_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_Y, dir );
00467
00468 G_PlayEffectID( G_EffectIndex("boba/fthrw"), org, dir);
00469 }
|
|
||||||||||||||||||||
|
Definition at line 272 of file NPC_AI_Jedi.c. References AngleVectors(), CLASS_BOBAFETT, gentity_s::client, entityShared_t::currentAngles, DotProduct, EF2_FLYING, playerState_s::eFlags2, EV_JUMP, playerState_s::fd, ForceJump(), forcedata_s::forceJumpCharge, usercmd_s::forwardmove, G_AddEvent(), gentity_t, gclient_s::NPC_class, NULL, gentity_s::painDebounceTime, gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, usercmd_s::rightmove, TIMER_Set(), usercmd_t, vec3_t, VectorNormalize2(), VectorSet, WP_ResistForcePush(), and YAW.
00273 {
00274 vec3_t pDir, fwd, right, ang;
00275 float fDot, rDot;
00276 int strafeTime;
00277
00278 if ( self->client->NPC_class != CLASS_BOBAFETT )
00279 {
00280 return qfalse;
00281 }
00282
00283 if ( (self->client->ps.eFlags2&EF2_FLYING) )//moveType == MT_FLYSWIM )
00284 {//can't knock me down when I'm flying
00285 return qtrue;
00286 }
00287
00288 VectorSet(ang, 0, self->r.currentAngles[YAW], 0);
00289 strafeTime = Q_irand( 1000, 2000 );
00290
00291 AngleVectors( ang, fwd, right, NULL );
00292 VectorNormalize2( pushDir, pDir );
00293 fDot = DotProduct( pDir, fwd );
00294 rDot = DotProduct( pDir, right );
00295
00296 if ( Q_irand( 0, 2 ) )
00297 {//flip or roll with it
00298 usercmd_t tempCmd;
00299 if ( fDot >= 0.4f )
00300 {
00301 tempCmd.forwardmove = 127;
00302 TIMER_Set( self, "moveforward", strafeTime );
00303 }
00304 else if ( fDot <= -0.4f )
00305 {
00306 tempCmd.forwardmove = -127;
00307 TIMER_Set( self, "moveback", strafeTime );
00308 }
00309 else if ( rDot > 0 )
00310 {
00311 tempCmd.rightmove = 127;
00312 TIMER_Set( self, "strafeRight", strafeTime );
00313 TIMER_Set( self, "strafeLeft", -1 );
00314 }
00315 else
00316 {
00317 tempCmd.rightmove = -127;
00318 TIMER_Set( self, "strafeLeft", strafeTime );
00319 TIMER_Set( self, "strafeRight", -1 );
00320 }
00321 G_AddEvent( self, EV_JUMP, 0 );
00322 if ( !Q_irand( 0, 1 ) )
00323 {//flip
00324 self->client->ps.fd.forceJumpCharge = 280;//FIXME: calc this intelligently?
00325 ForceJump( self, &tempCmd );
00326 }
00327 else
00328 {//roll
00329 TIMER_Set( self, "duck", strafeTime );
00330 }
00331 self->painDebounceTime = 0;//so we do something
00332 }
00333 else if ( !Q_irand( 0, 1 ) && forceKnockdown )
00334 {//resist
00335 WP_ResistForcePush( self, pusher, qtrue );
00336 }
00337 else
00338 {//fall down
00339 return qfalse;
00340 }
00341
00342 return qtrue;
00343 }
|
|
||||||||||||
|
|
|
||||||||||||
|
|
|
|
Definition at line 1694 of file w_force.c. References absorbLoopSound, gentity_s::client, playerState_s::fd, playerState_s::forceAllowDeactivateTime, forcedata_s::forcePowersActive, FP_ABSORB, FP_PROTECT, FP_RAGE, G_PreDefSound(), G_Sound(), gentity_t, gentity_s::health, level, playerState_s::origin, PDSOUND_ABSORB, gclient_s::ps, level_locals_t::time, TRACK_CHANNEL_3, WP_ForcePowerStart(), WP_ForcePowerStop(), and WP_ForcePowerUsable(). Referenced by ClientThink_real(), and WP_DoSpecificPower().
01695 {
01696 if ( self->health <= 0 )
01697 {
01698 return;
01699 }
01700
01701 if (self->client->ps.forceAllowDeactivateTime < level.time &&
01702 (self->client->ps.fd.forcePowersActive & (1 << FP_ABSORB)) )
01703 {
01704 WP_ForcePowerStop( self, FP_ABSORB );
01705 return;
01706 }
01707
01708 if ( !WP_ForcePowerUsable( self, FP_ABSORB ) )
01709 {
01710 return;
01711 }
01712
01713 // Make sure to turn off Force Rage and Force Protection.
01714 if (self->client->ps.fd.forcePowersActive & (1 << FP_RAGE) )
01715 {
01716 WP_ForcePowerStop( self, FP_RAGE );
01717 }
01718 if (self->client->ps.fd.forcePowersActive & (1 << FP_PROTECT) )
01719 {
01720 WP_ForcePowerStop( self, FP_PROTECT );
01721 }
01722
01723 self->client->ps.forceAllowDeactivateTime = level.time + 1500;
01724
01725 WP_ForcePowerStart( self, FP_ABSORB, 0 );
01726 G_PreDefSound(self->client->ps.origin, PDSOUND_ABSORB);
01727 G_Sound( self, TRACK_CHANNEL_3, absorbLoopSound );
01728 }
|
|
|
Definition at line 1236 of file w_force.c. References BG_ForcePowerDrain(), CHAN_ITEM, gentity_s::client, playerState_s::fd, FORCE_LEVEL_2, FORCE_LEVEL_3, forcedata_s::forcePowerLevel, FP_HEAL, G_Sound(), G_SoundIndex(), gentity_t, gentity_s::health, gclient_s::ps, STAT_MAX_HEALTH, playerState_s::stats, and WP_ForcePowerUsable(). Referenced by ClientThink_real(), and WP_DoSpecificPower().
01237 {
01238 if ( self->health <= 0 )
01239 {
01240 return;
01241 }
01242
01243 if ( !WP_ForcePowerUsable( self, FP_HEAL ) )
01244 {
01245 return;
01246 }
01247
01248 if ( self->health >= self->client->ps.stats[STAT_MAX_HEALTH])
01249 {
01250 return;
01251 }
01252
01253 if (self->client->ps.fd.forcePowerLevel[FP_HEAL] == FORCE_LEVEL_3)
01254 {
01255 self->health += 25; //This was 50, but that angered the Balance God.
01256
01257 if (self->health > self->client->ps.stats[STAT_MAX_HEALTH])
01258 {
01259 self->health = self->client->ps.stats[STAT_MAX_HEALTH];
01260 }
01261 BG_ForcePowerDrain( &self->client->ps, FP_HEAL, 0 );
01262 }
01263 else if (self->client->ps.fd.forcePowerLevel[FP_HEAL] == FORCE_LEVEL_2)
01264 {
01265 self->health += 10;
01266
01267 if (self->health > self->client->ps.stats[STAT_MAX_HEALTH])
01268 {
01269 self->health = self->client->ps.stats[STAT_MAX_HEALTH];
01270 }
01271 BG_ForcePowerDrain( &self->client->ps, FP_HEAL, 0 );
01272 }
01273 else
01274 {
01275 self->health += 5;
01276
01277 if (self->health > self->client->ps.stats[STAT_MAX_HEALTH])
01278 {
01279 self->health = self->client->ps.stats[STAT_MAX_HEALTH];
01280 }
01281 BG_ForcePowerDrain( &self->client->ps, FP_HEAL, 0 );
01282 }
01283 /*
01284 else
01285 {
01286 WP_ForcePowerStart( self, FP_HEAL, 0 );
01287 }
01288 */
01289 //NOTE: Decided to make all levels instant.
01290
01291 G_Sound( self, CHAN_ITEM, G_SoundIndex("sound/weapons/force/heal.wav") );
01292 }
|
|
||||||||||||
|
Definition at line 2462 of file w_force.c. References gentity_s::client, ENTITYNUM_NONE, playerState_s::fd, gclient_s::fjDidJump, FORCE_JUMP_CHARGE_TIME, forcedata_s::forceJumpCharge, playerState_s::forceJumpFlip, forceJumpStrength, forcedata_s::forceJumpZStart, forcedata_s::forcePowerDuration, forcedata_s::forcePowerLevel, forcePowerNeeded, FP_LEVITATION, FRAMETIME, gentity_t, entityState_s::groundEntityNum, gentity_s::health, level, playerState_s::origin, gclient_s::ps, qtrue, gentity_s::s, level_locals_t::time, ucmd, usercmd_t, vec3_t, VectorCopy, playerState_s::velocity, WP_ForcePowerStart(), WP_ForcePowerUsable(), and WP_GetVelocityForForceJump(). Referenced by Boba_StopKnockdown(), and WP_DoSpecificPower().
02463 {
02464 float forceJumpChargeInterval;
02465 vec3_t jumpVel;
02466
02467 if ( self->client->ps.fd.forcePowerDuration[FP_LEVITATION] > level.time )
02468 {
02469 return;
02470 }
02471 if ( !WP_ForcePowerUsable( self, FP_LEVITATION ) )
02472 {
02473 return;
02474 }
02475 if ( self->s.groundEntityNum == ENTITYNUM_NONE )
02476 {
02477 return;
02478 }
02479 if ( self->health <= 0 )
02480 {
02481 return;
02482 }
02483
02484 self->client->fjDidJump = qtrue;
02485
02486 forceJumpChargeInterval = forceJumpStrength[self->client->ps.fd.forcePowerLevel[FP_LEVITATION]]/(FORCE_JUMP_CHARGE_TIME/FRAMETIME);
02487
02488 WP_GetVelocityForForceJump( self, jumpVel, ucmd );
02489
02490 //FIXME: sound effect
02491 self->client->ps.fd.forceJumpZStart = self->client->ps.origin[2];//remember this for when we land
02492 VectorCopy( jumpVel, self->client->ps.velocity );
02493 //wasn't allowing them to attack when jumping, but that was annoying
02494 //self->client->ps.weaponTime = self->client->ps.torsoAnimTimer;
02495
02496 WP_ForcePowerStart( self, FP_LEVITATION, self->client->ps.fd.forceJumpCharge/forceJumpChargeInterval/(FORCE_JUMP_CHARGE_TIME/FRAMETIME)*forcePowerNeeded[self->client->ps.fd.forcePowerLevel[FP_LEVITATION]][FP_LEVITATION] );
02497 //self->client->ps.fd.forcePowerDuration[FP_LEVITATION] = level.time + self->client->ps.weaponTime;
02498 self->client->ps.fd.forceJumpCharge = 0;
02499 self->client->ps.forceJumpFlip = qtrue;
02500 }
|
|
|
Definition at line 1777 of file w_force.c. References CHAN_BODY, gentity_s::client, playerState_s::fd, playerState_s::forceHandExtend, playerState_s::forceHandExtendTime, forcedata_s::forcePower, forcedata_s::forcePowerDebounce, FP_LIGHTNING, G_Sound(), G_SoundIndex(), gentity_t, HANDEXTEND_FORCE_HOLD, HANDEXTEND_NONE, gentity_s::health, level, gclient_s::ps, level_locals_t::time, playerState_s::weaponTime, WP_ForcePowerStart(), and WP_ForcePowerUsable(). Referenced by WP_DoSpecificPower().
01778 {
01779 if ( self->health <= 0 )
01780 {
01781 return;
01782 }
01783 if ( self->client->ps.fd.forcePower < 25 || !WP_ForcePowerUsable( self, FP_LIGHTNING ) )
01784 {
01785 return;
01786 }
01787 if ( self->client->ps.fd.forcePowerDebounce[FP_LIGHTNING] > level.time )
01788 {//stops it while using it and also after using it, up to 3 second delay
01789 return;
01790 }
01791
01792 if (self->client->ps.forceHandExtend != HANDEXTEND_NONE)
01793 {
01794 return;
01795 }
01796
01797 if (self->client->ps.weaponTime > 0)
01798 {
01799 return;
01800 }
01801
01802 //Shoot lightning from hand
01803 //using grip anim now, to extend the burst time
01804 self->client->ps.forceHandExtend = HANDEXTEND_FORCE_HOLD;
01805 self->client->ps.forceHandExtendTime = level.time + 20000;
01806
01807 G_Sound( self, CHAN_BODY, G_SoundIndex("sound/weapons/force/lightning") );
01808
01809 WP_ForcePowerStart( self, FP_LIGHTNING, 500 );
01810 }
|
|
|
Definition at line 1658 of file w_force.c. References gentity_s::client, playerState_s::fd, playerState_s::forceAllowDeactivateTime, forcedata_s::forcePowersActive, FP_ABSORB, FP_PROTECT, FP_RAGE, G_PreDefSound(), G_Sound(), gentity_t, gentity_s::health, level, playerState_s::origin, PDSOUND_PROTECT, protectLoopSound, gclient_s::ps, level_locals_t::time, TRACK_CHANNEL_3, WP_ForcePowerStart(), WP_ForcePowerStop(), and WP_ForcePowerUsable(). Referenced by ClientThink_real(), and WP_DoSpecificPower().
01659 {
01660 if ( self->health <= 0 )
01661 {
01662 return;
01663 }
01664
01665 if (self->client->ps.forceAllowDeactivateTime < level.time &&
01666 (self->client->ps.fd.forcePowersActive & (1 << FP_PROTECT)) )
01667 {
01668 WP_ForcePowerStop( self, FP_PROTECT );
01669 return;
01670 }
01671
01672 if ( !WP_ForcePowerUsable( self, FP_PROTECT ) )
01673 {
01674 return;
01675 }
01676
01677 // Make sure to turn off Force Rage and Force Absorb.
01678 if (self->client->ps.fd.forcePowersActive & (1 << FP_RAGE) )
01679 {
01680 WP_ForcePowerStop( self, FP_RAGE );
01681 }
01682 if (self->client->ps.fd.forcePowersActive & (1 << FP_ABSORB) )
01683 {
01684 WP_ForcePowerStop( self, FP_ABSORB );
01685 }
01686
01687 self->client->ps.forceAllowDeactivateTime = level.time + 1500;
01688
01689 WP_ForcePowerStart( self, FP_PROTECT, 0 );
01690 G_PreDefSound(self->client->ps.origin, PDSOUND_PROTECT);
01691 G_Sound( self, TRACK_CHANNEL_3, protectLoopSound );
01692 }
|
|
|
Definition at line 1730 of file w_force.c. References gentity_s::client, playerState_s::fd, playerState_s::forceAllowDeactivateTime, forcedata_s::forcePowersActive, forcedata_s::forceRageRecoveryTime, FP_ABSORB, FP_PROTECT, FP_RAGE, G_Sound(), G_SoundIndex(), gentity_t, gentity_s::health, level, gclient_s::ps, rageLoopSound, level_locals_t::time, TRACK_CHANNEL_3, TRACK_CHANNEL_4, WP_ForcePowerStart(), WP_ForcePowerStop(), and WP_ForcePowerUsable(). Referenced by ClientThink_real(), and WP_DoSpecificPower().
01731 {
01732 if ( self->health <= 0 )
01733 {
01734 return;
01735 }
01736
01737 if (self->client->ps.forceAllowDeactivateTime < level.time &&
01738 (self->client->ps.fd.forcePowersActive & (1 << FP_RAGE)) )
01739 {
01740 WP_ForcePowerStop( self, FP_RAGE );
01741 return;
01742 }
01743
01744 if ( !WP_ForcePowerUsable( self, FP_RAGE ) )
01745 {
01746 return;
01747 }
01748
01749 if (self->client->ps.fd.forceRageRecoveryTime >= level.time)
01750 {
01751 return;
01752 }
01753
01754 if (self->health < 10)
01755 {
01756 return;
01757 }
01758
01759 // Make sure to turn off Force Protection and Force Absorb.
01760 if (self->client->ps.fd.forcePowersActive & (1 << FP_PROTECT) )
01761 {
01762 WP_ForcePowerStop( self, FP_PROTECT );
01763 }
01764 if (self->client->ps.fd.forcePowersActive & (1 << FP_ABSORB) )
01765 {
01766 WP_ForcePowerStop( self, FP_ABSORB );
01767 }
01768
01769 self->client->ps.forceAllowDeactivateTime = level.time + 1500;
01770
01771 WP_ForcePowerStart( self, FP_RAGE, 0 );
01772
01773 G_Sound( self, TRACK_CHANNEL_4, G_SoundIndex("sound/weapons/force/rage.wav") );
01774 G_Sound( self, TRACK_CHANNEL_3, rageLoopSound );
01775 }
|
|
||||||||||||
|
Definition at line 3054 of file w_force.c. References entityShared_t::absmax, entityShared_t::absmin, trace_t::allsolid, AngleVectors(), BG_KnockDownable(), bgEntity_t, entityShared_t::bmodel, CanCounterThrow(), CHAN_BODY, CLASS_ATST, CLASS_GALAKMECH, CLASS_RANCOR, gentity_s::classname, gentity_s::client, client, gclient_s::dangerTime, DotProduct, EF_INVULNERABLE, EF_MISSILE_STICK, EF_NODRAW, entityState_s::eFlags, playerState_s::eFlags, vehicleInfo_t::Eject, trace_t::entityNum, ENTITYNUM_NONE, ET_ITEM, ET_MISSILE, ET_NPC, entityState_s::eType, playerState_s::fd, FORCE_LEVEL_1, FORCE_LEVEL_2, FORCE_LEVEL_3, playerState_s::forceDodgeAnim, forcedata_s::forceGripBeingGripped, playerState_s::forceHandExtend, playerState_s::forceHandExtendTime, forcedata_s::forcePowerLevel, forcePowerNeeded, ForcePowerUsableOn(), FP_ABSORB, FP_GRIP, FP_PULL, FP_PUSH, trace_t::fraction, g_debugMelee, g_entities, g_gametype, G_InGetUpAnim(), G_LetGoOfWall(), G_ReflectMissile(), G_Sound(), G_SoundIndex(), g_useWhileThrowing, entityState_s::genericenemyindex, gentity_t, GEntity_UseFunc(), GT_SIEGE, HANDEXTEND_FORCEPULL, HANDEXTEND_FORCEPUSH, HANDEXTEND_KNOCKDOWN, HANDEXTEND_NONE, gentity_s::health, InFieldOfVision(), vmCvar_t::integer, gentity_s::inuse, gclient_s::invulnerableTimer, level, playerState_s::m_iVehicleNum, gentity_s::m_pVehicle, Vehicle_s::m_pVehicleInfo, MASK_PLAYERSOLID, MASK_SHOT, MAX_CLIENTS, MAX_GENTITIES, MOVER_POS1, MOVER_POS2, gentity_s::moverState, gclient_s::NPC_class, NULL, entityState_s::number, OnSameTeam(), playerState_s::origin, PMF_STUCK_TO_WALL, entityState_s::pos, playerState_s::powerups, gclient_s::ps, PW_DISINT_4, PW_PULL, Q_irand(), Q_stricmp(), qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, playerState_s::saberInFlight, playerState_s::saberLockFrame, playerState_s::saberLockHits, playerState_s::saberLockTime, gentity_s::spawnflags, SPF_BUTTON_FPUSHABLE, trace_t::startsolid, level_locals_t::time, TossClientWeapon(), Touch_Button(), TR_INTERPOLATE, TR_STATIONARY, trap_EntitiesInBox(), trap_InPVS(), trap_Trace(), trajectory_t::trBase, trajectory_t::trType, vehicleInfo_t::type, vec3_origin, vec3_t, vectoangles(), VectorAdd, VectorCopy, VectorMA, VectorNormalize(), VectorSubtract, VH_ANIMAL, VH_SPEEDER, playerState_s::viewangles, playerState_s::viewheight, playerState_s::weapon, entityState_s::weapon, playerState_s::weaponTime, WP_AbsorbConversion(), WP_ForcePowerStart(), WP_ForcePowerStop(), WP_ForcePowerUsable(), WP_SABER, and WP_THERMAL. Referenced by ClientThink_real(), WP_DoSpecificPower(), and WP_SaberStartMissileBlockCheck().
03055 {
03056 //shove things in front of you away
03057 float dist;
03058 gentity_t *ent;
03059 int entityList[MAX_GENTITIES];
03060 gentity_t *push_list[MAX_GENTITIES];
03061 int numListedEntities;
03062 vec3_t mins, maxs;
03063 vec3_t v;
03064 int i, e;
03065 int ent_count = 0;
03066 int radius = 1024; //since it's view-based now. //350;
03067 int powerLevel;
03068 int visionArc;
03069 int pushPower;
03070 int pushPowerMod;
03071 vec3_t center, ent_org, size, forward, right, end, dir, fwdangles = {0};
03072 float dot1;
03073 trace_t tr;
03074 int x;
03075 vec3_t pushDir;
03076 vec3_t thispush_org;
03077 vec3_t tfrom, tto, fwd, a;
03078 float knockback = pull?0:200;
03079 int powerUse = 0;
03080
03081 visionArc = 0;
03082
03083 if (self->client->ps.forceHandExtend != HANDEXTEND_NONE && (self->client->ps.forceHandExtend != HANDEXTEND_KNOCKDOWN || !G_InGetUpAnim(&self->client->ps)))
03084 {
03085 return;
03086 }
03087
03088 if (!g_useWhileThrowing.integer && self->client->ps.saberInFlight)
03089 {
03090 return;
03091 }
03092
03093 if (self->client->ps.weaponTime > 0)
03094 {
03095 return;
03096 }
03097
03098 if ( self->health <= 0 )
03099 {
03100 return;
03101 }
03102 if ( self->client->ps.powerups[PW_DISINT_4] > level.time )
03103 {
03104 return;
03105 }
03106 if (pull)
03107 {
03108 powerUse = FP_PULL;
03109 }
03110 else
03111 {
03112 powerUse = FP_PUSH;
03113 }
03114
03115 if ( !WP_ForcePowerUsable( self, powerUse ) )
03116 {
03117 return;
03118 }
03119
03120 if (!pull && self->client->ps.saberLockTime > level.time && self->client->ps.saberLockFrame)
03121 {
03122 G_Sound( self, CHAN_BODY, G_SoundIndex( "sound/weapons/force/push.wav" ) );
03123 self->client->ps.powerups[PW_DISINT_4] = level.time + 1500;
03124
03125 self->client->ps.saberLockHits += self->client->ps.fd.forcePowerLevel[FP_PUSH]*2;
03126
03127 WP_ForcePowerStart( self, FP_PUSH, 0 );
03128 return;
03129 }
03130
03131 WP_ForcePowerStart( self, powerUse, 0 );
03132
03133 //make sure this plays and that you cannot press fire for about 1 second after this
03134 if ( pull )
03135 {
03136 G_Sound( self, CHAN_BODY, G_SoundIndex( "sound/weapons/force/pull.wav" ) );
03137 if (self->client->ps.forceHandExtend == HANDEXTEND_NONE)
03138 {
03139 self->client->ps.forceHandExtend = HANDEXTEND_FORCEPULL;
03140 if ( g_gametype.integer == GT_SIEGE && self->client->ps.weapon == WP_SABER )
03141 {//hold less so can attack right after a pull
03142 self->client->ps.forceHandExtendTime = level.time + 200;
03143 }
03144 else
03145 {
03146 self->client->ps.forceHandExtendTime = level.time + 400;
03147 }
03148 }
03149 self->client->ps.powerups[PW_DISINT_4] = self->client->ps.forceHandExtendTime + 200;
03150 self->client->ps.powerups[PW_PULL] = self->client->ps.powerups[PW_DISINT_4];
03151 }
03152 else
03153 {
03154 G_Sound( self, CHAN_BODY, G_SoundIndex( "sound/weapons/force/push.wav" ) );
03155 if (self->client->ps.forceHandExtend == HANDEXTEND_NONE)
03156 {
03157 self->client->ps.forceHandExtend = HANDEXTEND_FORCEPUSH;
03158 self->client->ps.forceHandExtendTime = level.time + 1000;
03159 }
03160 else if (self->client->ps.forceHandExtend == HANDEXTEND_KNOCKDOWN && G_InGetUpAnim(&self->client->ps))
03161 {
03162 if (self->client->ps.forceDodgeAnim > 4)
03163 {
03164 self->client->ps.forceDodgeAnim -= 8;
03165 }
03166 self->client->ps.forceDodgeAnim += 8; //special case, play push on upper torso, but keep playing current knockdown anim on legs
03167 }
03168 self->client->ps.powerups[PW_DISINT_4] = level.time + 1100;
03169 self->client->ps.powerups[PW_PULL] = 0;
03170 }
03171
03172 VectorCopy( self->client->ps.viewangles, fwdangles );
03173 AngleVectors( fwdangles, forward, right, NULL );
03174 VectorCopy( self->client->ps.origin, center );
03175
03176 for ( i = 0 ; i < 3 ; i++ )
03177 {
03178 mins[i] = center[i] - radius;
03179 maxs[i] = center[i] + radius;
03180 }
03181
03182
03183 if (pull)
03184 {
03185 powerLevel = self->client->ps.fd.forcePowerLevel[FP_PULL];
03186 pushPower = 256*self->client->ps.fd.forcePowerLevel[FP_PULL];
03187 }
03188 else
03189 {
03190 powerLevel = self->client->ps.fd.forcePowerLevel[FP_PUSH];
03191 pushPower = 256*self->client->ps.fd.forcePowerLevel[FP_PUSH];
03192 }
03193
03194 if (!powerLevel)
03195 { //Shouldn't have made it here..
03196 return;
03197 }
03198
03199 if (powerLevel == FORCE_LEVEL_2)
03200 {
03201 visionArc = 60;
03202 }
03203 else if (powerLevel == FORCE_LEVEL_3)
03204 {
03205 visionArc = 180;
03206 }
03207
03208 if (powerLevel == FORCE_LEVEL_1)
03209 { //can only push/pull targeted things at level 1
03210 VectorCopy(self->client->ps.origin, tfrom);
03211 tfrom[2] += self->client->ps.viewheight;
03212 AngleVectors(self->client->ps.viewangles, fwd, NULL, NULL);
03213 tto[0] = tfrom[0] + fwd[0]*radius/2;
03214 tto[1] = tfrom[1] + fwd[1]*radius/2;
03215 tto[2] = tfrom[2] + fwd[2]*radius/2;
03216
03217 trap_Trace(&tr, tfrom, NULL, NULL, tto, self->s.number, MASK_PLAYERSOLID);
03218
03219 if (tr.fraction != 1.0 &&
03220 tr.entityNum != ENTITYNUM_NONE)
03221 {
03222 if (!g_entities[tr.entityNum].client && g_entities[tr.entityNum].s.eType == ET_NPC)
03223 { //g2animent
03224 if (g_entities[tr.entityNum].s.genericenemyindex < level.time)
03225 {
03226 g_entities[tr.entityNum].s.genericenemyindex = level.time + 2000;
03227 }
03228 }
03229
03230 numListedEntities = 0;
03231 entityList[numListedEntities] = tr.entityNum;
03232
03233 if (pull)
03234 {
03235 if (!ForcePowerUsableOn(self, &g_entities[tr.entityNum], FP_PULL))
03236 {
03237 return;
03238 }
03239 }
03240 else
03241 {
03242 if (!ForcePowerUsableOn(self, &g_entities[tr.entityNum], FP_PUSH))
03243 {
03244 return;
03245 }
03246 }
03247 numListedEntities++;
03248 }
03249 else
03250 {
03251 //didn't get anything, so just
03252 return;
03253 }
03254 }
03255 else
03256 {
03257 numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
03258
03259 e = 0;
03260
03261 while (e < numListedEntities)
03262 {
03263 ent = &g_entities[entityList[e]];
03264
03265 if (!ent->client && ent->s.eType == ET_NPC)
03266 { //g2animent
03267 if (ent->s.genericenemyindex < level.time)
03268 {
03269 ent->s.genericenemyindex = level.time + 2000;
03270 }
03271 }
03272
03273 if (ent)
03274 {
03275 if (ent->client)
03276 {
03277 VectorCopy(ent->client->ps.origin, thispush_org);
03278 }
03279 else
03280 {
03281 VectorCopy(ent->s.pos.trBase, thispush_org);
03282 }
03283 }
03284
03285 if (ent)
03286 { //not in the arc, don't consider it
03287 VectorCopy(self->client->ps.origin, tto);
03288 tto[2] += self->client->ps.viewheight;
03289 VectorSubtract(thispush_org, tto, a);
03290 vectoangles(a, a);
03291
03292 if (ent->client && !InFieldOfVision(self->client->ps.viewangles, visionArc, a) &&
03293 ForcePowerUsableOn(self, ent, powerUse))
03294 { //only bother with arc rules if the victim is a client
03295 entityList[e] = ENTITYNUM_NONE;
03296 }
03297 else if (ent->client)
03298 {
03299 if (pull)
03300 {
03301 if (!ForcePowerUsableOn(self, ent, FP_PULL))
03302 {
03303 entityList[e] = ENTITYNUM_NONE;
03304 }
03305 }
03306 else
03307 {
03308 if (!ForcePowerUsableOn(self, ent, FP_PUSH))
03309 {
03310 entityList[e] = ENTITYNUM_NONE;
03311 }
03312 }
03313 }
03314 }
03315 e++;
03316 }
03317 }
03318
03319 for ( e = 0 ; e < numListedEntities ; e++ )
03320 {
03321 if (entityList[e] != ENTITYNUM_NONE &&
03322 entityList[e] >= 0 &&
03323 entityList[e] < MAX_GENTITIES)
03324 {
03325 ent = &g_entities[entityList[e]];
03326 }
03327 else
03328 {
03329 ent = NULL;
03330 }
03331
03332 if (!ent)
03333 continue;
03334 if (ent == self)
03335 continue;
03336 if (ent->client && OnSameTeam(ent, self))
03337 {
03338 continue;
03339 }
03340 if ( !(ent->inuse) )
03341 continue;
03342 if ( ent->s.eType != ET_MISSILE )
03343 {
03344 if ( ent->s.eType != ET_ITEM )
03345 {
03346 //FIXME: need pushable objects
03347 if ( Q_stricmp( "func_button", ent->classname ) == 0 )
03348 {//we might push it
03349 if ( pull || !(ent->spawnflags&SPF_BUTTON_FPUSHABLE) )
03350 {//not force-pushable, never pullable
03351 continue;
03352 }
03353 }
03354 else
03355 {
03356 if ( ent->s.eFlags & EF_NODRAW )
03357 {
03358 continue;
03359 }
03360 if ( !ent->client )
03361 {
03362 if ( Q_stricmp( "lightsaber", ent->classname ) != 0 )
03363 {//not a lightsaber
03364 if ( Q_stricmp( "func_door", ent->classname ) != 0 || !(ent->spawnflags & 2/*MOVER_FORCE_ACTIVATE*/) )
03365 {//not a force-usable door
03366 if ( Q_stricmp( "func_static", ent->classname ) != 0 || (!(ent->spawnflags&1/*F_PUSH*/)&&!(ent->spawnflags&2/*F_PULL*/)) )
03367 {//not a force-usable func_static
03368 if ( Q_stricmp( "limb", ent->classname ) )
03369 {//not a limb
03370 continue;
03371 }
03372 }
03373 }
03374 else if ( ent->moverState != MOVER_POS1 && ent->moverState != MOVER_POS2 )
03375 {//not at rest
03376 continue;
03377 }
03378 }
03379 }
03380 else if ( ent->client->NPC_class == CLASS_GALAKMECH
03381 || ent->client->NPC_class == CLASS_ATST
03382 || ent->client->NPC_class == CLASS_RANCOR )
03383 {//can't push ATST or Galak or Rancor
03384 continue;
03385 }
03386 }
03387 }
03388 }
03389 else
03390 {
03391 if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags&EF_MISSILE_STICK) )
03392 {//can't force-push/pull stuck missiles (detpacks, tripmines)
03393 continue;
03394 }
03395 if ( ent->s.pos.trType == TR_STATIONARY && ent->s.weapon != WP_THERMAL )
03396 {//only thermal detonators can be pushed once stopped
03397 continue;
03398 }
03399 }
03400
03401 //this is all to see if we need to start a saber attack, if it's in flight, this doesn't matter
03402 // find the distance from the edge of the bounding box
03403 for ( i = 0 ; i < 3 ; i++ )
03404 {
03405 if ( center[i] < ent->r.absmin[i] )
03406 {
03407 v[i] = ent->r.absmin[i] - center[i];
03408 } else if ( center[i] > ent->r.absmax[i] )
03409 {
03410 v[i] = center[i] - ent->r.absmax[i];
03411 } else
03412 {
03413 v[i] = 0;
03414 }
03415 }
03416
03417 VectorSubtract( ent->r.absmax, ent->r.absmin, size );
03418 VectorMA( ent->r.absmin, 0.5, size, ent_org );
03419
03420 VectorSubtract( ent_org, center, dir );
03421 VectorNormalize( dir );
03422 if ( (dot1 = DotProduct( dir, forward )) < 0.6 )
03423 continue;
03424
03425 dist = VectorLength( v );
03426
03427 //Now check and see if we can actually deflect it
03428 //method1
03429 //if within a certain range, deflect it
03430 if ( dist >= radius )
03431 {
03432 continue;
03433 }
03434
03435 //in PVS?
03436 if ( !ent->r.bmodel && !trap_InPVS( ent_org, self->client->ps.origin ) )
03437 {//must be in PVS
03438 continue;
03439 }
03440
03441 //really should have a clear LOS to this thing...
03442 trap_Trace( &tr, self->client->ps.origin, vec3_origin, vec3_origin, ent_org, self->s.number, MASK_SHOT );
03443 if ( tr.fraction < 1.0f && tr.entityNum != ent->s.number )
03444 {//must have clear LOS
03445 //try from eyes too before you give up
03446 vec3_t eyePoint;
03447 VectorCopy(self->client->ps.origin, eyePoint);
03448 eyePoint[2] += self->client->ps.viewheight;
03449 trap_Trace( &tr, eyePoint, vec3_origin, vec3_origin, ent_org, self->s.number, MASK_SHOT );
03450
03451 if ( tr.fraction < 1.0f && tr.entityNum != ent->s.number )
03452 {
03453 continue;
03454 }
03455 }
03456
03457 // ok, we are within the radius, add us to the incoming list
03458 push_list[ent_count] = ent;
03459 ent_count++;
03460 }
03461
03462 if ( ent_count )
03463 {
03464 //method1:
03465 for ( x = 0; x < ent_count; x++ )
03466 {
03467 int modPowerLevel = powerLevel;
03468
03469
03470 if (push_list[x]->client)
03471 {
03472 modPowerLevel = WP_AbsorbConversion(push_list[x], push_list[x]->client->ps.fd.forcePowerLevel[FP_ABSORB], self, powerUse, powerLevel, forcePowerNeeded[self->client->ps.fd.forcePowerLevel[powerUse]][powerUse]);
03473 if (modPowerLevel == -1)
03474 {
03475 modPowerLevel = powerLevel;
03476 }
03477 }
03478
03479 pushPower = 256*modPowerLevel;
03480
03481 if (push_list[x]->client)
03482 {
03483 VectorCopy(push_list[x]->client->ps.origin, thispush_org);
03484 }
03485 else
03486 {
03487 VectorCopy(push_list[x]->s.origin, thispush_org);
03488 }
03489
03490 if ( push_list[x]->client )
03491 {//FIXME: make enemy jedi able to hunker down and resist this?
03492 int otherPushPower = push_list[x]->client->ps.fd.forcePowerLevel[powerUse];
03493 qboolean canPullWeapon = qtrue;
03494 float dirLen = 0;
03495
03496 if ( g_debugMelee.integer )
03497 {
03498 if ( (push_list[x]->client->ps.pm_flags&PMF_STUCK_TO_WALL) )
03499 {//no resistance if stuck to wall
03500 //push/pull them off the wall
03501 otherPushPower = 0;
03502 G_LetGoOfWall( push_list[x] );
03503 }
03504 }
03505
03506 knockback = pull?0:200;
03507
03508 pushPowerMod = pushPower;
03509
03510 if (push_list[x]->client->pers.cmd.forwardmove ||
03511 push_list[x]->client->pers.cmd.rightmove)
03512 { //if you are moving, you get one less level of defense
03513 otherPushPower--;
03514
03515 if (otherPushPower < 0)
03516 {
03517 otherPushPower = 0;
03518 }
03519 }
03520
03521 if (otherPushPower && CanCounterThrow(push_list[x], self, pull))
03522 {
03523 if ( pull )
03524 {
03525 G_Sound( push_list[x], CHAN_BODY, G_SoundIndex( "sound/weapons/force/pull.wav" ) );
03526 push_list[x]->client->ps.forceHandExtend = HANDEXTEND_FORCEPULL;
03527 push_list[x]->client->ps.forceHandExtendTime = level.time + 400;
03528 }
03529 else
03530 {
03531 G_Sound( push_list[x], CHAN_BODY, G_SoundIndex( "sound/weapons/force/push.wav" ) );
03532 push_list[x]->client->ps.forceHandExtend = HANDEXTEND_FORCEPUSH;
03533 push_list[x]->client->ps.forceHandExtendTime = level.time + 1000;
03534 }
03535 push_list[x]->client->ps.powerups[PW_DISINT_4] = push_list[x]->client->ps.forceHandExtendTime + 200;
03536
03537 if (pull)
03538 {
03539 push_list[x]->client->ps.powerups[PW_PULL] = push_list[x]->client->ps.powerups[PW_DISINT_4];
03540 }
03541 else
03542 {
03543 push_list[x]->client->ps.powerups[PW_PULL] = 0;
03544 }
03545
03546 //Make a counter-throw effect
03547
03548 if (otherPushPower >= modPowerLevel)
03549 {
03550 pushPowerMod = 0;
03551 canPullWeapon = qfalse;
03552 }
03553 else
03554 {
03555 int powerDif = (modPowerLevel - otherPushPower);
03556
03557 if (powerDif >= 3)
03558 {
03559 pushPowerMod -= pushPowerMod*0.2;
03560 }
03561 else if (powerDif == 2)
03562 {
03563 pushPowerMod -= pushPowerMod*0.4;
03564 }
03565 else if (powerDif == 1)
03566 {
03567 pushPowerMod -= pushPowerMod*0.8;
03568 }
03569
03570 if (pushPowerMod < 0)
03571 {
03572 pushPowerMod = 0;
03573 }
03574 }
03575 }
03576
03577 //shove them
03578 if ( pull )
03579 {
03580 VectorSubtract( self->client->ps.origin, thispush_org, pushDir );
03581
03582 if (push_list[x]->client && VectorLength(pushDir) <= 256)
03583 {
03584 int randfact = 0;
03585
03586 if (modPowerLevel == FORCE_LEVEL_1)
03587 {
03588 randfact = 3;
03589 }
03590 else if (modPowerLevel == FORCE_LEVEL_2)
03591 {
03592 randfact = 7;
03593 }
03594 else if (modPowerLevel == FORCE_LEVEL_3)
03595 {
03596 randfact = 10;
03597 }
03598
03599 if (!OnSameTeam(self, push_list[x]) && Q_irand(1, 10) <= randfact && canPullWeapon)
03600 {
03601 vec3_t uorg, vecnorm;
03602
03603 VectorCopy(self->client->ps.origin, uorg);
03604 uorg[2] += 64;
03605
03606 VectorSubtract(uorg, thispush_org, vecnorm);
03607 VectorNormalize(vecnorm);
03608
03609 TossClientWeapon(push_list[x], vecnorm, 500);
03610 }
03611 }
03612 }
03613 else
03614 {
03615 VectorSubtract( thispush_org, self->client->ps.origin, pushDir );
03616 }
03617
03618 if ((modPowerLevel > otherPushPower || push_list[x]->client->ps.m_iVehicleNum) && push_list[x]->client)
03619 {
03620 if (modPowerLevel == FORCE_LEVEL_3 &&
03621 push_list[x]->client->ps.forceHandExtend != HANDEXTEND_KNOCKDOWN)
03622 {
03623 dirLen = VectorLength(pushDir);
03624
03625 if (BG_KnockDownable(&push_list[x]->client->ps) &&
03626 dirLen <= (64*((modPowerLevel - otherPushPower)-1)))
03627 { //can only do a knockdown if fairly close
03628 push_list[x]->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
03629 push_list[x]->client->ps.forceHandExtendTime = level.time + 700;
03630 push_list[x]->client->ps.forceDodgeAnim = 0; //this toggles between 1 and 0, when it's 1 we should play the get up anim
03631 push_list[x]->client->ps.quickerGetup = qtrue;
03632 }
03633 else if (push_list[x]->s.number < MAX_CLIENTS && push_list[x]->client->ps.m_iVehicleNum &&
03634 dirLen <= 128.0f )
03635 { //a player on a vehicle
03636 gentity_t *vehEnt = &g_entities[push_list[x]->client->ps.m_iVehicleNum];
03637 if (vehEnt->inuse && vehEnt->client && vehEnt->m_pVehicle)
03638 {
03639 if (vehEnt->m_pVehicle->m_pVehicleInfo->type == VH_SPEEDER ||
03640 vehEnt->m_pVehicle->m_pVehicleInfo->type == VH_ANIMAL)
03641 { //push the guy off
03642 vehEnt->m_pVehicle->m_pVehicleInfo->Eject(vehEnt->m_pVehicle, (bgEntity_t *)push_list[x], qfalse);
03643 }
03644 }
03645 }
03646 }
03647 }
03648
03649 if (!dirLen)
03650 {
03651 dirLen = VectorLength(pushDir);
03652 }
03653
03654 VectorNormalize(pushDir);
03655
03656 if (push_list[x]->client)
03657 {
03658 //escape a force grip if we're in one
03659 if (self->client->ps.fd.forceGripBeingGripped > level.time)
03660 { //force the enemy to stop gripping me if I managed to push him
03661 if (push_list[x]->client->ps.fd.forceGripEntityNum == self->s.number)
03662 {
03663 if (modPowerLevel >= push_list[x]->client->ps.fd.forcePowerLevel[FP_GRIP])
03664 { //only break the grip if our push/pull level is >= their grip level
03665 WP_ForcePowerStop(push_list[x], FP_GRIP);
03666 self->client->ps.fd.forceGripBeingGripped = 0;
03667 push_list[x]->client->ps.fd.forceGripUseTime = level.time + 1000; //since we just broke out of it..
03668 }
03669 }
03670 }
03671
03672 push_list[x]->client->ps.otherKiller = self->s.number;
03673 push_list[x]->client->ps.otherKillerTime = level.time + 5000;
03674 push_list[x]->client->ps.otherKillerDebounceTime = level.time + 100;
03675
03676 pushPowerMod -= (dirLen*0.7);
03677 if (pushPowerMod < 16)
03678 {
03679 pushPowerMod = 16;
03680 }
03681
03682 //fullbody push effect
03683 push_list[x]->client->pushEffectTime = level.time + 600;
03684
03685 push_list[x]->client->ps.velocity[0] = pushDir[0]*pushPowerMod;
03686 push_list[x]->client->ps.velocity[1] = pushDir[1]*pushPowerMod;
03687
03688 if ((int)push_list[x]->client->ps.velocity[2] == 0)
03689 { //if not going anywhere vertically, boost them up a bit
03690 push_list[x]->client->ps.velocity[2] = pushDir[2]*pushPowerMod;
03691
03692 if (push_list[x]->client->ps.velocity[2] < 128)
03693 {
03694 push_list[x]->client->ps.velocity[2] = 128;
03695 }
03696 }
03697 else
03698 {
03699 push_list[x]->client->ps.velocity[2] = pushDir[2]*pushPowerMod;
03700 }
03701 }
03702 }
03703 else if ( push_list[x]->s.eType == ET_MISSILE && push_list[x]->s.pos.trType != TR_STATIONARY && (push_list[x]->s.pos.trType != TR_INTERPOLATE||push_list[x]->s.weapon != WP_THERMAL) )//rolling and stationary thermal detonators are dealt with below
03704 {
03705 if ( pull )
03706 {//deflect rather than reflect?
03707 }
03708 else
03709 {
03710 G_ReflectMissile( self, push_list[x], forward );
03711 }
03712 }
03713 else if ( !Q_stricmp( "func_static", push_list[x]->classname ) )
03714 {//force-usable func_static
03715 if ( !pull && (push_list[x]->spawnflags&1/*F_PUSH*/) )
03716 {
03717 GEntity_UseFunc( push_list[x], self, self );
03718 }
03719 else if ( pull && (push_list[x]->spawnflags&2/*F_PULL*/) )
03720 {
03721 GEntity_UseFunc( push_list[x], self, self );
03722 }
03723 }
03724 else if ( !Q_stricmp( "func_door", push_list[x]->classname ) && (push_list[x]->spawnflags&2) )
03725 {//push/pull the door
03726 vec3_t pos1, pos2;
03727 vec3_t trFrom;
03728
03729 VectorCopy(self->client->ps.origin, trFrom);
03730 trFrom[2] += self->client->ps.viewheight;
03731
03732 AngleVectors( self->client->ps.viewangles, forward, NULL, NULL );
03733 VectorNormalize( forward );
03734 VectorMA( trFrom, radius, forward, end );
03735 trap_Trace( &tr, trFrom, vec3_origin, vec3_origin, end, self->s.number, MASK_SHOT );
03736 if ( tr.entityNum != push_list[x]->s.number || tr.fraction == 1.0 || tr.allsolid || tr.startsolid )
03737 {//must be pointing right at it
03738 continue;
03739 }
03740
03741 if ( VectorCompare( vec3_origin, push_list[x]->s.origin ) )
03742 {//does not have an origin brush, so pos1 & pos2 are relative to world origin, need to calc center
03743 VectorSubtract( push_list[x]->r.absmax, push_list[x]->r.absmin, size );
03744 VectorMA( push_list[x]->r.absmin, 0.5, size, center );
03745 if ( (push_list[x]->spawnflags&1) && push_list[x]->moverState == MOVER_POS1 )
03746 {//if at pos1 and started open, make sure we get the center where it *started* because we're going to add back in the relative values pos1 and pos2
03747 VectorSubtract( center, push_list[x]->pos1, center );
03748 }
03749 else if ( !(push_list[x]->spawnflags&1) && push_list[x]->moverState == MOVER_POS2 )
03750 {//if at pos2, make sure we get the center where it *started* because we're going to add back in the relative values pos1 and pos2
03751 VectorSubtract( center, push_list[x]->pos2, center );
03752 }
03753 VectorAdd( center, push_list[x]->pos1, pos1 );
03754 VectorAdd( center, push_list[x]->pos2, pos2 );
03755 }
03756 else
03757 {//actually has an origin, pos1 and pos2 are absolute
03758 VectorCopy( push_list[x]->r.currentOrigin, center );
03759 VectorCopy( push_list[x]->pos1, pos1 );
03760 VectorCopy( push_list[x]->pos2, pos2 );
03761 }
03762
03763 if ( Distance( pos1, trFrom ) < Distance( pos2, trFrom ) )
03764 {//pos1 is closer
03765 if ( push_list[x]->moverState == MOVER_POS1 )
03766 {//at the closest pos
03767 if ( pull )
03768 {//trying to pull, but already at closest point, so screw it
03769 continue;
03770 }
03771 }
03772 else if ( push_list[x]->moverState == MOVER_POS2 )
03773 {//at farthest pos
03774 if ( !pull )
03775 {//trying to push, but already at farthest point, so screw it
03776 continue;
03777 }
03778 }
03779 }
03780 else
03781 {//pos2 is closer
03782 if ( push_list[x]->moverState == MOVER_POS1 )
03783 {//at the farthest pos
03784 if ( !pull )
03785 {//trying to push, but already at farthest point, so screw it
03786 continue;
03787 }
03788 }
03789 else if ( push_list[x]->moverState == MOVER_POS2 )
03790 {//at closest pos
03791 if ( pull )
03792 {//trying to pull, but already at closest point, so screw it
03793 continue;
03794 }
03795 }
03796 }
03797 GEntity_UseFunc( push_list[x], self, self );
03798 }
03799 else if ( Q_stricmp( "func_button", push_list[x]->classname ) == 0 )
03800 {//pretend you pushed it
03801 Touch_Button( push_list[x], self, NULL );
03802 continue;
03803 }
03804 }
03805 }
03806
03807 //attempt to break any leftover grips
03808 //if we're still in a current grip that wasn't broken by the push, it will still remain
03809 self->client->dangerTime = level.time;
03810 self->client->ps.eFlags &= ~EF_INVULNERABLE;
03811 self->client->invulnerableTimer = 0;
03812
03813 if (self->client->ps.fd.forceGripBeingGripped > level.time)
03814 {
03815 self->client->ps.fd.forceGripBeingGripped = 0;
03816 }
03817 }
|
|
||||||||||||||||
|
Definition at line 23 of file NPC_sounds.c.
00024 {
00025 if ( !self->NPC )
00026 {
00027 return;
00028 }
00029
00030 if ( !self->client || self->client->ps.pm_type >= PM_DEAD )
00031 {
00032 return;
00033 }
00034
00035 if ( self->NPC->blockedSpeechDebounceTime > level.time )
00036 {
00037 return;
00038 }
00039
00040 if ( trap_ICARUS_TaskIDPending( self, TID_CHAN_VOICE ) )
00041 {
00042 return;
00043 }
00044
00045
00046 if ( (self->NPC->scriptFlags&SCF_NO_COMBAT_TALK) && ( (event >= EV_ANGER1 && event <= EV_VICTORY3) || (event >= EV_CHASE1 && event <= EV_SUSPICIOUS5) ) )//(event < EV_FF_1A || event > EV_FF_3C) && (event < EV_RESPOND1 || event > EV_MISSION3) )
00047 {
00048 return;
00049 }
00050
00051 if ( (self->NPC->scriptFlags&SCF_NO_ALERT_TALK) && (event >= EV_GIVEUP1 && event <= EV_SUSPICIOUS5) )
00052 {
00053 return;
00054 }
00055 //FIXME: Also needs to check for teammates. Don't want
00056 // everyone babbling at once
00057
00058 //NOTE: was losing too many speech events, so we do it directly now, screw networking!
00059 //G_AddEvent( self, event, 0 );
00060 G_SpeechEvent( self, event );
00061
00062 //won't speak again for 5 seconds (unless otherwise specified)
00063 self->NPC->blockedSpeechDebounceTime = level.time + ((speakDebounceTime==0) ? 5000 : speakDebounceTime);
00064 }
|
|
||||||||||||||||||||
|
|
|
||||||||||||||||||||||||
|
Definition at line 2087 of file g_utils.c.
02088 {
02089 trace_t tr;
02090 vec3_t start, end;
02091 int i;
02092
02093 VectorCopy( point, start );
02094
02095 for ( i = 0; i < 3; i++ )
02096 {
02097 VectorCopy( start, end );
02098 end[i] += mins[i];
02099 trap_Trace( &tr, start, vec3_origin, vec3_origin, end, ignore, clipmask );
02100 if ( tr.allsolid || tr.startsolid )
02101 {
02102 return qfalse;
02103 }
02104 if ( tr.fraction < 1.0 )
02105 {
02106 VectorCopy( start, end );
02107 end[i] += maxs[i]-(mins[i]*tr.fraction);
02108 trap_Trace( &tr, start, vec3_origin, vec3_origin, end, ignore, clipmask );
02109 if ( tr.allsolid || tr.startsolid )
02110 {
02111 return qfalse;
02112 }
02113 if ( tr.fraction < 1.0 )
02114 {
02115 return qfalse;
02116 }
02117 VectorCopy( end, start );
02118 }
02119 }
02120 //expanded it, now see if it's all clear
02121 trap_Trace( &tr, start, mins, maxs, start, ignore, clipmask );
02122 if ( tr.allsolid || tr.startsolid )
02123 {
02124 return qfalse;
02125 }
02126 VectorCopy( start, point );
02127 return qtrue;
02128 }
|
|
||||||||||||||||||||
|
Definition at line 1524 of file q_math.c. References cos(), DEG2RAD, DotProductNormalize(), qboolean, qfalse, qtrue, vec3_t, VectorCopy, VectorMA, VectorNormalize(), and VectorSubtract. Referenced by NAV_MoveToGoal(), and ShortestLineSegBewteen2LineSegs().
01525 {
01526 vec3_t vecStart2From, vecStart2End, vecEnd2Start, vecEnd2From;
01527 float distEnd2From, distEnd2Result, theta, cos_theta, dot;
01528
01529 //Find the perpendicular vector to vec from start to end
01530 VectorSubtract( from, start, vecStart2From);
01531 VectorSubtract( end, start, vecStart2End);
01532
01533 dot = DotProductNormalize( vecStart2From, vecStart2End );
01534
01535 if ( dot <= 0 )
01536 {
01537 //The perpendicular would be beyond or through the start point
01538 VectorCopy( start, result );
01539 return qfalse;
01540 }
01541
01542 if ( dot == 1 )
01543 {
01544 //parallel, closer of 2 points will be the target
01545 if( (VectorLengthSquared( vecStart2From )) < (VectorLengthSquared( vecStart2End )) )
01546 {
01547 VectorCopy( from, result );
01548 }
01549 else
01550 {
01551 VectorCopy( end, result );
01552 }
01553 return qfalse;
01554 }
01555
01556 //Try other end
01557 VectorSubtract( from, end, vecEnd2From);
01558 VectorSubtract( start, end, vecEnd2Start);
01559
01560 dot = DotProductNormalize( vecEnd2From, vecEnd2Start );
01561
01562 if ( dot <= 0 )
01563 {//The perpendicular would be beyond or through the start point
01564 VectorCopy( end, result );
01565 return qfalse;
01566 }
01567
01568 if ( dot == 1 )
01569 {//parallel, closer of 2 points will be the target
01570 if( (VectorLengthSquared( vecEnd2From )) < (VectorLengthSquared( vecEnd2Start )))
01571 {
01572 VectorCopy( from, result );
01573 }
01574 else
01575 {
01576 VectorCopy( end, result );
01577 }
01578 return qfalse;
01579 }
01580
01581 // /|
01582 // c / |
01583 // / |a
01584 // theta /)__|
01585 // b
01586 //cos(theta) = b / c
01587 //solve for b
01588 //b = cos(theta) * c
01589
01590 //angle between vecs end2from and end2start, should be between 0 and 90
01591 theta = 90 * (1 - dot);//theta
01592
01593 //Get length of side from End2Result using sine of theta
01594 distEnd2From = VectorLength( vecEnd2From );//c
01595 cos_theta = cos(DEG2RAD(theta));//cos(theta)
01596 distEnd2Result = cos_theta * distEnd2From;//b
01597
01598 //Extrapolate to find result
01599 VectorNormalize( vecEnd2Start );
01600 VectorMA( end, distEnd2Result, vecEnd2Start, result );
01601
01602 //perpendicular intersection is between the 2 endpoints
01603 return qtrue;
01604 }
|
|
||||||||||||||||||||||||||||||||
|
Definition at line 3632 of file g_combat.c. References AngleVectors(), renderInfo_s::boltValidityTime, CLASS_ATST, CLASS_GALAKMECH, CLASS_GONK, CLASS_INTERROGATOR, CLASS_MARK1, CLASS_MARK2, CLASS_MOUSE, CLASS_PROBE, CLASS_PROTOCOL, CLASS_R2D2, CLASS_SENTRY, gentity_s::client, entityShared_t::currentAngles, entityShared_t::currentOrigin, DotProduct, g_dismember, gentity_t, gentity_s::ghoul2, HL_ARM_LT, HL_ARM_RT, HL_BACK, HL_BACK_LT, HL_BACK_RT, HL_CHEST, HL_CHEST_LT, HL_CHEST_RT, HL_FOOT_LT, HL_FOOT_RT, HL_GENERIC1, HL_GENERIC2, HL_GENERIC3, HL_GENERIC4, HL_GENERIC5, HL_GENERIC6, HL_HAND_LT, HL_HAND_RT, HL_HEAD, HL_LEG_LT, HL_LEG_RT, HL_NONE, HL_WAIST, vmCvar_t::integer, level, gentity_s::localAnimIndex, MOD_SABER, gentity_s::modelScale, NEGATIVE_Y, gclient_s::NPC_class, NULL, playerState_s::origin, ORIGIN, gclient_s::ps, Q_stricmp(), Q_strncmp(), qboolean, qfalse, qtrue, gentity_s::r, gclient_s::renderInfo, level_locals_t::time, renderInfo_s::torsoAngles, renderInfo_s::torsoPoint, trap_G2API_AddBolt(), trap_G2API_GetBoltMatrix(), UpdateClientRenderBolts(), vec3_t, VectorSet, VectorSubtract, playerState_s::viewangles, and YAW. Referenced by G_CheckForDismemberment(), G_Damage(), and G_LocationBasedDamageModifier().
03633 {
03634 qboolean dismember = qfalse;
03635 int actualTime;
03636 int kneeLBolt = -1;
03637 int kneeRBolt = -1;
03638 int handRBolt = -1;
03639 int handLBolt = -1;
03640 int footRBolt = -1;
03641 int footLBolt = -1;
03642
03643 *hitLoc = HL_NONE;
03644
03645 if ( !surfName || !surfName[0] )
03646 {
03647 return qfalse;
03648 }
03649
03650 if( !ent->client )
03651 {
03652 return qfalse;
03653 }
03654
03655 if (!point)
03656 {
03657 return qfalse;
03658 }
03659
03660 if ( ent->client
03661 && ( ent->client->NPC_class == CLASS_R2D2
03662 || ent->client->NPC_class == CLASS_R2D2
03663 || ent->client->NPC_class == CLASS_GONK
03664 || ent->client->NPC_class == CLASS_MOUSE
03665 || ent->client->NPC_class == CLASS_SENTRY
03666 || ent->client->NPC_class == CLASS_INTERROGATOR
03667 || ent->client->NPC_class == CLASS_SENTRY
03668 || ent->client->NPC_class == CLASS_PROBE ) )
03669 {//we don't care about per-surface hit-locations or dismemberment for these guys
03670 return qfalse;
03671 }
03672
03673 if (ent->localAnimIndex <= 1)
03674 { //humanoid
03675 handLBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*l_hand");
03676 handRBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*r_hand");
03677 kneeLBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*hips_l_knee");
03678 kneeRBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*hips_r_knee");
03679 footLBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*l_leg_foot");
03680 footRBolt = trap_G2API_AddBolt(ent->ghoul2, 0, "*r_leg_foot");
03681 }
03682
03683 if ( ent->client && (ent->client->NPC_class == CLASS_ATST) )
03684 {
03685 //FIXME: almost impossible to hit these... perhaps we should
03686 // check for splashDamage and do radius damage to these parts?
03687 // Or, if we ever get bbox G2 traces, that may fix it, too
03688 if (!Q_stricmp("head_light_blaster_cann",surfName))
03689 {
03690 *hitLoc = HL_ARM_LT;
03691 }
03692 else if (!Q_stricmp("head_concussion_charger",surfName))
03693 {
03694 *hitLoc = HL_ARM_RT;
03695 }
03696 return(qfalse);
03697 }
03698 else if ( ent->client && (ent->client->NPC_class == CLASS_MARK1) )
03699 {
03700 if (!Q_stricmp("l_arm",surfName))
03701 {
03702 *hitLoc = HL_ARM_LT;
03703 }
03704 else if (!Q_stricmp("r_arm",surfName))
03705 {
03706 *hitLoc = HL_ARM_RT;
03707 }
03708 else if (!Q_stricmp("torso_front",surfName))
03709 {
03710 *hitLoc = HL_CHEST;
03711 }
03712 else if (!Q_stricmp("torso_tube1",surfName))
03713 {
03714 *hitLoc = HL_GENERIC1;
03715 }
03716 else if (!Q_stricmp("torso_tube2",surfName))
03717 {
03718 *hitLoc = HL_GENERIC2;
03719 }
03720 else if (!Q_stricmp("torso_tube3",surfName))
03721 {
03722 *hitLoc = HL_GENERIC3;
03723 }
03724 else if (!Q_stricmp("torso_tube4",surfName))
03725 {
03726 *hitLoc = HL_GENERIC4;
03727 }
03728 else if (!Q_stricmp("torso_tube5",surfName))
03729 {
03730 *hitLoc = HL_GENERIC5;
03731 }
03732 else if (!Q_stricmp("torso_tube6",surfName))
03733 {
03734 *hitLoc = HL_GENERIC6;
03735 }
03736 return(qfalse);
03737 }
03738 else if ( ent->client && (ent->client->NPC_class == CLASS_MARK2) )
03739 {
03740 if (!Q_stricmp("torso_canister1",surfName))
03741 {
03742 *hitLoc = HL_GENERIC1;
03743 }
03744 else if (!Q_stricmp("torso_canister2",surfName))
03745 {
03746 *hitLoc = HL_GENERIC2;
03747 }
03748 else if (!Q_stricmp("torso_canister3",surfName))
03749 {
03750 *hitLoc = HL_GENERIC3;
03751 }
03752 return(qfalse);
03753 }
03754 else if ( ent->client && (ent->client->NPC_class == CLASS_GALAKMECH) )
03755 {
03756 if (!Q_stricmp("torso_antenna",surfName)||!Q_stricmp("torso_antenna_base",surfName))
03757 {
03758 *hitLoc = HL_GENERIC1;
03759 }
03760 else if (!Q_stricmp("torso_shield",surfName))
03761 {
03762 *hitLoc = HL_GENERIC2;
03763 }
03764 else
03765 {
03766 *hitLoc = HL_CHEST;
03767 }
03768 return(qfalse);
03769 }
03770
03771 //FIXME: check the hitLoc and hitDir against the cap tag for the place
03772 //where the split will be- if the hit dir is roughly perpendicular to
03773 //the direction of the cap, then the split is allowed, otherwise we
03774 //hit it at the wrong angle and should not dismember...
03775 actualTime = level.time;
03776 if ( !Q_strncmp( "hips", surfName, 4 ) )
03777 {//FIXME: test properly for legs
03778 *hitLoc = HL_WAIST;
03779 if ( ent->client != NULL && ent->ghoul2 )
03780 {
03781 mdxaBone_t boltMatrix;
03782 vec3_t tagOrg, angles;
03783
03784 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03785 if (kneeLBolt>=0)
03786 {
03787 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, kneeLBolt,
03788 &boltMatrix, angles, ent->r.currentOrigin,
03789 actualTime, NULL, ent->modelScale );
03790 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03791 if ( DistanceSquared( point, tagOrg ) < 100 )
03792 {//actually hit the knee
03793 *hitLoc = HL_LEG_LT;
03794 }
03795 }
03796 if (*hitLoc == HL_WAIST)
03797 {
03798 if (kneeRBolt>=0)
03799 {
03800 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, kneeRBolt,
03801 &boltMatrix, angles, ent->r.currentOrigin,
03802 actualTime, NULL, ent->modelScale );
03803 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03804 if ( DistanceSquared( point, tagOrg ) < 100 )
03805 {//actually hit the knee
03806 *hitLoc = HL_LEG_RT;
03807 }
03808 }
03809 }
03810 }
03811 }
03812 else if ( !Q_strncmp( "torso", surfName, 5 ) )
03813 {
03814 if ( !ent->client )
03815 {
03816 *hitLoc = HL_CHEST;
03817 }
03818 else
03819 {
03820 vec3_t t_fwd, t_rt, t_up, dirToImpact;
03821 float frontSide, rightSide, upSide;
03822 AngleVectors( ent->client->renderInfo.torsoAngles, t_fwd, t_rt, t_up );
03823
03824 if (ent->client->renderInfo.boltValidityTime != level.time)
03825 {
03826 vec3_t renderAng;
03827
03828 renderAng[0] = 0;
03829 renderAng[1] = ent->client->ps.viewangles[YAW];
03830 renderAng[2] = 0;
03831
03832 UpdateClientRenderBolts(ent, ent->client->ps.origin, renderAng);
03833 }
03834
03835 VectorSubtract( point, ent->client->renderInfo.torsoPoint, dirToImpact );
03836 frontSide = DotProduct( t_fwd, dirToImpact );
03837 rightSide = DotProduct( t_rt, dirToImpact );
03838 upSide = DotProduct( t_up, dirToImpact );
03839 if ( upSide < -10 )
03840 {//hit at waist
03841 *hitLoc = HL_WAIST;
03842 }
03843 else
03844 {//hit on upper torso
03845 if ( rightSide > 4 )
03846 {
03847 *hitLoc = HL_ARM_RT;
03848 }
03849 else if ( rightSide < -4 )
03850 {
03851 *hitLoc = HL_ARM_LT;
03852 }
03853 else if ( rightSide > 2 )
03854 {
03855 if ( frontSide > 0 )
03856 {
03857 *hitLoc = HL_CHEST_RT;
03858 }
03859 else
03860 {
03861 *hitLoc = HL_BACK_RT;
03862 }
03863 }
03864 else if ( rightSide < -2 )
03865 {
03866 if ( frontSide > 0 )
03867 {
03868 *hitLoc = HL_CHEST_LT;
03869 }
03870 else
03871 {
03872 *hitLoc = HL_BACK_LT;
03873 }
03874 }
03875 else if ( upSide > -3 && mod == MOD_SABER )
03876 {
03877 *hitLoc = HL_HEAD;
03878 }
03879 else if ( frontSide > 0 )
03880 {
03881 *hitLoc = HL_CHEST;
03882 }
03883 else
03884 {
03885 *hitLoc = HL_BACK;
03886 }
03887 }
03888 }
03889 }
03890 else if ( !Q_strncmp( "head", surfName, 4 ) )
03891 {
03892 *hitLoc = HL_HEAD;
03893 }
03894 else if ( !Q_strncmp( "r_arm", surfName, 5 ) )
03895 {
03896 *hitLoc = HL_ARM_RT;
03897 if ( ent->client != NULL && ent->ghoul2 )
03898 {
03899 mdxaBone_t boltMatrix;
03900 vec3_t tagOrg, angles;
03901
03902 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03903 if (handRBolt>=0)
03904 {
03905 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, handRBolt,
03906 &boltMatrix, angles, ent->r.currentOrigin,
03907 actualTime, NULL, ent->modelScale );
03908 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03909 if ( DistanceSquared( point, tagOrg ) < 256 )
03910 {//actually hit the hand
03911 *hitLoc = HL_HAND_RT;
03912 }
03913 }
03914 }
03915 }
03916 else if ( !Q_strncmp( "l_arm", surfName, 5 ) )
03917 {
03918 *hitLoc = HL_ARM_LT;
03919 if ( ent->client != NULL && ent->ghoul2 )
03920 {
03921 mdxaBone_t boltMatrix;
03922 vec3_t tagOrg, angles;
03923
03924 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03925 if (handLBolt>=0)
03926 {
03927 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, handLBolt,
03928 &boltMatrix, angles, ent->r.currentOrigin,
03929 actualTime, NULL, ent->modelScale );
03930 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03931 if ( DistanceSquared( point, tagOrg ) < 256 )
03932 {//actually hit the hand
03933 *hitLoc = HL_HAND_LT;
03934 }
03935 }
03936 }
03937 }
03938 else if ( !Q_strncmp( "r_leg", surfName, 5 ) )
03939 {
03940 *hitLoc = HL_LEG_RT;
03941 if ( ent->client != NULL && ent->ghoul2 )
03942 {
03943 mdxaBone_t boltMatrix;
03944 vec3_t tagOrg, angles;
03945
03946 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03947 if (footRBolt>=0)
03948 {
03949 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, footRBolt,
03950 &boltMatrix, angles, ent->r.currentOrigin,
03951 actualTime, NULL, ent->modelScale );
03952 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03953 if ( DistanceSquared( point, tagOrg ) < 100 )
03954 {//actually hit the foot
03955 *hitLoc = HL_FOOT_RT;
03956 }
03957 }
03958 }
03959 }
03960 else if ( !Q_strncmp( "l_leg", surfName, 5 ) )
03961 {
03962 *hitLoc = HL_LEG_LT;
03963 if ( ent->client != NULL && ent->ghoul2 )
03964 {
03965 mdxaBone_t boltMatrix;
03966 vec3_t tagOrg, angles;
03967
03968 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
03969 if (footLBolt>=0)
03970 {
03971 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, footLBolt,
03972 &boltMatrix, angles, ent->r.currentOrigin,
03973 actualTime, NULL, ent->modelScale );
03974 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
03975 if ( DistanceSquared( point, tagOrg ) < 100 )
03976 {//actually hit the foot
03977 *hitLoc = HL_FOOT_LT;
03978 }
03979 }
03980 }
03981 }
03982 else if ( !Q_strncmp( "r_hand", surfName, 6 ) || !Q_strncmp( "w_", surfName, 2 ) )
03983 {//right hand or weapon
03984 *hitLoc = HL_HAND_RT;
03985 }
03986 else if ( !Q_strncmp( "l_hand", surfName, 6 ) )
03987 {
03988 *hitLoc = HL_HAND_LT;
03989 }
03990 /*
03991 #ifdef _DEBUG
03992 else
03993 {
03994 Com_Printf( "ERROR: surface %s does not belong to any hitLocation!!!\n", surfName );
03995 }
03996 #endif //_DEBUG
03997 */
03998
03999 //if ( g_dismemberment->integer >= 11381138 || !ent->client->dismembered )
04000 if (g_dismember.integer == 100)
04001 { //full probability...
04002 if ( ent->client && ent->client->NPC_class == CLASS_PROTOCOL )
04003 {
04004 dismember = qtrue;
04005 }
04006 else if ( dir && (dir[0] || dir[1] || dir[2]) &&
04007 bladeDir && (bladeDir[0] || bladeDir[1] || bladeDir[2]) )
04008 {//we care about direction (presumably for dismemberment)
04009 //if ( g_dismemberProbabilities->value<=0.0f||G_Dismemberable( ent, *hitLoc ) )
04010 if (1) //Fix me?
04011 {//either we don't care about probabilties or the probability let us continue
04012 char *tagName = NULL;
04013 float aoa = 0.5f;
04014 //dir must be roughly perpendicular to the hitLoc's cap bolt
04015 switch ( *hitLoc )
04016 {
04017 case HL_LEG_RT:
04018 tagName = "*hips_cap_r_leg";
04019 break;
04020 case HL_LEG_LT:
04021 tagName = "*hips_cap_l_leg";
04022 break;
04023 case HL_WAIST:
04024 tagName = "*hips_cap_torso";
04025 aoa = 0.25f;
04026 break;
04027 case HL_CHEST_RT:
04028 case HL_ARM_RT:
04029 case HL_BACK_LT:
04030 tagName = "*torso_cap_r_arm";
04031 break;
04032 case HL_CHEST_LT:
04033 case HL_ARM_LT:
04034 case HL_BACK_RT:
04035 tagName = "*torso_cap_l_arm";
04036 break;
04037 case HL_HAND_RT:
04038 tagName = "*r_arm_cap_r_hand";
04039 break;
04040 case HL_HAND_LT:
04041 tagName = "*l_arm_cap_l_hand";
04042 break;
04043 case HL_HEAD:
04044 tagName = "*torso_cap_head";
04045 aoa = 0.25f;
04046 break;
04047 case HL_CHEST:
04048 case HL_BACK:
04049 case HL_FOOT_RT:
04050 case HL_FOOT_LT:
04051 default:
04052 //no dismemberment possible with these, so no checks needed
04053 break;
04054 }
04055 if ( tagName )
04056 {
04057 int tagBolt = trap_G2API_AddBolt( ent->ghoul2, 0, tagName );
04058 if ( tagBolt != -1 )
04059 {
04060 mdxaBone_t boltMatrix;
04061 vec3_t tagOrg, tagDir, angles;
04062
04063 VectorSet( angles, 0, ent->r.currentAngles[YAW], 0 );
04064 trap_G2API_GetBoltMatrix( ent->ghoul2, 0, tagBolt,
04065 &boltMatrix, angles, ent->r.currentOrigin,
04066 actualTime, NULL, ent->modelScale );
04067 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, tagOrg );
04068 BG_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_Y, tagDir );
04069 if ( DistanceSquared( point, tagOrg ) < 256 )
04070 {//hit close
04071 float dot = DotProduct( dir, tagDir );
04072 if ( dot < aoa && dot > -aoa )
04073 {//hit roughly perpendicular
04074 dot = DotProduct( bladeDir, tagDir );
04075 if ( dot < aoa && dot > -aoa )
04076 {//blade was roughly perpendicular
04077 dismember = qtrue;
04078 }
04079 }
04080 }
04081 }
04082 }
04083 }
04084 }
04085 else
04086 { //hmm, no direction supplied.
04087 dismember = qtrue;
04088 }
04089 }
04090 return dismember;
04091 }
|
|
||||||||||||||||
|
|
|
|
Definition at line 16 of file NPC_AI_Jedi.c. References gentity_t.
00017 { //perhaps write this at some point?
00018
00019 }
|
|
||||||||||||||||||||
|
Definition at line 212 of file ai_wpnav.c.
00213 {
00214 gentity_t *te;
00215
00216 te = G_TempEntity( start, EV_TESTLINE );
00217 VectorCopy(start, te->s.origin);
00218 VectorCopy(end, te->s.origin2);
00219 te->s.time2 = time;
00220 te->s.weapon = color;
00221 te->r.svFlags |= SVF_BROADCAST;
00222 }
|
|
||||||||||||||||
|
Definition at line 324 of file NPC_move.c. References AngleVectors(), gentity_s::client, entityShared_t::currentAngles, DotProduct, floor(), usercmd_s::forwardmove, gentity_t, playerState_s::moveDir, NULL, gclient_s::ps, gentity_s::r, usercmd_s::rightmove, usercmd_t, vec3_t, VectorCopy, and VectorNormalize(). Referenced by NPC_MoveToGoal().
00325 {
00326 vec3_t forward, right;
00327 float fDot, rDot;
00328
00329 AngleVectors( self->r.currentAngles, forward, right, NULL );
00330
00331 dir[2] = 0;
00332 VectorNormalize( dir );
00333 //NPCs cheat and store this directly because converting movement into a ucmd loses precision
00334 VectorCopy( dir, self->client->ps.moveDir );
00335
00336 fDot = DotProduct( forward, dir ) * 127.0f;
00337 rDot = DotProduct( right, dir ) * 127.0f;
00338 //Must clamp this because DotProduct is not guaranteed to return a number within -1 to 1, and that would be bad when we're shoving this into a signed byte
00339 if ( fDot > 127.0f )
00340 {
00341 fDot = 127.0f;
00342 }
00343 if ( fDot < -127.0f )
00344 {
00345 fDot = -127.0f;
00346 }
00347 if ( rDot > 127.0f )
00348 {
00349 rDot = 127.0f;
00350 }
00351 if ( rDot < -127.0f )
00352 {
00353 rDot = -127.0f;
00354 }
00355 cmd->forwardmove = floor(fDot);
00356 cmd->rightmove = floor(rDot);
00357
00358 /*
00359 vec3_t wishvel;
00360 for ( int i = 0 ; i < 3 ; i++ )
00361 {
00362 wishvel[i] = forward[i]*cmd->forwardmove + right[i]*cmd->rightmove;
00363 }
00364 VectorNormalize( wishvel );
00365 if ( !VectorCompare( wishvel, dir ) )
00366 {
00367 Com_Printf( "PRECISION LOSS: %s != %s\n", vtos(wishvel), vtos(dir) );
00368 }
00369 */
00370 }
|
|
|
|
|
Definition at line 5465 of file NPC_AI_Jedi.c. References gentity_s::client, entityShared_t::currentOrigin, DistanceHorizontalSquared(), gNPC_t::enemyLastSeenTime, g_entities, G_SetEnemy(), gentity_t, InFOV(), level, MAX_CLIENTS, NPC, NPC_ClearLOS4(), NPC_SetLookTarget(), NPC_SomeoneLookingAtMe(), NPC_ValidEnemy(), NPCInfo, playerState_s::powerups, gclient_s::ps, PW_CLOAKED, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, level_locals_t::time, TIMER_Set(), and trap_InPVS().
05466 {
05467 int i = 0;
05468 gentity_t *player;
05469 float target_dist;
05470 float zDiff;
05471
05472 for ( i = 0; i < MAX_CLIENTS; i++ )
05473 {
05474 player = &g_entities[i];
05475
05476 if ( !player || !player->client )
05477 {
05478 continue;
05479 }
05480
05481 if ( !NPC_ValidEnemy( player ) )
05482 {
05483 continue;
05484 }
05485
05486 // if ( NPC->client->ps.powerups[PW_CLOAKED] || g_crosshairEntNum != NPC->s.number )
05487 if (NPC->client->ps.powerups[PW_CLOAKED] || !NPC_SomeoneLookingAtMe(NPC)) //rwwFIXMEFIXME: Need to pay attention to who is under crosshair for each player or something.
05488 {//if I'm not cloaked and the player's crosshair is on me, I will wake up, otherwise do this stuff down here...
05489 if ( !trap_InPVS( player->r.currentOrigin, NPC->r.currentOrigin ) )
05490 {//must be in same room
05491 continue;
05492 }
05493 else
05494 {
05495 if ( !NPC->client->ps.powerups[PW_CLOAKED] )
05496 {
05497 NPC_SetLookTarget( NPC, 0, 0 );
05498 }
05499 }
05500 zDiff = NPC->r.currentOrigin[2]-player->r.currentOrigin[2];
05501 if ( zDiff <= 0 || zDiff > 512 )
05502 {//never ambush if they're above me or way way below me
05503 continue;
05504 }
05505
05506 //If the target is this close, then wake up regardless
05507 if ( (target_dist = DistanceHorizontalSquared( player->r.currentOrigin, NPC->r.currentOrigin )) > 4096 )
05508 {//closer than 64 - always ambush
05509 if ( target_dist > 147456 )
05510 {//> 384, not close enough to ambush
05511 continue;
05512 }
05513 //Check FOV first
05514 if ( NPC->client->ps.powerups[PW_CLOAKED] )
05515 {
05516 if ( InFOV( player, NPC, 30, 90 ) == qfalse )
05517 {
05518 continue;
05519 }
05520 }
05521 else
05522 {
05523 if ( InFOV( player, NPC, 45, 90 ) == qfalse )
05524 {
05525 continue;
05526 }
05527 }
05528 }
05529
05530 if ( !NPC_ClearLOS4( player ) )
05531 {
05532 continue;
05533 }
05534 }
05535
05536 //Got him, return true;
05537 G_SetEnemy( NPC, player );
05538 NPCInfo->enemyLastSeenTime = level.time;
05539 TIMER_Set( NPC, "attackDelay", Q_irand( 500, 2500 ) );
05540 return qtrue;
05541 }
05542
05543 //Didn't get anyone.
05544 return qfalse;
05545 }
|
|
|
Definition at line 835 of file NPC_AI_Jedi.c. References CLASS_SHADOWTROOPER, gentity_s::client, gentity_s::health, Jedi_Cloak(), Jedi_Decloak(), level, NPC, gclient_s::NPC_class, gentity_s::painDebounceTime, gclient_s::ps, playerState_s::saberHolstered, playerState_s::saberInFlight, and level_locals_t::time. Referenced by NPC_BSJedi_Default().
00836 {
00837 if ( NPC && NPC->client && NPC->client->NPC_class == CLASS_SHADOWTROOPER )
00838 {
00839 if ( !NPC->client->ps.saberHolstered ||
00840 NPC->health <= 0 ||
00841 NPC->client->ps.saberInFlight ||
00842 // (NPC->client->ps.eFlags&EF_FORCE_GRIPPED) ||
00843 // (NPC->client->ps.eFlags&EF_FORCE_DRAINED) ||
00844 NPC->painDebounceTime > level.time )
00845 {//can't be cloaked if saber is on, or dead or saber in flight or taking pain or being gripped
00846 Jedi_Decloak( NPC );
00847 }
00848 else if ( NPC->health > 0
00849 && !NPC->client->ps.saberInFlight
00850 // && !(NPC->client->ps.eFlags&EF_FORCE_GRIPPED)
00851 // && !(NPC->client->ps.eFlags&EF_FORCE_DRAINED)
00852 && NPC->painDebounceTime < level.time )
00853 {//still alive, have saber in hand, not taking pain and not being gripped
00854 Jedi_Cloak( NPC );
00855 }
00856 }
00857 }
|
|
|
||||||||||||||||
|
Definition at line 1969 of file NPC_AI_Jedi.c. References AngleVectors(), animNumber_t, BG_AnimLength(), BG_InRoll(), BG_SaberInAttack(), BG_SaberInSpecialAttack(), BOTH_ARIAL_LEFT, BOTH_ARIAL_RIGHT, BOTH_CARTWHEEL_LEFT, BOTH_CARTWHEEL_RIGHT, BOTH_WALL_FLIP_LEFT, BOTH_WALL_FLIP_RIGHT, BOTH_WALL_RUN_LEFT, BOTH_WALL_RUN_LEFT_FLIP, BOTH_WALL_RUN_RIGHT, BOTH_WALL_RUN_RIGHT_FLIP, CHAN_BODY, CLASS_BOBAFETT, CLASS_DESANN, gentity_s::client, trace_t::contents, CONTENTS_BOTCLIP, CONTENTS_MONSTERCLIP, CONTENTS_SOLID, entityShared_t::currentOrigin, DotProduct, trace_t::entityNum, ENTITYNUM_WORLD, EV_JUMP, EVASION_CARTWHEEL, EVASION_NONE, EVASION_OTHER, evasionType_t, playerState_s::fd, FORCE_LEVEL_2, forcedata_s::forceJumpCharge, forceJumpStrength, forcedata_s::forceJumpZStart, forcedata_s::forcePowersActive, forcedata_s::forceRageRecoveryTime, FP_RAGE, trace_t::fraction, G_AddEvent(), g_entities, G_SoundOnEnt(), gentity_t, playerState_s::legsAnim, playerState_s::legsTimer, level, gentity_s::localAnimIndex, entityShared_t::maxs, entityShared_t::mins, saberInfo_t::model, cplane_s::normal, gentity_s::NPC, gclient_s::NPC_class, NPC_SetAnim(), NULL, entityState_s::number, PITCH, trace_t::plane, PM_InKnockDown(), PM_SaberInStart(), gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, gNPC_t::rank, RANK_CREWMAN, RANK_LT, ROLL, gentity_s::s, gclient_s::saber, saberInfo_t::saberFlags, playerState_s::saberMove, SCF_NO_ACROBATICS, gNPC_t::scriptFlags, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, SETANIM_LEGS, SFL_NO_CARTWHEELS, SFL_NO_WALL_FLIPS, SFL_NO_WALL_RUNS, entityState_s::solid, SOLID_BMODEL, level_locals_t::time, playerState_s::torsoAnim, trap_Trace(), vec3_t, VectorCopy, VectorMA, VectorNormalize(), VectorScale, VectorSet, VectorSubtract, playerState_s::velocity, playerState_s::viewangles, playerState_s::weapon, playerState_s::weaponTime, WP_SABER, and YAW. Referenced by Jedi_SaberBlockGo().
01970 {
01971 if ( self->NPC && (self->NPC->scriptFlags&SCF_NO_ACROBATICS) )
01972 {
01973 return EVASION_NONE;
01974 }
01975 if ( self->client
01976 && (self->client->ps.fd.forceRageRecoveryTime > level.time || (self->client->ps.fd.forcePowersActive&(1<<FP_RAGE))) )
01977 {//no fancy dodges when raging
01978 return EVASION_NONE;
01979 }
01980 //Check for:
01981 //ARIALS/CARTWHEELS
01982 //WALL-RUNS
01983 //WALL-FLIPS
01984 //FIXME: if facing a wall, do forward wall-walk-backflip
01985 if ( self->client->ps.legsAnim == BOTH_WALL_RUN_LEFT || self->client->ps.legsAnim == BOTH_WALL_RUN_RIGHT )
01986 {//already running on a wall
01987 vec3_t right, fwdAngles;
01988 int anim = -1;
01989 float animLength;
01990
01991 VectorSet(fwdAngles, 0, self->client->ps.viewangles[YAW], 0);
01992
01993 AngleVectors( fwdAngles, NULL, right, NULL );
01994
01995 animLength = BG_AnimLength( self->localAnimIndex, (animNumber_t)self->client->ps.legsAnim );
01996 if ( self->client->ps.legsAnim == BOTH_WALL_RUN_LEFT && rightdot < 0 )
01997 {//I'm running on a wall to my left and the attack is on the left
01998 if ( animLength - self->client->ps.legsTimer > 400
01999 && self->client->ps.legsTimer > 400 )
02000 {//not at the beginning or end of the anim
02001 anim = BOTH_WALL_RUN_LEFT_FLIP;
02002 }
02003 }
02004 else if ( self->client->ps.legsAnim == BOTH_WALL_RUN_RIGHT && rightdot > 0 )
02005 {//I'm running on a wall to my right and the attack is on the right
02006 if ( animLength - self->client->ps.legsTimer > 400
02007 && self->client->ps.legsTimer > 400 )
02008 {//not at the beginning or end of the anim
02009 anim = BOTH_WALL_RUN_RIGHT_FLIP;
02010 }
02011 }
02012 if ( anim != -1 )
02013 {//flip off the wall!
02014 int parts;
02015 //FIXME: check the direction we will flip towards for do-not-enter/walls/drops?
02016 //NOTE: we presume there is still a wall there!
02017 if ( anim == BOTH_WALL_RUN_LEFT_FLIP )
02018 {
02019 self->client->ps.velocity[0] *= 0.5f;
02020 self->client->ps.velocity[1] *= 0.5f;
02021 VectorMA( self->client->ps.velocity, 150, right, self->client->ps.velocity );
02022 }
02023 else if ( anim == BOTH_WALL_RUN_RIGHT_FLIP )
02024 {
02025 self->client->ps.velocity[0] *= 0.5f;
02026 self->client->ps.velocity[1] *= 0.5f;
02027 VectorMA( self->client->ps.velocity, -150, right, self->client->ps.velocity );
02028 }
02029 parts = SETANIM_LEGS;
02030 if ( !self->client->ps.weaponTime )
02031 {
02032 parts = SETANIM_BOTH;
02033 }
02034 NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
02035 //self->client->ps.pm_flags |= (PMF_JUMPING|PMF_SLOW_MO_FALL);
02036 //rwwFIXMEFIXME: Add these pm flags?
02037 G_AddEvent( self, EV_JUMP, 0 );
02038 return EVASION_OTHER;
02039 }
02040 }
02041 else if ( self->client->NPC_class != CLASS_DESANN //desann doesn't do these kind of frilly acrobatics
02042 && (self->NPC->rank == RANK_CREWMAN || self->NPC->rank >= RANK_LT)
02043 && Q_irand( 0, 1 )
02044 && !BG_InRoll( &self->client->ps, self->client->ps.legsAnim )
02045 && !PM_InKnockDown( &self->client->ps )
02046 && !BG_SaberInSpecialAttack( self->client->ps.torsoAnim ) )
02047 {
02048 vec3_t fwd, right, traceto, mins, maxs, fwdAngles;
02049 trace_t trace;
02050 int parts, anim;
02051 float speed, checkDist;
02052 qboolean allowCartWheels = qtrue;
02053 qboolean allowWallFlips = qtrue;
02054
02055 if ( self->client->ps.weapon == WP_SABER )
02056 {
02057 if ( self->client->saber[0].model
02058 && self->client->saber[0].model[0]
02059 && (self->client->saber[0].saberFlags&SFL_NO_CARTWHEELS) )
02060 {
02061 allowCartWheels = qfalse;
02062 }
02063 else if ( self->client->saber[1].model
02064 && self->client->saber[1].model[0]
02065 && (self->client->saber[1].saberFlags&SFL_NO_CARTWHEELS) )
02066 {
02067 allowCartWheels = qfalse;
02068 }
02069 if ( self->client->saber[0].model
02070 && self->client->saber[0].model[0]
02071 && (self->client->saber[0].saberFlags&SFL_NO_WALL_FLIPS) )
02072 {
02073 allowWallFlips = qfalse;
02074 }
02075 else if ( self->client->saber[1].model
02076 && self->client->saber[1].model[0]
02077 && (self->client->saber[1].saberFlags&SFL_NO_WALL_FLIPS) )
02078 {
02079 allowWallFlips = qfalse;
02080 }
02081 }
02082
02083 VectorSet(mins, self->r.mins[0],self->r.mins[1],0);
02084 VectorSet(maxs, self->r.maxs[0],self->r.maxs[1],24);
02085 VectorSet(fwdAngles, 0, self->client->ps.viewangles[YAW], 0);
02086
02087 AngleVectors( fwdAngles, fwd, right, NULL );
02088
02089 parts = SETANIM_BOTH;
02090
02091 if ( BG_SaberInAttack( self->client->ps.saberMove )
02092 || PM_SaberInStart( self->client->ps.saberMove ) )
02093 {
02094 parts = SETANIM_LEGS;
02095 }
02096 if ( rightdot >= 0 )
02097 {
02098 if ( Q_irand( 0, 1 ) )
02099 {
02100 anim = BOTH_ARIAL_LEFT;
02101 }
02102 else
02103 {
02104 anim = BOTH_CARTWHEEL_LEFT;
02105 }
02106 checkDist = -128;
02107 speed = -200;
02108 }
02109 else
02110 {
02111 if ( Q_irand( 0, 1 ) )
02112 {
02113 anim = BOTH_ARIAL_RIGHT;
02114 }
02115 else
02116 {
02117 anim = BOTH_CARTWHEEL_RIGHT;
02118 }
02119 checkDist = 128;
02120 speed = 200;
02121 }
02122 //trace in the dir that we want to go
02123 VectorMA( self->r.currentOrigin, checkDist, right, traceto );
02124 trap_Trace( &trace, self->r.currentOrigin, mins, maxs, traceto, self->s.number, CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP );
02125 if ( trace.fraction >= 1.0f && allowCartWheels )
02126 {//it's clear, let's do it
02127 //FIXME: check for drops?
02128 vec3_t fwdAngles, jumpRt;
02129
02130 NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
02131 self->client->ps.weaponTime = self->client->ps.legsTimer;//don't attack again until this anim is done
02132 VectorCopy( self->client->ps.viewangles, fwdAngles );
02133 fwdAngles[PITCH] = fwdAngles[ROLL] = 0;
02134 //do the flip
02135 AngleVectors( fwdAngles, NULL, jumpRt, NULL );
02136 VectorScale( jumpRt, speed, self->client->ps.velocity );
02137 self->client->ps.fd.forceJumpCharge = 0;//so we don't play the force flip anim
02138 self->client->ps.velocity[2] = 200;
02139 self->client->ps.fd.forceJumpZStart = self->r.currentOrigin[2];//so we don't take damage if we land at same height
02140 //self->client->ps.pm_flags |= PMF_JUMPING;
02141 if ( self->client->NPC_class == CLASS_BOBAFETT )
02142 {
02143 G_AddEvent( self, EV_JUMP, 0 );
02144 }
02145 else
02146 {
02147 G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/jump.wav" );
02148 }
02149 //ucmd.upmove = 0;
02150 return EVASION_CARTWHEEL;
02151 }
02152 else if ( !(trace.contents&CONTENTS_BOTCLIP) )
02153 {//hit a wall, not a do-not-enter brush
02154 //FIXME: before we check any of these jump-type evasions, we should check for headroom, right?
02155 //Okay, see if we can flip *off* the wall and go the other way
02156 vec3_t idealNormal;
02157 gentity_t *traceEnt;
02158
02159 VectorSubtract( self->r.currentOrigin, traceto, idealNormal );
02160 VectorNormalize( idealNormal );
02161 traceEnt = &g_entities[trace.entityNum];
02162 if ( (trace.entityNum<ENTITYNUM_WORLD&&traceEnt&&traceEnt->s.solid!=SOLID_BMODEL) || DotProduct( trace.plane.normal, idealNormal ) > 0.7f )
02163 {//it's a ent of some sort or it's a wall roughly facing us
02164 float bestCheckDist = 0;
02165 //hmm, see if we're moving forward
02166 if ( DotProduct( self->client->ps.velocity, fwd ) < 200 )
02167 {//not running forward very fast
02168 //check to see if it's okay to move the other way
02169 if ( (trace.fraction*checkDist) <= 32 )
02170 {//wall on that side is close enough to wall-flip off of or wall-run on
02171 bestCheckDist = checkDist;
02172 checkDist *= -1.0f;
02173 VectorMA( self->r.currentOrigin, checkDist, right, traceto );
02174 //trace in the dir that we want to go
02175 trap_Trace( &trace, self->r.currentOrigin, mins, maxs, traceto, self->s.number, CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP );
02176 if ( trace.fraction >= 1.0f )
02177 {//it's clear, let's do it
02178 if ( allowWallFlips )
02179 {//okay to do wall-flips with this saber
02180 int parts;
02181
02182 //FIXME: check for drops?
02183 //turn the cartwheel into a wallflip in the other dir
02184 if ( rightdot > 0 )
02185 {
02186 anim = BOTH_WALL_FLIP_LEFT;
02187 self->client->ps.velocity[0] = self->client->ps.velocity[1] = 0;
02188 VectorMA( self->client->ps.velocity, 150, right, self->client->ps.velocity );
02189 }
02190 else
02191 {
02192 anim = BOTH_WALL_FLIP_RIGHT;
02193 self->client->ps.velocity[0] = self->client->ps.velocity[1] = 0;
02194 VectorMA( self->client->ps.velocity, -150, right, self->client->ps.velocity );
02195 }
02196 self->client->ps.velocity[2] = forceJumpStrength[FORCE_LEVEL_2]/2.25f;
02197 //animate me
02198 parts = SETANIM_LEGS;
02199 if ( !self->client->ps.weaponTime )
02200 {
02201 parts = SETANIM_BOTH;
02202 }
02203 NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
02204 self->client->ps.fd.forceJumpZStart = self->r.currentOrigin[2];//so we don't take damage if we land at same height
02205 //self->client->ps.pm_flags |= (PMF_JUMPING|PMF_SLOW_MO_FALL);
02206 if ( self->client->NPC_class == CLASS_BOBAFETT )
02207 {
02208 G_AddEvent( self, EV_JUMP, 0 );
02209 }
02210 else
02211 {
02212 G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/jump.wav" );
02213 }
02214 return EVASION_OTHER;
02215 }
02216 }
02217 else
02218 {//boxed in on both sides
02219 if ( DotProduct( self->client->ps.velocity, fwd ) < 0 )
02220 {//moving backwards
02221 return EVASION_NONE;
02222 }
02223 if ( (trace.fraction*checkDist) <= 32 && (trace.fraction*checkDist) < bestCheckDist )
02224 {
02225 bestCheckDist = checkDist;
02226 }
02227 }
02228 }
02229 else
02230 {//too far from that wall to flip or run off it, check other side
02231 checkDist *= -1.0f;
02232 VectorMA( self->r.currentOrigin, checkDist, right, traceto );
02233 //trace in the dir that we want to go
02234 trap_Trace( &trace, self->r.currentOrigin, mins, maxs, traceto, self->s.number, CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP );
02235 if ( (trace.fraction*checkDist) <= 32 )
02236 {//wall on this side is close enough
02237 bestCheckDist = checkDist;
02238 }
02239 else
02240 {//neither side has a wall within 32
02241 return EVASION_NONE;
02242 }
02243 }
02244 }
02245 //Try wall run?
02246 if ( bestCheckDist )
02247 {//one of the walls was close enough to wall-run on
02248 qboolean allowWallRuns = qtrue;
02249 if ( self->client->ps.weapon == WP_SABER )
02250 {
02251 if ( self->client->saber[0].model
02252 && self->client->saber[0].model[0]
02253 && (self->client->saber[0].saberFlags&SFL_NO_WALL_RUNS) )
02254 {
02255 allowWallRuns = qfalse;
02256 }
02257 else if ( self->client->saber[1].model
02258 && self->client->saber[1].model[0]
02259 && (self->client->saber[1].saberFlags&SFL_NO_WALL_RUNS) )
02260 {
02261 allowWallRuns = qfalse;
02262 }
02263 }
02264 if ( allowWallRuns )
02265 {//okay to do wallruns with this saber
02266 int parts;
02267
02268 //FIXME: check for long enough wall and a drop at the end?
02269 if ( bestCheckDist > 0 )
02270 {//it was to the right
02271 anim = BOTH_WALL_RUN_RIGHT;
02272 }
02273 else
02274 {//it was to the left
02275 anim = BOTH_WALL_RUN_LEFT;
02276 }
02277 self->client->ps.velocity[2] = forceJumpStrength[FORCE_LEVEL_2]/2.25f;
02278 //animate me
02279 parts = SETANIM_LEGS;
02280 if ( !self->client->ps.weaponTime )
02281 {
02282 parts = SETANIM_BOTH;
02283 }
02284 NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
02285 self->client->ps.fd.forceJumpZStart = self->r.currentOrigin[2];//so we don't take damage if we land at same height
02286 //self->client->ps.pm_flags |= (PMF_JUMPING|PMF_SLOW_MO_FALL);
02287 if ( self->client->NPC_class == CLASS_BOBAFETT )
02288 {
02289 G_AddEvent( self, EV_JUMP, 0 );
02290 }
02291 else
02292 {
02293 G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/jump.wav" );
02294 }
02295 return EVASION_OTHER;
02296 }
02297 }
02298 //else check for wall in front, do backflip off wall
02299 }
02300 }
02301 }
02302 return EVASION_NONE;
02303 }
|
|
|
Definition at line 110 of file NPC_AI_Jedi.c. References gentity_t, and TIMER_Set(). Referenced by NPC_SetMiscDefaultData().
00111 {
00112 TIMER_Set( ent, "roamTime", 0 );
00113 TIMER_Set( ent, "chatter", 0 );
00114 TIMER_Set( ent, "strafeLeft", 0 );
00115 TIMER_Set( ent, "strafeRight", 0 );
00116 TIMER_Set( ent, "noStrafe", 0 );
00117 TIMER_Set( ent, "walking", 0 );
00118 TIMER_Set( ent, "taunting", 0 );
00119 TIMER_Set( ent, "parryTime", 0 );
00120 TIMER_Set( ent, "parryReCalcTime", 0 );
00121 TIMER_Set( ent, "forceJumpChasing", 0 );
00122 TIMER_Set( ent, "jumpChaseDebounce", 0 );
00123 TIMER_Set( ent, "moveforward", 0 );
00124 TIMER_Set( ent, "moveback", 0 );
00125 TIMER_Set( ent, "movenone", 0 );
00126 TIMER_Set( ent, "moveright", 0 );
00127 TIMER_Set( ent, "moveleft", 0 );
00128 TIMER_Set( ent, "movecenter", 0 );
00129 TIMER_Set( ent, "saberLevelDebounce", 0 );
00130 TIMER_Set( ent, "noRetreat", 0 );
00131 TIMER_Set( ent, "holdLightning", 0 );
00132 TIMER_Set( ent, "gripping", 0 );
00133 TIMER_Set( ent, "draining", 0 );
00134 TIMER_Set( ent, "noturn", 0 );
00135 }
|
|
|
Definition at line 799 of file NPC_AI_Jedi.c. References CHAN_ITEM, gentity_s::client, FL_NOTARGET, gentity_s::flags, G_Sound(), G_SoundIndex(), gentity_t, playerState_s::powerups, gclient_s::ps, PW_CLOAKED, and Q3_INFINITE. Referenced by ClientThink_real(), ItemUse_UseCloak(), Jedi_CheckCloak(), and NPC_SetMiscDefaultData().
00800 {
00801 if ( self )
00802 {
00803 self->flags |= FL_NOTARGET;
00804 if ( self->client )
00805 {
00806 if ( !self->client->ps.powerups[PW_CLOAKED] )
00807 {//cloak
00808 self->client->ps.powerups[PW_CLOAKED] = Q3_INFINITE;
00809
00810 //FIXME: debounce attacks?
00811 //FIXME: temp sound
00812 G_Sound( self, CHAN_ITEM, G_SoundIndex("sound/chars/shadowtrooper/cloak.wav") );
00813 }
00814 }
00815 }
00816 }
|
|
|
Definition at line 818 of file NPC_AI_Jedi.c. References CHAN_ITEM, gentity_s::client, FL_NOTARGET, gentity_s::flags, G_Sound(), G_SoundIndex(), gentity_t, playerState_s::powerups, gclient_s::ps, and PW_CLOAKED. Referenced by ClientThink_real(), DEMP2_AltRadiusDamage(), ForceLightningDamage(), G_MissileImpact(), G_RunFrame(), ItemUse_UseCloak(), Jedi_Ambush(), and Jedi_CheckCloak().
00819 {
00820 if ( self )
00821 {
00822 self->flags &= ~FL_NOTARGET;
00823 if ( self->client )
00824 {
00825 if ( self->client->ps.powerups[PW_CLOAKED] )
00826 {//Uncloak
00827 self->client->ps.powerups[PW_CLOAKED] = 0;
00828
00829 G_Sound( self, CHAN_ITEM, G_SoundIndex("sound/chars/shadowtrooper/decloak.wav") );
00830 }
00831 }
00832 }
00833 }
|
|
||||||||||||||||
|
Definition at line 3686 of file NPC_AI_Jedi.c. References AngleVectors(), gentity_s::client, entityShared_t::currentOrigin, DotProduct, gclient_s::enemyTeam, trace_t::entityNum, trace_t::fraction, g_entities, gentity_t, gentity_s::health, gentity_s::inuse, MASK_SHOT, MAX_GENTITIES, NULL, entityState_s::number, gclient_s::playerTeam, gclient_s::ps, Q3_INFINITE, gentity_s::r, gentity_s::s, trap_EntitiesInBox(), trap_InPVS(), trap_Trace(), vec3_origin, vec3_t, VectorNormalize(), VectorSubtract, and playerState_s::viewangles.
03687 {
03688 vec3_t forward, mins, maxs, dir;
03689 float dist, bestDist = Q3_INFINITE;
03690 gentity_t *enemy = fallback;
03691 gentity_t *check = NULL;
03692 int entityList[MAX_GENTITIES];
03693 int e, numListedEntities;
03694 trace_t tr;
03695
03696 if ( !self->client )
03697 {
03698 return enemy;
03699 }
03700
03701 AngleVectors( self->client->ps.viewangles, forward, NULL, NULL );
03702
03703 for ( e = 0 ; e < 3 ; e++ )
03704 {
03705 mins[e] = self->r.currentOrigin[e] - 1024;
03706 maxs[e] = self->r.currentOrigin[e] + 1024;
03707 }
03708 numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
03709
03710 for ( e = 0 ; e < numListedEntities ; e++ )
03711 {
03712 check = &g_entities[entityList[e]];
03713 if ( check == self )
03714 {//me
03715 continue;
03716 }
03717 if ( !(check->inuse) )
03718 {//freed
03719 continue;
03720 }
03721 if ( !check->client )
03722 {//not a client - FIXME: what about turrets?
03723 continue;
03724 }
03725 if ( check->client->playerTeam != self->client->enemyTeam )
03726 {//not an enemy - FIXME: what about turrets?
03727 continue;
03728 }
03729 if ( check->health <= 0 )
03730 {//dead
03731 continue;
03732 }
03733
03734 if ( !trap_InPVS( check->r.currentOrigin, self->r.currentOrigin ) )
03735 {//can't potentially see them
03736 continue;
03737 }
03738
03739 VectorSubtract( check->r.currentOrigin, self->r.currentOrigin, dir );
03740 dist = VectorNormalize( dir );
03741
03742 if ( DotProduct( dir, forward ) < minDot )
03743 {//not in front
03744 continue;
03745 }
03746
03747 //really should have a clear LOS to this thing...
03748 trap_Trace( &tr, self->r.currentOrigin, vec3_origin, vec3_origin, check->r.currentOrigin, self->s.number, MASK_SHOT );
03749 if ( tr.fraction < 1.0f && tr.entityNum != check->s.number )
03750 {//must have clear shot
03751 continue;
03752 }
03753
03754 if ( dist < bestDist )
03755 {//closer than our last best one
03756 dist = bestDist;
03757 enemy = check;
03758 }
03759 }
03760 return enemy;
03761 }
|
|
|
Definition at line 137 of file NPC_AI_Jedi.c. References gNPC_t::blockedSpeechDebounceTime, EV_PUSHFAIL, G_AddVoiceEvent(), gentity_t, gentity_s::health, level, gentity_s::NPC, entityState_s::number, gentity_s::s, and level_locals_t::time. Referenced by WP_ResistForcePush().
00138 {
00139 if ( !self->s.number )
00140 {
00141 G_AddVoiceEvent( self, EV_PUSHFAIL, 3000 );
00142 }
00143 else if ( self->health > 0 && self->NPC && self->NPC->blockedSpeechDebounceTime < level.time )
00144 {
00145 G_AddVoiceEvent( self, EV_PUSHFAIL, 3000 );
00146 self->NPC->blockedSpeechDebounceTime = level.time + 3000;
00147 }
00148 }
|
|
|
Definition at line 150 of file NPC_AI_Jedi.c. References gNPC_t::blockedSpeechDebounceTime, EV_DEFLECT1, EV_DEFLECT3, G_AddVoiceEvent(), gentity_t, gentity_s::health, level, gentity_s::NPC, entityState_s::number, Q_irand(), gentity_s::s, and level_locals_t::time.
00151 {
00152 if ( !self->s.number )
00153 {
00154 G_AddVoiceEvent( self, Q_irand( EV_DEFLECT1, EV_DEFLECT3 ), 3000 );
00155 }
00156 else if ( self->health > 0 && self->NPC && self->NPC->blockedSpeechDebounceTime < level.time )
00157 {
00158 G_AddVoiceEvent( self, Q_irand( EV_DEFLECT1, EV_DEFLECT3 ), 3000 );
00159 self->NPC->blockedSpeechDebounceTime = level.time + 3000;
00160 }
00161 }
|
|
|
Definition at line 2443 of file NPC_AI_Jedi.c. References CLASS_JEDI, CLASS_TAVION, gentity_s::client, playerState_s::fd, FORCE_LEVEL_1, FORCE_LEVEL_2, forcedata_s::forcePowerLevel, FP_SABER_DEFENSE, g_spskill, gentity_t, vmCvar_t::integer, gclient_s::NPC_class, NPCInfo, gclient_s::ps, qboolean, qfalse, qtrue, gNPC_t::rank, and RANK_COMMANDER. Referenced by Jedi_SaberBlockGo().
02444 {
02445 if ( ( self->client->NPC_class == CLASS_JEDI && NPCInfo->rank == RANK_COMMANDER ) ||
02446 self->client->NPC_class == CLASS_TAVION ||
02447 (self->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE]>FORCE_LEVEL_1&&g_spskill.integer>1) ||
02448 (self->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE]>FORCE_LEVEL_2&&g_spskill.integer>0) )
02449 {
02450 return qtrue;
02451 }
02452 return qfalse;
02453 }
|
|
|
Definition at line 966 of file NPC_AI_Jedi.c. References gentity_t, gentity_s::NPC, Q_irand(), and TIMER_Set().
|
|
||||||||||||
|
Definition at line 2305 of file NPC_AI_Jedi.c. References bg_parryDebounce, ceil(), CLASS_TAVION, gentity_s::client, EVASION_CARTWHEEL, EVASION_DODGE, EVASION_DUCK, EVASION_DUCK_PARRY, EVASION_FJUMP, EVASION_JUMP, EVASION_JUMP_PARRY, EVASION_OTHER, EVASION_PARRY, playerState_s::fd, forcedata_s::forcePowerLevel, FP_SABER_DEFENSE, g_saberRealisticCombat, g_spskill, gentity_t, vmCvar_t::integer, gentity_s::NPC, gclient_s::NPC_class, entityState_s::number, gclient_s::ps, Q_irand(), gNPC_t::rank, RANK_CIVILIAN, RANK_CREWMAN, RANK_LT_JG, gentity_s::s, playerState_s::saberInFlight, and playerState_s::torsoTimer. Referenced by Jedi_SaberBlockGo().
02306 {
02307 if ( !self->client )
02308 {
02309 return 0;
02310 }
02311 if ( !self->s.number )
02312 {//player
02313 return bg_parryDebounce[self->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE]];
02314 }
02315 else if ( self->NPC )
02316 {
02317 if ( !g_saberRealisticCombat.integer
02318 && ( g_spskill.integer == 2 || (g_spskill.integer == 1 && self->client->NPC_class == CLASS_TAVION) ) )
02319 {
02320 if ( self->client->NPC_class == CLASS_TAVION )
02321 {
02322 return 0;
02323 }
02324 else
02325 {
02326 return Q_irand( 0, 150 );
02327 }
02328 }
02329 else
02330 {
02331 int baseTime;
02332 if ( evasionType == EVASION_DODGE )
02333 {
02334 baseTime = self->client->ps.torsoTimer;
02335 }
02336 else if ( evasionType == EVASION_CARTWHEEL )
02337 {
02338 baseTime = self->client->ps.torsoTimer;
02339 }
02340 else if ( self->client->ps.saberInFlight )
02341 {
02342 baseTime = Q_irand( 1, 3 ) * 50;
02343 }
02344 else
02345 {
02346 if ( g_saberRealisticCombat.integer )
02347 {
02348 baseTime = 500;
02349
02350 switch ( g_spskill.integer )
02351 {
02352 case 0:
02353 baseTime = 500;
02354 break;
02355 case 1:
02356 baseTime = 300;
02357 break;
02358 case 2:
02359 default:
02360 baseTime = 100;
02361 break;
02362 }
02363 }
02364 else
02365 {
02366 baseTime = 150;//500;
02367
02368 switch ( g_spskill.integer )
02369 {
02370 case 0:
02371 baseTime = 200;//500;
02372 break;
02373 case 1:
02374 baseTime = 100;//300;
02375 break;
02376 case 2:
02377 default:
02378 baseTime = 50;//100;
02379 break;
02380 }
02381 }
02382
02383 if ( self->client->NPC_class == CLASS_TAVION )
02384 {//Tavion is faster
02385 baseTime = ceil(baseTime/2.0f);
02386 }
02387 else if ( self->NPC->rank >= RANK_LT_JG )
02388 {//fencers, bosses, shadowtroopers, luke, desann, et al use the norm
02389 if ( Q_irand( 0, 2 ) )
02390 {//medium speed parry
02391 baseTime = baseTime;
02392 }
02393 else
02394 {//with the occasional fast parry
02395 baseTime = ceil(baseTime/2.0f);
02396 }
02397 }
02398 else if ( self->NPC->rank == RANK_CIVILIAN )
02399 {//grunts are slowest
02400 baseTime = baseTime*Q_irand(1,3);
02401 }
02402 else if ( self->NPC->rank == RANK_CREWMAN )
02403 {//acrobats aren't so bad
02404 if ( evasionType == EVASION_PARRY
02405 || evasionType == EVASION_DUCK_PARRY
02406 || evasionType == EVASION_JUMP_PARRY )
02407 {//slower with parries
02408 baseTime = baseTime*Q_irand(1,2);
02409 }
02410 else
02411 {//faster with acrobatics
02412 //baseTime = baseTime;
02413 }
02414 }
02415 else
02416 {//force users are kinda slow
02417 baseTime = baseTime*Q_irand(1,2);
02418 }
02419 if ( evasionType == EVASION_DUCK || evasionType == EVASION_DUCK_PARRY )
02420 {
02421 baseTime += 100;
02422 }
02423 else if ( evasionType == EVASION_JUMP || evasionType == EVASION_JUMP_PARRY )
02424 {
02425 baseTime += 50;
02426 }
02427 else if ( evasionType == EVASION_OTHER )
02428 {
02429 baseTime += 100;
02430 }
02431 else if ( evasionType == EVASION_FJUMP )
02432 {
02433 baseTime += 100;
02434 }
02435 }
02436
02437 return baseTime;
02438 }
02439 }
02440 return 0;
02441 }
|
|
||||||||||||||||||||||||||||
|
Definition at line 2485 of file NPC_AI_Jedi.c. References entityShared_t::absmin, AngleVectors(), BG_InRoll(), BG_SaberInAttack(), BG_SaberInSpecialAttack(), BG_SabersOff(), BG_SpinningSaberAnim(), BLOCKED_LOWER_LEFT, BLOCKED_LOWER_RIGHT, BLOCKED_TOP, BLOCKED_UPPER_LEFT, BLOCKED_UPPER_RIGHT, BOTH_BUTTERFLY_LEFT, BOTH_BUTTERFLY_RIGHT, BOTH_DODGE_BL, BOTH_DODGE_BR, BOTH_DODGE_FL, BOTH_DODGE_FR, BOTH_DODGE_L, BOTH_DODGE_R, CHAN_BODY, CLASS_BOBAFETT, CLASS_TAVION, gentity_s::client, Com_Printf(), entityShared_t::currentOrigin, d_JediAI, d_slowmodeath, DotProduct, gentity_s::enemy, ENTITYNUM_NONE, EV_JUMP, EVASION_CARTWHEEL, EVASION_DODGE, EVASION_DUCK, EVASION_DUCK_PARRY, EVASION_FJUMP, EVASION_JUMP, EVASION_JUMP_PARRY, EVASION_NONE, EVASION_PARRY, evasionType_t, renderInfo_s::eyePoint, fabs(), playerState_s::fd, forcedata_s::forceJumpCharge, forcedata_s::forceJumpZStart, forcedata_s::forcePowerDebounce, forcedata_s::forcePowersActive, forcedata_s::forceRageRecoveryTime, usercmd_s::forwardmove, FP_DRAIN, FP_GRIP, FP_RAGE, FP_SABER_DEFENSE, G_AddEvent(), G_Sound(), G_SoundIndex(), G_StartMatrixEffect(), gentity_t, playerState_s::groundEntityNum, vmCvar_t::integer, Jedi_CheckFlipEvasions(), Jedi_QuickReactions(), Jedi_ReCalcParryTime(), Jedi_SaberBusy(), JUMP_VELOCITY, playerState_s::legsAnim, level, gentity_s::NPC, NPC, gclient_s::NPC_class, NPC_SetAnim(), NULL, entityState_s::number, playerState_s::pm_flags, PM_InKnockDown(), PM_SaberInStart(), playerState_s::pm_time, PMF_DUCKED, PMF_TIME_KNOCKBACK, entityState_s::pos, gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, gNPC_t::rank, RANK_CREWMAN, RANK_LT_JG, gclient_s::renderInfo, usercmd_s::rightmove, gentity_s::s, playerState_s::saberBlocked, playerState_s::saberInFlight, playerState_s::saberMove, SCF_NO_ACROBATICS, gNPC_t::scriptFlags, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, level_locals_t::time, TIMER_Done(), TIMER_Set(), TIMER_Start(), playerState_s::torsoAnim, playerState_s::torsoTimer, trajectory_t::trDelta, usercmd_s::upmove, usercmd_t, vec3_t, VectorCopy, VectorNormalize2(), VectorSubtract, playerState_s::velocity, playerState_s::viewangles, entityState_s::weapon, playerState_s::weaponTime, WP_ForcePowerStop(), WP_MissileBlockForBlock(), and WP_SABER. Referenced by WP_SaberStartMissileBlockCheck().
02486 {
02487 vec3_t hitloc, hitdir, diff, fwdangles={0,0,0}, right;
02488 float rightdot;
02489 float zdiff;
02490 int duckChance = 0;
02491 int dodgeAnim = -1;
02492 qboolean saberBusy = qfalse, evaded = qfalse, doDodge = qfalse;
02493 evasionType_t evasionType = EVASION_NONE;
02494
02495 //FIXME: if we don't have our saber in hand, pick the force throw option or a jump or strafe!
02496 //FIXME: reborn don't block enough anymore
02497 if ( !incoming )
02498 {
02499 VectorCopy( pHitloc, hitloc );
02500 VectorCopy( phitDir, hitdir );
02501 //FIXME: maybe base this on rank some? And/or g_spskill?
02502 if ( self->client->ps.saberInFlight )
02503 {//DOH! do non-saber evasion!
02504 saberBusy = qtrue;
02505 }
02506 else if ( Jedi_QuickReactions( self ) )
02507 {//jedi trainer and tavion are must faster at parrying and can do it whenever they like
02508 //Also, on medium, all level 3 people can parry any time and on hard, all level 2 or 3 people can parry any time
02509 }
02510 else
02511 {
02512 saberBusy = Jedi_SaberBusy( self );
02513 }
02514 }
02515 else
02516 {
02517 if ( incoming->s.weapon == WP_SABER )
02518 {//flying lightsaber, face it!
02519 //FIXME: for this to actually work, we'd need to call update angles too?
02520 //Jedi_FaceEntity( self, incoming, qtrue );
02521 }
02522 VectorCopy( incoming->r.currentOrigin, hitloc );
02523 VectorNormalize2( incoming->s.pos.trDelta, hitdir );
02524 }
02525 if ( self->client && self->client->NPC_class == CLASS_BOBAFETT )
02526 {
02527 saberBusy = qtrue;
02528 }
02529
02530 VectorSubtract( hitloc, self->client->renderInfo.eyePoint, diff );
02531 diff[2] = 0;
02532 //VectorNormalize( diff );
02533 fwdangles[1] = self->client->ps.viewangles[1];
02534 // Ultimately we might care if the shot was ahead or behind, but for now, just quadrant is fine.
02535 AngleVectors( fwdangles, NULL, right, NULL );
02536
02537 rightdot = DotProduct(right, diff);// + flrand(-0.10f,0.10f);
02538 //totalHeight = self->client->renderInfo.eyePoint[2] - self->r.absmin[2];
02539 zdiff = hitloc[2] - self->client->renderInfo.eyePoint[2];// + Q_irand(-6,6);
02540
02541 //see if we can dodge if need-be
02542 if ( (dist>16&&(Q_irand( 0, 2 )||saberBusy))
02543 || self->client->ps.saberInFlight
02544 || BG_SabersOff( &self->client->ps )
02545 || self->client->NPC_class == CLASS_BOBAFETT )
02546 {//either it will miss by a bit (and 25% chance) OR our saber is not in-hand OR saber is off
02547 if ( self->NPC && (self->NPC->rank == RANK_CREWMAN || self->NPC->rank >= RANK_LT_JG) )
02548 {//acrobat or fencer or above
02549 if ( self->client->ps.groundEntityNum != ENTITYNUM_NONE &&//on the ground
02550 !(self->client->ps.pm_flags&PMF_DUCKED)&&cmd->upmove>=0&&TIMER_Done( self, "duck" )//not ducking
02551 && !BG_InRoll( &self->client->ps, self->client->ps.legsAnim )//not rolling
02552 && !PM_InKnockDown( &self->client->ps )//not knocked down
02553 && ( self->client->ps.saberInFlight ||
02554 self->client->NPC_class == CLASS_BOBAFETT ||
02555 (!BG_SaberInAttack( self->client->ps.saberMove )//not attacking
02556 && !PM_SaberInStart( self->client->ps.saberMove )//not starting an attack
02557 && !BG_SpinningSaberAnim( self->client->ps.torsoAnim )//not in a saber spin
02558 && !BG_SaberInSpecialAttack( self->client->ps.torsoAnim ))//not in a special attack
02559 )
02560 )
02561 {//need to check all these because it overrides both torso and legs with the dodge
02562 doDodge = qtrue;
02563 }
02564 }
02565 }
02566 // Figure out what quadrant the block was in.
02567 if ( d_JediAI.integer )
02568 {
02569 Com_Printf( "(%d) evading attack from height %4.2f, zdiff: %4.2f, rightdot: %4.2f\n", level.time, hitloc[2]-self->r.absmin[2],zdiff,rightdot);
02570 }
02571
02572 //UL = > -1//-6
02573 //UR = > -6//-9
02574 //TOP = > +6//+4
02575 //FIXME: take FP_SABER_DEFENSE into account here somehow?
02576 if ( zdiff >= -5 )//was 0
02577 {
02578 if ( incoming || !saberBusy )
02579 {
02580 if ( rightdot > 12
02581 || (rightdot > 3 && zdiff < 5)
02582 || (!incoming&&fabs(hitdir[2])<0.25f) )//was normalized, 0.3
02583 {//coming from right
02584 if ( doDodge )
02585 {
02586 if ( self->client->NPC_class == CLASS_BOBAFETT && !Q_irand( 0, 2 ) )
02587 {//roll!
02588 TIMER_Start( self, "duck", Q_irand( 500, 1500 ) );
02589 TIMER_Start( self, "strafeLeft", Q_irand( 500, 1500 ) );
02590 TIMER_Set( self, "strafeRight", 0 );
02591 evasionType = EVASION_DUCK;
02592 evaded = qtrue;
02593 }
02594 else if ( Q_irand( 0, 1 ) )
02595 {
02596 dodgeAnim = BOTH_DODGE_FL;
02597 }
02598 else
02599 {
02600 dodgeAnim = BOTH_DODGE_BL;
02601 }
02602 }
02603 else
02604 {
02605 self->client->ps.saberBlocked = BLOCKED_UPPER_RIGHT;
02606 evasionType = EVASION_PARRY;
02607 if ( self->client->ps.groundEntityNum != ENTITYNUM_NONE )
02608 {
02609 if ( zdiff > 5 )
02610 {
02611 TIMER_Start( self, "duck", Q_irand( 500, 1500 ) );
02612 evasionType = EVASION_DUCK_PARRY;
02613 evaded = qtrue;
02614 if ( d_JediAI.integer )
02615 {
02616 Com_Printf( "duck " );
02617 }
02618 }
02619 else
02620 {
02621 duckChance = 6;
02622 }
02623 }
02624 }
02625 if ( d_JediAI.integer )
02626 {
02627 Com_Printf( "UR block\n" );
02628 }
02629 }
02630 else if ( rightdot < -12
02631 || (rightdot < -3 && zdiff < 5)
02632 || (!incoming&&fabs(hitdir[2])<0.25f) )//was normalized, -0.3
02633 {//coming from left
02634 if ( doDodge )
02635 {
02636 if ( self->client->NPC_class == CLASS_BOBAFETT && !Q_irand( 0, 2 ) )
02637 {//roll!
02638 TIMER_Start( self, "duck", Q_irand( 500, 1500 ) );
02639 TIMER_Start( self, "strafeRight", Q_irand( 500, 1500 ) );
02640 TIMER_Set( self, "strafeLeft", 0 );
02641 evasionType = EVASION_DUCK;
02642 evaded = qtrue;
02643 }
02644 else if ( Q_irand( 0, 1 ) )
02645 {
02646 dodgeAnim = BOTH_DODGE_FR;
02647 }
02648 else
02649 {
02650 dodgeAnim = BOTH_DODGE_BR;
02651 }
02652 }
02653 else
02654 {
02655 self->client->ps.saberBlocked = BLOCKED_UPPER_LEFT;
02656 evasionType = EVASION_PARRY;
02657 if ( self->client->ps.groundEntityNum != ENTITYNUM_NONE )
02658 {
02659 if ( zdiff > 5 )
02660 {
02661 TIMER_Start( self, "duck", Q_irand( 500, 1500 ) );
02662 evasionType = EVASION_DUCK_PARRY;
02663 evaded = qtrue;
02664 if ( d_JediAI.integer )
02665 {
02666 Com_Printf( "duck " );
02667 }
02668 }
02669 else
02670 {
02671 duckChance = 6;
02672 }
02673 }
02674 }
02675 if ( d_JediAI.integer )
02676 {
02677 Com_Printf( "UL block\n" );
02678 }
02679 }
02680 else
02681 {
02682 self->client->ps.saberBlocked = BLOCKED_TOP;
02683 evasionType = EVASION_PARRY;
02684 if ( self->client->ps.groundEntityNum != ENTITYNUM_NONE )
02685 {
02686 duckChance = 4;
02687 }
02688 if ( d_JediAI.integer )
02689 {
02690 Com_Printf( "TOP block\n" );
02691 }
02692 }
02693 evaded = qtrue;
02694 }
02695 else
02696 {
02697 if ( self->client->ps.groundEntityNum != ENTITYNUM_NONE )
02698 {
02699 //duckChance = 2;
02700 TIMER_Start( self, "duck", Q_irand( 500, 1500 ) );
02701 evasionType = EVASION_DUCK;
02702 evaded = qtrue;
02703 if ( d_JediAI.integer )
02704 {
02705 Com_Printf( "duck " );
02706 }
02707 }
02708 }
02709 }
02710 //LL = -22//= -18 to -39
02711 //LR = -23//= -20 to -41
02712 else if ( zdiff > -22 )//was-15 )
02713 {
02714 if ( 1 )//zdiff < -10 )
02715 {//hmm, pretty low, but not low enough to use the low block, so we need to duck
02716 if ( self->client->ps.groundEntityNum != ENTITYNUM_NONE )
02717 {
02718 //duckChance = 2;
02719 TIMER_Start( self, "duck", Q_irand( 500, 1500 ) );
02720 evasionType = EVASION_DUCK;
02721 evaded = qtrue;
02722 if ( d_JediAI.integer )
02723 {
02724 Com_Printf( "duck " );
02725 }
02726 }
02727 else
02728 {//in air! Ducking does no good
02729 }
02730 }
02731 if ( incoming || !saberBusy )
02732 {
02733 if ( rightdot > 8 || (rightdot > 3 && zdiff < -11) )//was normalized, 0.2
02734 {
02735 if ( doDodge )
02736 {
02737 if ( self->client->NPC_class == CLASS_BOBAFETT && !Q_irand( 0, 2 ) )
02738 {//roll!
02739 TIMER_Start( self, "strafeLeft", Q_irand( 500, 1500 ) );
02740 TIMER_Set( self, "strafeRight", 0 );
02741 }
02742 else
02743 {
02744 dodgeAnim = BOTH_DODGE_L;
02745 }
02746 }
02747 else
02748 {
02749 self->client->ps.saberBlocked = BLOCKED_UPPER_RIGHT;
02750 if ( evasionType == EVASION_DUCK )
02751 {
02752 evasionType = EVASION_DUCK_PARRY;
02753 }
02754 else
02755 {
02756 evasionType = EVASION_PARRY;
02757 }
02758 }
02759 if ( d_JediAI.integer )
02760 {
02761 Com_Printf( "mid-UR block\n" );
02762 }
02763 }
02764 else if ( rightdot < -8 || (rightdot < -3 && zdiff < -11) )//was normalized, -0.2
02765 {
02766 if ( doDodge )
02767 {
02768 if ( self->client->NPC_class == CLASS_BOBAFETT && !Q_irand( 0, 2 ) )
02769 {//roll!
02770 TIMER_Start( self, "strafeLeft", Q_irand( 500, 1500 ) );
02771 TIMER_Set( self, "strafeRight", 0 );
02772 }
02773 else
02774 {
02775 dodgeAnim = BOTH_DODGE_R;
02776 }
02777 }
02778 else
02779 {
02780 self->client->ps.saberBlocked = BLOCKED_UPPER_LEFT;
02781 if ( evasionType == EVASION_DUCK )
02782 {
02783 evasionType = EVASION_DUCK_PARRY;
02784 }
02785 else
02786 {
02787 evasionType = EVASION_PARRY;
02788 }
02789 }
02790 if ( d_JediAI.integer )
02791 {
02792 Com_Printf( "mid-UL block\n" );
02793 }
02794 }
02795 else
02796 {
02797 self->client->ps.saberBlocked = BLOCKED_TOP;
02798 if ( evasionType == EVASION_DUCK )
02799 {
02800 evasionType = EVASION_DUCK_PARRY;
02801 }
02802 else
02803 {
02804 evasionType = EVASION_PARRY;
02805 }
02806 if ( d_JediAI.integer )
02807 {
02808 Com_Printf( "mid-TOP block\n" );
02809 }
02810 }
02811 evaded = qtrue;
02812 }
02813 }
02814 else if ( saberBusy || (zdiff < -36 && ( zdiff < -44 || !Q_irand( 0, 2 ) ) ) )//was -30 and -40//2nd one was -46
02815 {//jump!
02816 if ( self->client->ps.groundEntityNum == ENTITYNUM_NONE )
02817 {//already in air, duck to pull up legs
02818 TIMER_Start( self, "duck", Q_irand( 500, 1500 ) );
02819 evasionType = EVASION_DUCK;
02820 evaded = qtrue;
02821 if ( d_JediAI.integer )
02822 {
02823 Com_Printf( "legs up\n" );
02824 }
02825 if ( incoming || !saberBusy )
02826 {
02827 //since the jump may be cleared if not safe, set a lower block too
02828 if ( rightdot >= 0 )
02829 {
02830 self->client->ps.saberBlocked = BLOCKED_LOWER_RIGHT;
02831 evasionType = EVASION_DUCK_PARRY;
02832 if ( d_JediAI.integer )
02833 {
02834 Com_Printf( "LR block\n" );
02835 }
02836 }
02837 else
02838 {
02839 self->client->ps.saberBlocked = BLOCKED_LOWER_LEFT;
02840 evasionType = EVASION_DUCK_PARRY;
02841 if ( d_JediAI.integer )
02842 {
02843 Com_Printf( "LL block\n" );
02844 }
02845 }
02846 evaded = qtrue;
02847 }
02848 }
02849 else
02850 {//gotta jump!
02851 if ( self->NPC && (self->NPC->rank == RANK_CREWMAN || self->NPC->rank > RANK_LT_JG ) &&
02852 (!Q_irand( 0, 10 ) || (!Q_irand( 0, 2 ) && (cmd->forwardmove || cmd->rightmove))) )
02853 {//superjump
02854 //FIXME: check the jump, if can't, then block
02855 if ( self->NPC
02856 && !(self->NPC->scriptFlags&SCF_NO_ACROBATICS)
02857 && self->client->ps.fd.forceRageRecoveryTime < level.time
02858 && !(self->client->ps.fd.forcePowersActive&(1<<FP_RAGE))
02859 && !PM_InKnockDown( &self->client->ps ) )
02860 {
02861 self->client->ps.fd.forceJumpCharge = 320;//FIXME: calc this intelligently
02862 evasionType = EVASION_FJUMP;
02863 evaded = qtrue;
02864 if ( d_JediAI.integer )
02865 {
02866 Com_Printf( "force jump + " );
02867 }
02868 }
02869 }
02870 else
02871 {//normal jump
02872 //FIXME: check the jump, if can't, then block
02873 if ( self->NPC
02874 && !(self->NPC->scriptFlags&SCF_NO_ACROBATICS)
02875 && self->client->ps.fd.forceRageRecoveryTime < level.time
02876 && !(self->client->ps.fd.forcePowersActive&(1<<FP_RAGE)) )
02877 {
02878 if ( self->client->NPC_class == CLASS_BOBAFETT && !Q_irand( 0, 1 ) )
02879 {//roll!
02880 if ( rightdot > 0 )
02881 {
02882 TIMER_Start( self, "strafeLeft", Q_irand( 500, 1500 ) );
02883 TIMER_Set( self, "strafeRight", 0 );
02884 TIMER_Set( self, "walking", 0 );
02885 }
02886 else
02887 {
02888 TIMER_Start( self, "strafeRight", Q_irand( 500, 1500 ) );
02889 TIMER_Set( self, "strafeLeft", 0 );
02890 TIMER_Set( self, "walking", 0 );
02891 }
02892 }
02893 else
02894 {
02895 if ( self == NPC )
02896 {
02897 cmd->upmove = 127;
02898 }
02899 else
02900 {
02901 self->client->ps.velocity[2] = JUMP_VELOCITY;
02902 }
02903 }
02904 evasionType = EVASION_JUMP;
02905 evaded = qtrue;
02906 if ( d_JediAI.integer )
02907 {
02908 Com_Printf( "jump + " );
02909 }
02910 }
02911 if ( self->client->NPC_class == CLASS_TAVION )
02912 {
02913 if ( !incoming
02914 && self->client->ps.groundEntityNum < ENTITYNUM_NONE
02915 && !Q_irand( 0, 2 ) )
02916 {
02917 if ( !BG_SaberInAttack( self->client->ps.saberMove )
02918 && !PM_SaberInStart( self->client->ps.saberMove )
02919 && !BG_InRoll( &self->client->ps, self->client->ps.legsAnim )
02920 && !PM_InKnockDown( &self->client->ps )
02921 && !BG_SaberInSpecialAttack( self->client->ps.torsoAnim ) )
02922 {//do the butterfly!
02923 int butterflyAnim;
02924 if ( Q_irand( 0, 1 ) )
02925 {
02926 butterflyAnim = BOTH_BUTTERFLY_LEFT;
02927 }
02928 else
02929 {
02930 butterflyAnim = BOTH_BUTTERFLY_RIGHT;
02931 }
02932 evasionType = EVASION_CARTWHEEL;
02933 NPC_SetAnim( self, SETANIM_BOTH, butterflyAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
02934 self->client->ps.velocity[2] = 225;
02935 self->client->ps.fd.forceJumpZStart = self->r.currentOrigin[2];//so we don't take damage if we land at same height
02936 // self->client->ps.pm_flags |= PMF_JUMPING|PMF_SLOW_MO_FALL;
02937 // self->client->ps.SaberActivateTrail( 300 );//FIXME: reset this when done!
02938 //Ah well. No hacking from the server for now.
02939 if ( self->client->NPC_class == CLASS_BOBAFETT )
02940 {
02941 G_AddEvent( self, EV_JUMP, 0 );
02942 }
02943 else
02944 {
02945 G_Sound( self, CHAN_BODY, G_SoundIndex("sound/weapons/force/jump.wav") );
02946 }
02947 cmd->upmove = 0;
02948 saberBusy = qtrue;
02949 evaded = qtrue;
02950 }
02951 }
02952 }
02953 }
02954 if ( ((evasionType = Jedi_CheckFlipEvasions( self, rightdot, zdiff ))!=EVASION_NONE) )
02955 {
02956 if ( d_slowmodeath.integer > 5 && self->enemy && !self->enemy->s.number )
02957 {
02958 G_StartMatrixEffect( self );
02959 }
02960 saberBusy = qtrue;
02961 evaded = qtrue;
02962 }
02963 else if ( incoming || !saberBusy )
02964 {
02965 //since the jump may be cleared if not safe, set a lower block too
02966 if ( rightdot >= 0 )
02967 {
02968 self->client->ps.saberBlocked = BLOCKED_LOWER_RIGHT;
02969 if ( evasionType == EVASION_JUMP )
02970 {
02971 evasionType = EVASION_JUMP_PARRY;
02972 }
02973 else if ( evasionType == EVASION_NONE )
02974 {
02975 evasionType = EVASION_PARRY;
02976 }
02977 if ( d_JediAI.integer )
02978 {
02979 Com_Printf( "LR block\n" );
02980 }
02981 }
02982 else
02983 {
02984 self->client->ps.saberBlocked = BLOCKED_LOWER_LEFT;
02985 if ( evasionType == EVASION_JUMP )
02986 {
02987 evasionType = EVASION_JUMP_PARRY;
02988 }
02989 else if ( evasionType == EVASION_NONE )
02990 {
02991 evasionType = EVASION_PARRY;
02992 }
02993 if ( d_JediAI.integer )
02994 {
02995 Com_Printf( "LL block\n" );
02996 }
02997 }
02998 evaded = qtrue;
02999 }
03000 }
03001 }
03002 else
03003 {
03004 if ( incoming || !saberBusy )
03005 {
03006 if ( rightdot >= 0 )
03007 {
03008 self->client->ps.saberBlocked = BLOCKED_LOWER_RIGHT;
03009 evasionType = EVASION_PARRY;
03010 if ( d_JediAI.integer )
03011 {
03012 Com_Printf( "LR block\n" );
03013 }
03014 }
03015 else
03016 {
03017 self->client->ps.saberBlocked = BLOCKED_LOWER_LEFT;
03018 evasionType = EVASION_PARRY;
03019 if ( d_JediAI.integer )
03020 {
03021 Com_Printf( "LL block\n" );
03022 }
03023 }
03024 if ( incoming && incoming->s.weapon == WP_SABER )
03025 {//thrown saber!
03026 if ( self->NPC && (self->NPC->rank == RANK_CREWMAN || self->NPC->rank > RANK_LT_JG ) &&
03027 (!Q_irand( 0, 10 ) || (!Q_irand( 0, 2 ) && (cmd->forwardmove || cmd->rightmove))) )
03028 {//superjump
03029 //FIXME: check the jump, if can't, then block
03030 if ( self->NPC
03031 && !(self->NPC->scriptFlags&SCF_NO_ACROBATICS)
03032 && self->client->ps.fd.forceRageRecoveryTime < level.time
03033 && !(self->client->ps.fd.forcePowersActive&(1<<FP_RAGE))
03034 && !PM_InKnockDown( &self->client->ps ) )
03035 {
03036 self->client->ps.fd.forceJumpCharge = 320;//FIXME: calc this intelligently
03037 evasionType = EVASION_FJUMP;
03038 if ( d_JediAI.integer )
03039 {
03040 Com_Printf( "force jump + " );
03041 }
03042 }
03043 }
03044 else
03045 {//normal jump
03046 //FIXME: check the jump, if can't, then block
03047 if ( self->NPC
03048 && !(self->NPC->scriptFlags&SCF_NO_ACROBATICS)
03049 && self->client->ps.fd.forceRageRecoveryTime < level.time
03050 && !(self->client->ps.fd.forcePowersActive&(1<<FP_RAGE)))
03051 {
03052 if ( self == NPC )
03053 {
03054 cmd->upmove = 127;
03055 }
03056 else
03057 {
03058 self->client->ps.velocity[2] = JUMP_VELOCITY;
03059 }
03060 evasionType = EVASION_JUMP_PARRY;
03061 if ( d_JediAI.integer )
03062 {
03063 Com_Printf( "jump + " );
03064 }
03065 }
03066 }
03067 }
03068 evaded = qtrue;
03069 }
03070 }
03071
03072 if ( evasionType == EVASION_NONE )
03073 {
03074 return EVASION_NONE;
03075 }
03076 //stop taunting
03077 TIMER_Set( self, "taunting", 0 );
03078 //stop gripping
03079 TIMER_Set( self, "gripping", -level.time );
03080 WP_ForcePowerStop( self, FP_GRIP );
03081 //stop draining
03082 TIMER_Set( self, "draining", -level.time );
03083 WP_ForcePowerStop( self, FP_DRAIN );
03084
03085 if ( dodgeAnim != -1 )
03086 {//dodged
03087 evasionType = EVASION_DODGE;
03088 NPC_SetAnim( self, SETANIM_BOTH, dodgeAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
03089 self->client->ps.weaponTime = self->client->ps.torsoTimer;
03090 //force them to stop moving in this case
03091 self->client->ps.pm_time = self->client->ps.torsoTimer;
03092 //FIXME: maybe make a sound? Like a grunt? EV_JUMP?
03093 self->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
03094 //dodged, not block
03095 if ( d_slowmodeath.integer > 5 && self->enemy && !self->enemy->s.number )
03096 {
03097 G_StartMatrixEffect( self );
03098 }
03099 }
03100 else
03101 {
03102 if ( duckChance )
03103 {
03104 if ( !Q_irand( 0, duckChance ) )
03105 {
03106 TIMER_Start( self, "duck", Q_irand( 500, 1500 ) );
03107 if ( evasionType == EVASION_PARRY )
03108 {
03109 evasionType = EVASION_DUCK_PARRY;
03110 }
03111 else
03112 {
03113 evasionType = EVASION_DUCK;
03114 }
03115 /*
03116 if ( d_JediAI.integer )
03117 {
03118 Com_Printf( "duck " );
03119 }
03120 */
03121 }
03122 }
03123
03124 if ( incoming )
03125 {
03126 self->client->ps.saberBlocked = WP_MissileBlockForBlock( self->client->ps.saberBlocked );
03127 }
03128
03129 }
03130 //if ( self->client->ps.saberBlocked != BLOCKED_NONE )
03131 {
03132 int parryReCalcTime = Jedi_ReCalcParryTime( self, evasionType );
03133 if ( self->client->ps.fd.forcePowerDebounce[FP_SABER_DEFENSE] < level.time + parryReCalcTime )
03134 {
03135 self->client->ps.fd.forcePowerDebounce[FP_SABER_DEFENSE] = level.time + parryReCalcTime;
03136 }
03137 }
03138 return evasionType;
03139 }
|
|
|
|
|
|
|
Definition at line 6170 of file NPC_AI_Jedi.c. References Boba_ChangeWeapon(), usercmd_s::buttons, CLASS_BOBAFETT, gentity_s::client, gNPC_t::confusionTime, entityShared_t::currentOrigin, gentity_s::enemy, gNPC_t::enemyCheckDebounceTime, playerState_s::fd, forcedata_s::forcePowersActive, G_SetEnemy(), gentity_t, gentity_s::health, Jedi_Ambush(), Jedi_CheckCloak(), Jedi_WaitingAmbush(), gentity_s::lastEnemy, level, clientPersistant_t::maxHealth, NPC, NPC_BSSniper_Default(), NPC_BSST_Patrol(), NPC_CheckEnemy(), gclient_s::NPC_class, NPCInfo, NULL, gclient_s::pers, gclient_s::ps, Q_irand(), qfalse, gentity_s::r, SCF_ALT_FIRE, gNPC_t::scriptFlags, level_locals_t::time, ucmd, and WP_DISRUPTOR. Referenced by NPC_BehaviorSet_Jedi().
06171 {
06172
06173 Jedi_CheckCloak();
06174 if( !NPC->enemy )
06175 {//don't have an enemy, look for one
06176 if ( NPC->client->NPC_class == CLASS_BOBAFETT )
06177 {
06178 NPC_BSST_Patrol();
06179 }
06180 else
06181 {
06182 Jedi_Patrol();
06183 }
06184 }
06185 else//if ( NPC->enemy )
06186 {//have an enemy
06187 if ( Jedi_WaitingAmbush( NPC ) )
06188 {//we were still waiting to drop down - must have had enemy set on me outside my AI
06189 Jedi_Ambush( NPC );
06190 }
06191 if ( NPC->client->NPC_class == CLASS_BOBAFETT )
06192 {
06193 if ( NPC->enemy->enemy != NPC && NPC->health == NPC->client->pers.maxHealth && DistanceSquared( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin )>(800*800) )
06194 {
06195 NPCInfo->scriptFlags |= SCF_ALT_FIRE;
06196 Boba_ChangeWeapon( WP_DISRUPTOR );
06197 NPC_BSSniper_Default();
06198 return;
06199 }
06200 }
06201 Jedi_Attack();
06202 //if we have multiple-jedi combat, probably need to keep checking (at certain debounce intervals) for a better (closer, more active) enemy and switch if needbe...
06203 if ( ((!ucmd.buttons&&!NPC->client->ps.fd.forcePowersActive)||(NPC->enemy&&NPC->enemy->health<=0)) && NPCInfo->enemyCheckDebounceTime < level.time )
06204 {//not doing anything (or walking toward a vanquished enemy - fixme: always taunt the player?), not using force powers and it's time to look again
06205 //FIXME: build a list of all local enemies (since we have to find best anyway) for other AI factors- like when to use group attacks, determine when to change tactics, when surrounded, when blocked by another in the enemy group, etc. Should we build this group list or let the enemies maintain their own list and we just access it?
06206 gentity_t *sav_enemy = NPC->enemy;//FIXME: what about NPC->lastEnemy?
06207 gentity_t *newEnemy;
06208
06209 NPC->enemy = NULL;
06210 newEnemy = NPC_CheckEnemy( NPCInfo->confusionTime < level.time, qfalse, qfalse );
06211 NPC->enemy = sav_enemy;
06212 if ( newEnemy && newEnemy != sav_enemy )
06213 {//picked up a new enemy!
06214 NPC->lastEnemy = NPC->enemy;
06215 G_SetEnemy( NPC, newEnemy );
06216 }
06217 NPCInfo->enemyCheckDebounceTime = level.time + Q_irand( 1000, 3000 );
06218 }
06219 }
06220 }
|
|
|
Definition at line 5758 of file NPC_AI_Jedi.c. References gNPC_t::aiFlags, BLOCKED_NONE, gNPC_t::blockedDest, BUTTON_ATTACK, usercmd_s::buttons, gentity_s::client, gentity_s::clipmask, CONTENTS_BODY, CONTENTS_BOTCLIP, entityShared_t::currentOrigin, gentity_s::enemy, ENTITYNUM_NONE, fabs(), g_entities, G_FreeEntity(), G_SetOrigin(), G_Spawn(), gentity_t, gNPC_t::goalEntity, gentity_s::health, Jedi_CanPullBackSaber(), NAV_CheckAhead(), NPC, NPC_BSFollowLeader(), NPC_ClearLOS4(), NPC_FaceEntity(), NPC_MoveToGoal(), NPC_UpdateAngles(), NPCAI_BLOCKED, NPCInfo, gclient_s::ps, qtrue, gentity_s::r, playerState_s::saberBlocked, playerState_s::saberEntityNum, playerState_s::saberInFlight, TIMER_Set(), TR_STATIONARY, trap_LinkEntity(), and ucmd. Referenced by NPC_BehaviorSet_Jedi().
05759 {
05760 NPC->client->ps.saberBlocked = BLOCKED_NONE;
05761 if ( !NPC->enemy )
05762 {
05763 //Com_Printf( "(%d) drop agg - no enemy (follow)\n", level.time );
05764 Jedi_AggressionErosion(-1);
05765 }
05766
05767 //did we drop our saber? If so, go after it!
05768 if ( NPC->client->ps.saberInFlight )
05769 {//saber is not in hand
05770 if ( NPC->client->ps.saberEntityNum < ENTITYNUM_NONE && NPC->client->ps.saberEntityNum > 0 )//player is 0
05771 {//
05772 if ( g_entities[NPC->client->ps.saberEntityNum].s.pos.trType == TR_STATIONARY )
05773 {//fell to the ground, try to pick it up...
05774 if ( Jedi_CanPullBackSaber( NPC ) )
05775 {
05776 //FIXME: if it's on the ground and we just pulled it back to us, should we
05777 // stand still for a bit to make sure it gets to us...?
05778 // otherwise we could end up running away from it while it's on its
05779 // way back to us and we could lose it again.
05780 NPC->client->ps.saberBlocked = BLOCKED_NONE;
05781 NPCInfo->goalEntity = &g_entities[NPC->client->ps.saberEntityNum];
05782 ucmd.buttons |= BUTTON_ATTACK;
05783 if ( NPC->enemy && NPC->enemy->health > 0 )
05784 {//get our saber back NOW!
05785 if ( !NPC_MoveToGoal( qtrue ) )//Jedi_Move( NPCInfo->goalEntity, qfalse );
05786 {//can't nav to it, try jumping to it
05787 NPC_FaceEntity( NPCInfo->goalEntity, qtrue );
05788 Jedi_TryJump( NPCInfo->goalEntity );
05789 }
05790 NPC_UpdateAngles( qtrue, qtrue );
05791 return;
05792 }
05793 }
05794 }
05795 }
05796 }
05797
05798 if ( NPCInfo->goalEntity )
05799 {
05800 trace_t trace;
05801
05802 if ( Jedi_Jumping( NPCInfo->goalEntity ) )
05803 {//in mid-jump
05804 return;
05805 }
05806
05807 if ( !NAV_CheckAhead( NPC, NPCInfo->goalEntity->r.currentOrigin, &trace, ( NPC->clipmask & ~CONTENTS_BODY )|CONTENTS_BOTCLIP ) )
05808 {//can't get straight to him
05809 if ( NPC_ClearLOS4( NPCInfo->goalEntity ) && NPC_FaceEntity( NPCInfo->goalEntity, qtrue ) )
05810 {//no line of sight
05811 if ( Jedi_TryJump( NPCInfo->goalEntity ) )
05812 {//started a jump
05813 return;
05814 }
05815 }
05816 }
05817 if ( NPCInfo->aiFlags & NPCAI_BLOCKED )
05818 {//try to jump to the blockedDest
05819 if ( fabs(NPCInfo->blockedDest[2]-NPC->r.currentOrigin[2]) > 64 )
05820 {
05821 gentity_t *tempGoal = G_Spawn();//ugh, this is NOT good...?
05822 G_SetOrigin( tempGoal, NPCInfo->blockedDest );
05823 trap_LinkEntity( tempGoal );
05824 TIMER_Set( NPC, "jumpChaseDebounce", -1 );
05825 if ( Jedi_TryJump( tempGoal ) )
05826 {//going to jump to the dest
05827 G_FreeEntity( tempGoal );
05828 return;
05829 }
05830 G_FreeEntity( tempGoal );
05831 }
05832 }
05833 }
05834 //try normal movement
05835 NPC_BSFollowLeader();
05836 }
|
|
|
Definition at line 854 of file NPC_AI_Sniper.c. References gentity_s::enemy, NPC, NPC_BSSniper_Attack(), and NPC_BSSniper_Patrol().
00855 {
00856 if( !NPC->enemy )
00857 {//don't have an enemy, look for one
00858 NPC_BSSniper_Patrol();
00859 }
00860 else//if ( NPC->enemy )
00861 {//have an enemy
00862 NPC_BSSniper_Attack();
00863 }
00864 }
|
|
|
Definition at line 1077 of file NPC_AI_Stormtrooper.c. References AEL_MINOR, AI_GetGroup(), entityState_s::angles, BOTH_STAND4, BUTTON_WALKING, usercmd_s::buttons, ChangeWeapon(), CLASS_IMPERIAL, CLASS_IMPWORKER, gentity_s::client, gNPC_t::confusionTime, gNPC_t::desiredPitch, gNPC_t::desiredYaw, usercmd_s::forwardmove, playerState_s::legsAnim, playerState_s::legsTimer, level, NPC, NPC_CheckAlertEvents(), NPC_CheckPlayerTeamStealth(), gclient_s::NPC_class, NPC_MoveToGoal(), NPC_SetAnim(), NPC_UpdateAngles(), NPCInfo, gclient_s::ps, Q_irand(), qfalse, qtrue, usercmd_s::rightmove, gentity_s::s, SCF_IGNORE_ALERTS, SCF_LOOK_FOR_ENEMIES, SCF_RUNNING, gNPC_t::scriptFlags, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, SETANIM_TORSO, level_locals_t::time, TIMER_Done(), playerState_s::torsoAnim, playerState_s::torsoTimer, ucmd, UpdateGoal(), usercmd_s::upmove, playerState_s::weapon, WEAPON_READY, playerState_s::weaponstate, and WP_NONE. Referenced by NPC_BSJedi_Default(), NPC_BSST_Attack(), and NPC_BSST_Default().
01078 {//FIXME: pick up on bodies of dead buddies?
01079
01080 //get group- mainly for group speech debouncing, but may use for group scouting/investigating AI, too
01081 AI_GetGroup( NPC );
01082
01083 if ( NPCInfo->confusionTime < level.time )
01084 {
01085 //Look for any enemies
01086 if ( NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES )
01087 {
01088 if ( NPC_CheckPlayerTeamStealth() )
01089 {
01090 //NPCInfo->behaviorState = BS_HUNT_AND_KILL;//should be auto now
01091 //NPC_AngerSound();
01092 NPC_UpdateAngles( qtrue, qtrue );
01093 return;
01094 }
01095 }
01096 }
01097
01098 if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) )
01099 {
01100 int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_MINOR );
01101
01102 //There is an event to look at
01103 if ( alertEvent >= 0 )
01104 {
01105 if ( NPC_ST_InvestigateEvent( alertEvent, qfalse ) )
01106 {//actually going to investigate it
01107 NPC_UpdateAngles( qtrue, qtrue );
01108 return;
01109 }
01110 }
01111 }
01112
01113 //If we have somewhere to go, then do that
01114 if ( UpdateGoal() )
01115 {
01116 ucmd.buttons |= BUTTON_WALKING;
01117 //ST_Move( NPCInfo->goalEntity );
01118 NPC_MoveToGoal( qtrue );
01119 }
01120 else// if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) )
01121 {
01122 if ( NPC->client->NPC_class != CLASS_IMPERIAL && NPC->client->NPC_class != CLASS_IMPWORKER )
01123 {//imperials do not look around
01124 if ( TIMER_Done( NPC, "enemyLastVisible" ) )
01125 {//nothing suspicious, look around
01126 if ( !Q_irand( 0, 30 ) )
01127 {
01128 NPCInfo->desiredYaw = NPC->s.angles[1] + Q_irand( -90, 90 );
01129 }
01130 if ( !Q_irand( 0, 30 ) )
01131 {
01132 NPCInfo->desiredPitch = Q_irand( -20, 20 );
01133 }
01134 }
01135 }
01136 }
01137
01138 NPC_UpdateAngles( qtrue, qtrue );
01139 //TEMP hack for Imperial stand anim
01140 if ( NPC->client->NPC_class == CLASS_IMPERIAL || NPC->client->NPC_class == CLASS_IMPWORKER )
01141 {//hack
01142 if ( ucmd.forwardmove || ucmd.rightmove || ucmd.upmove )
01143 {//moving
01144
01145 if( (NPC->client->ps.torsoTimer <= 0) || (NPC->client->ps.torsoAnim == BOTH_STAND4) )
01146 {
01147 if ( (ucmd.buttons&BUTTON_WALKING) && !(NPCInfo->scriptFlags&SCF_RUNNING) )
01148 {//not running, only set upper anim
01149 // No longer overrides scripted anims
01150 NPC_SetAnim( NPC, SETANIM_TORSO, BOTH_STAND4, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
01151 NPC->client->ps.torsoTimer = 200;
01152 }
01153 }
01154 }
01155 else
01156 {//standing still, set both torso and legs anim
01157 // No longer overrides scripted anims
01158 if( ( NPC->client->ps.torsoTimer <= 0 || (NPC->client->ps.torsoAnim == BOTH_STAND4) ) &&
01159 ( NPC->client->ps.legsTimer <= 0 || (NPC->client->ps.legsAnim == BOTH_STAND4) ) )
01160 {
01161 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_STAND4, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
01162 NPC->client->ps.torsoTimer = NPC->client->ps.legsTimer = 200;
01163 }
01164 }
01165 //FIXME: this is a disgusting hack that is supposed to make the Imperials start with their weapon holstered- need a better way
01166 if ( NPC->client->ps.weapon != WP_NONE )
01167 {
01168 ChangeWeapon( NPC, WP_NONE );
01169 NPC->client->ps.weapon = WP_NONE;
01170 NPC->client->ps.weaponstate = WEAPON_READY;
01171 /*
01172 if ( NPC->weaponModel[0] > 0 )
01173 {
01174 gi.G2API_RemoveGhoul2Model( NPC->ghoul2, NPC->weaponModel[0] );
01175 NPC->weaponModel[0] = -1;
01176 }
01177 */
01178 //rwwFIXMEFIXME: Do this?
01179 }
01180 }
01181 }
|
|
|
Referenced by NPC_CheckPlayerTeamStealth(). |
|
|
Definition at line 1611 of file NPC_utils.c.
01612 {
01613 if ( !self->client )
01614 {
01615 return;
01616 }
01617
01618 if ( (self->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
01619 {//lookTarget is set by and to the monster that's holding you, no other operations can change that
01620 return;
01621 }
01622
01623 self->client->renderInfo.lookTarget = ENTITYNUM_NONE;//ENTITYNUM_WORLD;
01624 self->client->renderInfo.lookTargetClearTime = 0;
01625 }
|
|
||||||||||||||||
|
Definition at line 5358 of file NPC_AI_Jedi.c. References entityShared_t::absmin, gNPCstats_e::aggression, AngleVectors(), BOTH_CEILING_CLING, BOTH_CEILING_DROP, CLASS_DESANN, gentity_s::client, Com_Printf(), d_JediAI, DotProduct, gNPC_t::enemyCheckDebounceTime, EV_PUSHED1, EV_PUSHED3, renderInfo_s::eyePoint, playerState_s::fd, FORCE_LEVEL_1, FORCE_LEVEL_3, forcedata_s::forcePowerDebounce, FP_GRIP, FP_SABER_DEFENSE, G_AddVoiceEvent(), g_spskill, gentity_t, gPainPoint, gentity_s::health, vmCvar_t::integer, Jedi_WaitingAmbush(), playerState_s::legsAnim, level, gclient_s::noclip, gentity_s::NPC, gclient_s::NPC_class, NPC_Pain(), NPC_SetAnim(), gentity_s::NPC_type, NULL, gclient_s::ps, Q_irand(), Q_stricmp(), qfalse, gentity_s::r, gNPC_t::rank, RANK_LT_JG, gclient_s::renderInfo, gentity_s::s, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, SETANIM_LEGS, SETANIM_TORSO, gNPC_t::stats, level_locals_t::time, TIMER_Set(), playerState_s::torsoAnim, vec3_t, VectorCopy, VectorSubtract, playerState_s::viewangles, entityState_s::weapon, WP_ForcePowerStop(), and WP_SABER. Referenced by NPC_PainFunc().
05359 {
05360 gentity_t *other = attacker;
05361 vec3_t point;
05362
05363 VectorCopy(gPainPoint, point);
05364
05365 //FIXME: base the actual aggression add/subtract on health?
05366 //FIXME: don't do this more than once per frame?
05367 //FIXME: when take pain, stop force gripping....?
05368 if ( other->s.weapon == WP_SABER )
05369 {//back off
05370 TIMER_Set( self, "parryTime", -1 );
05371 if ( self->client->NPC_class == CLASS_DESANN || !Q_stricmp("Yoda",self->NPC_type) )
05372 {//less for Desann
05373 self->client->ps.fd.forcePowerDebounce[FP_SABER_DEFENSE] = level.time + (3-g_spskill.integer)*50;
05374 }
05375 else if ( self->NPC->rank >= RANK_LT_JG )
05376 {
05377 self->client->ps.fd.forcePowerDebounce[FP_SABER_DEFENSE] = level.time + (3-g_spskill.integer)*100;//300
05378 }
05379 else
05380 {
05381 self->client->ps.fd.forcePowerDebounce[FP_SABER_DEFENSE] = level.time + (3-g_spskill.integer)*200;//500
05382 }
05383 if ( !Q_irand( 0, 3 ) )
05384 {//ouch... maybe switch up which saber power level we're using
05385 Jedi_AdjustSaberAnimLevel( self, Q_irand( FORCE_LEVEL_1, FORCE_LEVEL_3 ) );
05386 }
05387 if ( !Q_irand( 0, 1 ) )//damage > 20 || self->health < 40 ||
05388 {
05389 //Com_Printf( "(%d) drop agg - hit by saber\n", level.time );
05390 Jedi_Aggression( self, -1 );
05391 }
05392 if ( d_JediAI.integer )
05393 {
05394 Com_Printf( "(%d) PAIN: agg %d, no parry until %d\n", level.time, self->NPC->stats.aggression, level.time+500 );
05395 }
05396 //for testing only
05397 // Figure out what quadrant the hit was in.
05398 if ( d_JediAI.integer )
05399 {
05400 vec3_t diff, fwdangles, right;
05401 float rightdot, zdiff;
05402
05403 VectorSubtract( point, self->client->renderInfo.eyePoint, diff );
05404 diff[2] = 0;
05405 fwdangles[1] = self->client->ps.viewangles[1];
05406 AngleVectors( fwdangles, NULL, right, NULL );
05407 rightdot = DotProduct(right, diff);
05408 zdiff = point[2] - self->client->renderInfo.eyePoint[2];
05409
05410 Com_Printf( "(%d) saber hit at height %4.2f, zdiff: %4.2f, rightdot: %4.2f\n", level.time, point[2]-self->r.absmin[2],zdiff,rightdot);
05411 }
05412 }
05413 else
05414 {//attack
05415 //Com_Printf( "(%d) raise agg - hit by ranged\n", level.time );
05416 Jedi_Aggression( self, 1 );
05417 }
05418
05419 self->NPC->enemyCheckDebounceTime = 0;
05420
05421 WP_ForcePowerStop( self, FP_GRIP );
05422
05423 //NPC_Pain( self, inflictor, other, point, damage, mod );
05424 NPC_Pain(self, attacker, damage);
05425
05426 if ( !damage && self->health > 0 )
05427 {//FIXME: better way to know I was pushed
05428 G_AddVoiceEvent( self, Q_irand(EV_PUSHED1, EV_PUSHED3), 2000 );
05429 }
05430
05431 //drop me from the ceiling if I'm on it
05432 if ( Jedi_WaitingAmbush( self ) )
05433 {
05434 self->client->noclip = qfalse;
05435 }
05436 if ( self->client->ps.legsAnim == BOTH_CEILING_CLING )
05437 {
05438 NPC_SetAnim( self, SETANIM_LEGS, BOTH_CEILING_DROP, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
05439 }
05440 if ( self->client->ps.torsoAnim == BOTH_CEILING_CLING )
05441 {
05442 NPC_SetAnim( self, SETANIM_TORSO, BOTH_CEILING_DROP, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
05443 }
05444 }
|
|
|
Definition at line 163 of file NPC_AI_Jedi.c. References CLASS_DESANN, CLASS_TAVION, gentity_s::client, EV_CONFUSE1, EV_CONFUSE3, EV_GLOAT1, EV_GLOAT3, EV_TAUNT1, EV_TAUNT3, G_AddVoiceEvent(), gentity_t, gentity_s::health, gclient_s::NPC_class, and Q_irand(). Referenced by ForceTelepathyCheckDirectNPCTarget().
00164 {
00165 if ( self->health > 0 )
00166 {
00167 if ( self->client && ( self->client->NPC_class == CLASS_TAVION || self->client->NPC_class == CLASS_DESANN ) )
00168 {
00169 G_AddVoiceEvent( self, Q_irand( EV_CONFUSE1, EV_CONFUSE3 ), 2000 );
00170 }
00171 else if ( Q_irand( 0, 1 ) )
00172 {
00173 G_AddVoiceEvent( self, Q_irand( EV_TAUNT1, EV_TAUNT3 ), 2000 );
00174 }
00175 else
00176 {
00177 G_AddVoiceEvent( self, Q_irand( EV_GLOAT1, EV_GLOAT3 ), 2000 );
00178 }
00179 }
00180 }
|
|
||||||||||||
|
Definition at line 914 of file NPC_AI_Jedi.c. References gNPCstats_e::aggression, ceil(), entityShared_t::currentOrigin, gentity_t, gentity_s::health, gentity_s::NPC, Q_irand(), gentity_s::r, gentity_s::s, gNPC_t::stats, TIMER_Set(), entityState_s::weapon, WP_BLASTER, and WP_SABER. Referenced by G_SetEnemy().
00915 {
00916 float healthAggression;
00917 float weaponAggression;
00918 int newAggression;
00919
00920 switch( enemy->s.weapon )
00921 {
00922 case WP_SABER:
00923 healthAggression = (float)self->health/200.0f*6.0f;
00924 weaponAggression = 7;//go after him
00925 break;
00926 case WP_BLASTER:
00927 if ( DistanceSquared( self->r.currentOrigin, enemy->r.currentOrigin ) < 65536 )//256 squared
00928 {
00929 healthAggression = (float)self->health/200.0f*8.0f;
00930 weaponAggression = 8;//go after him
00931 }
00932 else
00933 {
00934 healthAggression = 8.0f - ((float)self->health/200.0f*8.0f);
00935 weaponAggression = 2;//hang back for a second
00936 }
00937 break;
00938 default:
00939 healthAggression = (float)self->health/200.0f*8.0f;
00940 weaponAggression = 6;//approach
00941 break;
00942 }
00943 //Average these with current aggression
00944 newAggression = ceil( (healthAggression + weaponAggression + (float)self->NPC->stats.aggression )/3.0f);
00945 //Com_Printf( "(%d) new agg %d - new enemy\n", level.time, newAggression );
00946 Jedi_Aggression( self, newAggression - self->NPC->stats.aggression );
00947
00948 //don't taunt right away
00949 TIMER_Set( self, "chatter", Q_irand( 4000, 7000 ) );
00950 }
|
|
||||||||||||||||
|
Definition at line 1079 of file NPC_AI_Jedi.c. References trace_t::allsolid, AngleVectors(), gentity_s::client, gentity_s::clipmask, CONTENTS_BOTCLIP, entityShared_t::currentOrigin, trace_t::endpos, gentity_s::enemy, trace_t::entityNum, ENTITYNUM_NONE, playerState_s::fd, forcedata_s::forceJumpCharge, usercmd_s::forwardmove, trace_t::fraction, gNPC_t::goalEntity, playerState_s::groundEntityNum, entityShared_t::maxs, entityShared_t::mins, playerState_s::moveDir, NPC, NPCInfo, NULL, entityState_s::number, PITCH, gclient_s::ps, qboolean, qfalse, qtrue, gentity_s::r, usercmd_s::rightmove, ROLL, gentity_s::s, trace_t::startsolid, STEPSIZE, trap_Trace(), ucmd, usercmd_s::upmove, vec3_t, VectorClear, VectorCopy, VectorMA, VectorScale, playerState_s::viewangles, and YAW. Referenced by NPC_BSFollowLeader().
01080 {
01081 vec3_t forward, right, testPos, angles, mins;
01082 trace_t trace;
01083 float fwdDist, rtDist;
01084 float bottom_max = -STEPSIZE*4 - 1;
01085
01086 if ( !forwardmove && !rightmove )
01087 {//not even moving
01088 //Com_Printf( "%d skipping walk-cliff check (not moving)\n", level.time );
01089 return qtrue;
01090 }
01091
01092 if ( ucmd.upmove > 0 || NPC->client->ps.fd.forceJumpCharge )
01093 {//Going to jump
01094 //Com_Printf( "%d skipping walk-cliff check (going to jump)\n", level.time );
01095 return qtrue;
01096 }
01097
01098 if ( NPC->client->ps.groundEntityNum == ENTITYNUM_NONE )
01099 {//in the air
01100 //Com_Printf( "%d skipping walk-cliff check (in air)\n", level.time );
01101 return qtrue;
01102 }
01103 /*
01104 if ( fabs( AngleDelta( NPC->r.currentAngles[YAW], NPCInfo->desiredYaw ) ) < 5.0 )//!ucmd.angles[YAW] )
01105 {//Not turning much, don't do this
01106 //NOTE: Should this not happen only if you're not turning AT ALL?
01107 // You could be turning slowly but moving fast, so that would
01108 // still let you walk right off a cliff...
01109 //NOTE: Or maybe it is a good idea to ALWAYS do this, regardless
01110 // of whether ot not we're turning? But why would we be walking
01111 // straight into a wall or off a cliff unless we really wanted to?
01112 return;
01113 }
01114 */
01115
01116 //FIXME: to really do this right, we'd have to actually do a pmove to predict where we're
01117 //going to be... maybe this should be a flag and pmove handles it and sets a flag so AI knows
01118 //NEXT frame? Or just incorporate current velocity, runspeed and possibly friction?
01119 VectorCopy( NPC->r.mins, mins );
01120 mins[2] += STEPSIZE;
01121 angles[PITCH] = angles[ROLL] = 0;
01122 angles[YAW] = NPC->client->ps.viewangles[YAW];//Add ucmd.angles[YAW]?
01123 AngleVectors( angles, forward, right, NULL );
01124 fwdDist = ((float)forwardmove)/2.0f;
01125 rtDist = ((float)rightmove)/2.0f;
01126 VectorMA( NPC->r.currentOrigin, fwdDist, forward, testPos );
01127 VectorMA( testPos, rtDist, right, testPos );
01128 trap_Trace( &trace, NPC->r.currentOrigin, mins, NPC->r.maxs, testPos, NPC->s.number, NPC->clipmask|CONTENTS_BOTCLIP );
01129 if ( trace.allsolid || trace.startsolid )
01130 {//hmm, trace started inside this brush... how do we decide if we should continue?
01131 //FIXME: what do we do if we start INSIDE a CONTENTS_BOTCLIP? Try the trace again without that in the clipmask?
01132 if ( reset )
01133 {
01134 trace.fraction = 1.0f;
01135 }
01136 VectorCopy( testPos, trace.endpos );
01137 //return qtrue;
01138 }
01139 if ( trace.fraction < 0.6 )
01140 {//Going to bump into something very close, don't move, just turn
01141 if ( (NPC->enemy && trace.entityNum == NPC->enemy->s.number) || (NPCInfo->goalEntity && trace.entityNum == NPCInfo->goalEntity->s.number) )
01142 {//okay to bump into enemy or goal
01143 //Com_Printf( "%d bump into enemy/goal okay\n", level.time );
01144 return qtrue;
01145 }
01146 else if ( reset )
01147 {//actually want to screw with the ucmd
01148 //Com_Printf( "%d avoiding walk into wall (entnum %d)\n", level.time, trace.entityNum );
01149 ucmd.forwardmove = 0;
01150 ucmd.rightmove = 0;
01151 VectorClear( NPC->client->ps.moveDir );
01152 }
01153 return qfalse;
01154 }
01155
01156 if ( NPCInfo->goalEntity )
01157 {
01158 if ( NPCInfo->goalEntity->r.currentOrigin[2] < NPC->r.currentOrigin[2] )
01159 {//goal is below me, okay to step off at least that far plus stepheight
01160 bottom_max += NPCInfo->goalEntity->r.currentOrigin[2] - NPC->r.currentOrigin[2];
01161 }
01162 }
01163 VectorCopy( trace.endpos, testPos );
01164 testPos[2] += bottom_max;
01165
01166 trap_Trace( &trace, trace.endpos, mins, NPC->r.maxs, testPos, NPC->s.number, NPC->clipmask );
01167
01168 //FIXME:Should we try to see if we can still get to our goal using the waypoint network from this trace.endpos?
01169 //OR: just put NPC clip brushes on these edges (still fall through when die)
01170
01171 if ( trace.allsolid || trace.startsolid )
01172 {//Not going off a cliff
01173 //Com_Printf( "%d walk off cliff okay (droptrace in solid)\n", level.time );
01174 return qtrue;
01175 }
01176
01177 if ( trace.fraction < 1.0 )
01178 {//Not going off a cliff
01179 //FIXME: what if plane.normal is sloped? We'll slide off, not land... plus this doesn't account for slide-movement...
01180 //Com_Printf( "%d walk off cliff okay will hit entnum %d at dropdist of %4.2f\n", level.time, trace.entityNum, (trace.fraction*bottom_max) );
01181 return qtrue;
01182 }
01183
01184 //going to fall at least bottom_max, don't move, just turn... is this bad, though? What if we want them to drop off?
01185 if ( reset )
01186 {//actually want to screw with the ucmd
01187 //Com_Printf( "%d avoiding walk off cliff\n", level.time );
01188 ucmd.forwardmove *= -1.0;//= 0;
01189 ucmd.rightmove *= -1.0;//= 0;
01190 VectorScale( NPC->client->ps.moveDir, -1, NPC->client->ps.moveDir );
01191 }
01192 return qfalse;
01193 }
|
|
||||||||||||||||
|
Definition at line 1632 of file NPC_utils.c.
01633 {
01634 if ( !self->client )
01635 {
01636 return;
01637 }
01638
01639 if ( (self->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
01640 {//lookTarget is set by and to the monster that's holding you, no other operations can change that
01641 return;
01642 }
01643
01644 self->client->renderInfo.lookTarget = entNum;
01645 self->client->renderInfo.lookTargetClearTime = clearTime;
01646 }
|
|
|
Definition at line 103 of file NPC_AI_Jedi.c. References AMMO_FORCE, BG_FindItemForAmmo(), G_SoundIndex(), and RegisterItem(). Referenced by NPC_SpawnType(), and SP_NPC_ShadowTrooper().
00104 {
00105 RegisterItem( BG_FindItemForAmmo( AMMO_FORCE ) );
00106 G_SoundIndex( "sound/chars/shadowtrooper/cloak.wav" );
00107 G_SoundIndex( "sound/chars/shadowtrooper/decloak.wav" );
00108 }
|
|
|
Definition at line 1042 of file NPC_utils.c.
01043 {
01044 int i = 0;
01045 gentity_t *pEnt;
01046
01047 while (i < MAX_CLIENTS)
01048 {
01049 pEnt = &g_entities[i];
01050
01051 if (pEnt && pEnt->inuse && pEnt->client && pEnt->client->sess.sessionTeam != TEAM_SPECTATOR &&
01052 !(pEnt->client->ps.pm_flags & PMF_FOLLOW) && pEnt->s.weapon != WP_NONE)
01053 {
01054 if (trap_InPVS(ent->r.currentOrigin, pEnt->r.currentOrigin))
01055 {
01056 if (InFOV( ent, pEnt, 30, 30 ))
01057 { //I'm in a 30 fov or so cone from this player.. that's enough I guess.
01058 return qtrue;
01059 }
01060 }
01061 }
01062
01063 i++;
01064 }
01065
01066 return qfalse;
01067 }
|
|
||||||||||||||||||||
|
Definition at line 661 of file NPC_reactions.c.
00662 {
00663 if ( !self->client )
00664 {
00665 return;
00666 }
00667
00668 if ( (self->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
00669 {//lookTarget is set by and to the monster that's holding you, no other operations can change that
00670 return;
00671 }
00672
00673 if ( !minLookTime )
00674 {
00675 minLookTime = 1000;
00676 }
00677
00678 if ( !maxLookTime )
00679 {
00680 maxLookTime = 1000;
00681 }
00682
00683 if ( !NPC_CheckLookTarget( self ) )
00684 {//Not already looking at something else
00685 //Look at him for 1 to 3 seconds
00686 NPC_SetLookTarget( self, lookEntNum, level.time + Q_irand( minLookTime, maxLookTime ) );
00687 }
00688 }
|
|
|
Definition at line 1216 of file bg_panimate.c.
01217 {
01218 switch ( (ps->legsAnim) )
01219 {
01220 case BOTH_KNOCKDOWN1:
01221 case BOTH_KNOCKDOWN2:
01222 case BOTH_KNOCKDOWN3:
01223 case BOTH_KNOCKDOWN4:
01224 case BOTH_KNOCKDOWN5:
01225 return qtrue;
01226 break;
01227 case BOTH_GETUP1:
01228 case BOTH_GETUP2:
01229 case BOTH_GETUP3:
01230 case BOTH_GETUP4:
01231 case BOTH_GETUP5:
01232 case BOTH_FORCE_GETUP_F1:
01233 case BOTH_FORCE_GETUP_F2:
01234 case BOTH_FORCE_GETUP_B1:
01235 case BOTH_FORCE_GETUP_B2:
01236 case BOTH_FORCE_GETUP_B3:
01237 case BOTH_FORCE_GETUP_B4:
01238 case BOTH_FORCE_GETUP_B5:
01239 case BOTH_GETUP_BROLL_B:
01240 case BOTH_GETUP_BROLL_F:
01241 case BOTH_GETUP_BROLL_L:
01242 case BOTH_GETUP_BROLL_R:
01243 case BOTH_GETUP_FROLL_B:
01244 case BOTH_GETUP_FROLL_F:
01245 case BOTH_GETUP_FROLL_L:
01246 case BOTH_GETUP_FROLL_R:
01247 if ( ps->legsTimer )
01248 {
01249 return qtrue;
01250 }
01251 break;
01252 }
01253 return qfalse;
01254 }
|
|
|
Definition at line 4636 of file bg_pmove.c.
04637 {
04638 switch ( anim )
04639 {
04640 case BOTH_ROLL_F: //# Roll forward
04641 case BOTH_ROLL_B: //# Roll backward
04642 case BOTH_ROLL_L: //# Roll left
04643 case BOTH_ROLL_R: //# Roll right
04644 return qtrue;
04645 break;
04646 }
04647 return qfalse;
04648 }
|
|
|
Definition at line 700 of file bg_saber.c.
|
|
|
Definition at line 1580 of file bg_saber.c.
|
|
|
Definition at line 1148 of file bg_panimate.c.
|
|
|
Definition at line 1166 of file bg_panimate.c. References LS_K1_BL, LS_K1_T_, qboolean, qfalse, and qtrue. Referenced by PM_SetSaberMove().
|
|
|
Definition at line 1157 of file bg_panimate.c. References LS_PARRY_LL, LS_PARRY_UP, qboolean, qfalse, and qtrue. Referenced by PM_SetSaberMove().
01158 {
01159 if ( move >= LS_PARRY_UP && move <= LS_PARRY_LL )
01160 {
01161 return qtrue;
01162 }
01163 return qfalse;
01164 }
|
|
|
Definition at line 1184 of file bg_panimate.c. References LS_S_T2B, LS_S_TL2BR, qboolean, qfalse, and qtrue. Referenced by BG_SaberInTransitionAny(), ClientThink_real(), Jedi_CheckFlipEvasions(), Jedi_SaberBlockGo(), and PM_SaberMoveOkayForKata().
01185 {
01186 if ( move >= LS_S_TL2BR && move <= LS_S_T2B )
01187 {
01188 return qtrue;
01189 }
01190 return qfalse;
01191 }
|
|
||||||||||||||||||||||||||||
|
Definition at line 2131 of file g_utils.c. References DotProduct, fabs(), G_FindClosestPointOnLineSegment(), Q3_INFINITE, qboolean, qfalse, qtrue, vec3_t, VectorCopy, VectorMA, and VectorSubtract.
02132 {
02133 float current_dist, new_dist;
02134 vec3_t new_pnt;
02135 //start1, end1 : the first segment
02136 //start2, end2 : the second segment
02137
02138 //output, one point on each segment, the closest two points on the segments.
02139
02140 //compute some temporaries:
02141 //vec start_dif = start2 - start1
02142 vec3_t start_dif;
02143 vec3_t v1;
02144 vec3_t v2;
02145 float v1v1, v2v2, v1v2;
02146 float denom;
02147
02148 VectorSubtract( start2, start1, start_dif );
02149 //vec v1 = end1 - start1
02150 VectorSubtract( end1, start1, v1 );
02151 //vec v2 = end2 - start2
02152 VectorSubtract( end2, start2, v2 );
02153 //
02154 v1v1 = DotProduct( v1, v1 );
02155 v2v2 = DotProduct( v2, v2 );
02156 v1v2 = DotProduct( v1, v2 );
02157
02158 //the main computation
02159
02160 denom = (v1v2 * v1v2) - (v1v1 * v2v2);
02161
02162 //if denom is small, then skip all this and jump to the section marked below
02163 if ( fabs(denom) > 0.001f )
02164 {
02165 float s = -( (v2v2*DotProduct( v1, start_dif )) - (v1v2*DotProduct( v2, start_dif )) ) / denom;
02166 float t = ( (v1v1*DotProduct( v2, start_dif )) - (v1v2*DotProduct( v1, start_dif )) ) / denom;
02167 qboolean done = qtrue;
02168
02169 if ( s < 0 )
02170 {
02171 done = qfalse;
02172 s = 0;// and see note below
02173 }
02174
02175 if ( s > 1 )
02176 {
02177 done = qfalse;
02178 s = 1;// and see note below
02179 }
02180
02181 if ( t < 0 )
02182 {
02183 done = qfalse;
02184 t = 0;// and see note below
02185 }
02186
02187 if ( t > 1 )
02188 {
02189 done = qfalse;
02190 t = 1;// and see note below
02191 }
02192
02193 //vec close_pnt1 = start1 + s * v1
02194 VectorMA( start1, s, v1, close_pnt1 );
02195 //vec close_pnt2 = start2 + t * v2
02196 VectorMA( start2, t, v2, close_pnt2 );
02197
02198 current_dist = Distance( close_pnt1, close_pnt2 );
02199 //now, if none of those if's fired, you are done.
02200 if ( done )
02201 {
02202 return current_dist;
02203 }
02204 //If they did fire, then we need to do some additional tests.
02205
02206 //What we are gonna do is see if we can find a shorter distance than the above
02207 //involving the endpoints.
02208 }
02209 else
02210 {
02211 //******start here for paralell lines with current_dist = infinity****
02212 current_dist = Q3_INFINITE;
02213 }
02214
02215 //test 2 close_pnts first
02216 /*
02217 G_FindClosestPointOnLineSegment( start1, end1, close_pnt2, new_pnt );
02218 new_dist = Distance( close_pnt2, new_pnt );
02219 if ( new_dist < current_dist )
02220 {//then update close_pnt1 close_pnt2 and current_dist
02221 VectorCopy( new_pnt, close_pnt1 );
02222 VectorCopy( close_pnt2, close_pnt2 );
02223 current_dist = new_dist;
02224 }
02225
02226 G_FindClosestPointOnLineSegment( start2, end2, close_pnt1, new_pnt );
02227 new_dist = Distance( close_pnt1, new_pnt );
02228 if ( new_dist < current_dist )
02229 {//then update close_pnt1 close_pnt2 and current_dist
02230 VectorCopy( close_pnt1, close_pnt1 );
02231 VectorCopy( new_pnt, close_pnt2 );
02232 current_dist = new_dist;
02233 }
02234 */
02235 //test all the endpoints
02236 new_dist = Distance( start1, start2 );
02237 if ( new_dist < current_dist )
02238 {//then update close_pnt1 close_pnt2 and current_dist
02239 VectorCopy( start1, close_pnt1 );
02240 VectorCopy( start2, close_pnt2 );
02241 current_dist = new_dist;
02242 }
02243
02244 new_dist = Distance( start1, end2 );
02245 if ( new_dist < current_dist )
02246 {//then update close_pnt1 close_pnt2 and current_dist
02247 VectorCopy( start1, close_pnt1 );
02248 VectorCopy( end2, close_pnt2 );
02249 current_dist = new_dist;
02250 }
02251
02252 new_dist = Distance( end1, start2 );
02253 if ( new_dist < current_dist )
02254 {//then update close_pnt1 close_pnt2 and current_dist
02255 VectorCopy( end1, close_pnt1 );
02256 VectorCopy( start2, close_pnt2 );
02257 current_dist = new_dist;
02258 }
02259
02260 new_dist = Distance( end1, end2 );
02261 if ( new_dist < current_dist )
02262 {//then update close_pnt1 close_pnt2 and current_dist
02263 VectorCopy( end1, close_pnt1 );
02264 VectorCopy( end2, close_pnt2 );
02265 current_dist = new_dist;
02266 }
02267
02268 //Then we have 4 more point / segment tests
02269
02270 G_FindClosestPointOnLineSegment( start2, end2, start1, new_pnt );
02271 new_dist = Distance( start1, new_pnt );
02272 if ( new_dist < current_dist )
02273 {//then update close_pnt1 close_pnt2 and current_dist
02274 VectorCopy( start1, close_pnt1 );
02275 VectorCopy( new_pnt, close_pnt2 );
02276 current_dist = new_dist;
02277 }
02278
02279 G_FindClosestPointOnLineSegment( start2, end2, end1, new_pnt );
02280 new_dist = Distance( end1, new_pnt );
02281 if ( new_dist < current_dist )
02282 {//then update close_pnt1 close_pnt2 and current_dist
02283 VectorCopy( end1, close_pnt1 );
02284 VectorCopy( new_pnt, close_pnt2 );
02285 current_dist = new_dist;
02286 }
02287
02288 G_FindClosestPointOnLineSegment( start1, end1, start2, new_pnt );
02289 new_dist = Distance( start2, new_pnt );
02290 if ( new_dist < current_dist )
02291 {//then update close_pnt1 close_pnt2 and current_dist
02292 VectorCopy( new_pnt, close_pnt1 );
02293 VectorCopy( start2, close_pnt2 );
02294 current_dist = new_dist;
02295 }
02296
02297 G_FindClosestPointOnLineSegment( start1, end1, end2, new_pnt );
02298 new_dist = Distance( end2, new_pnt );
02299 if ( new_dist < current_dist )
02300 {//then update close_pnt1 close_pnt2 and current_dist
02301 VectorCopy( new_pnt, close_pnt1 );
02302 VectorCopy( end2, close_pnt2 );
02303 current_dist = new_dist;
02304 }
02305
02306 return current_dist;
02307 }
|
|
|
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 }
|
|
||||||||||||
|
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 }
|
|
||||||||||||||||
|
Definition at line 774 of file w_force.c. References gentity_s::client, playerState_s::fd, forcedata_s::forcePower, forcedata_s::forcePowerLevel, forcePowerNeeded, forcePowers_t, forcedata_s::forcePowersActive, FP_DRAIN, FP_LEVITATION, FP_LIGHTNING, gentity_t, gclient_s::ps, qboolean, qfalse, and qtrue. Referenced by WP_DoSpecificPower(), WP_ForcePowerStart(), and WP_ForcePowerUsable().
00775 {
00776 int drain = overrideAmt ? overrideAmt :
00777 forcePowerNeeded[self->client->ps.fd.forcePowerLevel[forcePower]][forcePower];
00778
00779 if (self->client->ps.fd.forcePowersActive & (1 << forcePower))
00780 { //we're probably going to deactivate it..
00781 return qtrue;
00782 }
00783 if ( forcePower == FP_LEVITATION )
00784 {
00785 return qtrue;
00786 }
00787 if ( !drain )
00788 {
00789 return qtrue;
00790 }
00791 if ((forcePower == FP_DRAIN || forcePower == FP_LIGHTNING) &&
00792 self->client->ps.fd.forcePower >= 25)
00793 { //it's ok then, drain/lightning are actually duration
00794 return qtrue;
00795 }
00796 if ( self->client->ps.fd.forcePower < drain )
00797 {
00798 return qfalse;
00799 }
00800 return qtrue;
00801 }
|
|
||||||||||||
|
||||||||||||||||
|
|
|
||||||||||||||||
|
Definition at line 2377 of file w_force.c. References AngleVectors(), CHAN_VOICE, gentity_s::client, playerState_s::fd, FJ_BACKWARD, FJ_FORWARD, FJ_LEFT, FJ_RIGHT, FJ_UP, forcedata_s::forceJumpCharge, usercmd_s::forwardmove, G_MuteSound(), G_PreDefSound(), gentity_t, JUMP_VELOCITY, forcedata_s::killSoundEntIndex, NULL, playerState_s::origin, PDSOUND_FORCEJUMP, gclient_s::ps, usercmd_s::rightmove, TRACK_CHANNEL_1, ucmd, usercmd_t, vec3_t, VectorCopy, VectorMA, playerState_s::velocity, and playerState_s::viewangles. Referenced by ForceJump().
02378 {
02379 float pushFwd = 0, pushRt = 0;
02380 vec3_t view, forward, right;
02381 VectorCopy( self->client->ps.viewangles, view );
02382 view[0] = 0;
02383 AngleVectors( view, forward, right, NULL );
02384 if ( ucmd->forwardmove && ucmd->rightmove )
02385 {
02386 if ( ucmd->forwardmove > 0 )
02387 {
02388 pushFwd = 50;
02389 }
02390 else
02391 {
02392 pushFwd = -50;
02393 }
02394 if ( ucmd->rightmove > 0 )
02395 {
02396 pushRt = 50;
02397 }
02398 else
02399 {
02400 pushRt = -50;
02401 }
02402 }
02403 else if ( ucmd->forwardmove || ucmd->rightmove )
02404 {
02405 if ( ucmd->forwardmove > 0 )
02406 {
02407 pushFwd = 100;
02408 }
02409 else if ( ucmd->forwardmove < 0 )
02410 {
02411 pushFwd = -100;
02412 }
02413 else if ( ucmd->rightmove > 0 )
02414 {
02415 pushRt = 100;
02416 }
02417 else if ( ucmd->rightmove < 0 )
02418 {
02419 pushRt = -100;
02420 }
02421 }
02422
02423 G_MuteSound(self->client->ps.fd.killSoundEntIndex[TRACK_CHANNEL_1-50], CHAN_VOICE);
02424
02425 G_PreDefSound(self->client->ps.origin, PDSOUND_FORCEJUMP);
02426
02427 if (self->client->ps.fd.forceJumpCharge < JUMP_VELOCITY+40)
02428 { //give him at least a tiny boost from just a tap
02429 self->client->ps.fd.forceJumpCharge = JUMP_VELOCITY+400;
02430 }
02431
02432 if (self->client->ps.velocity[2] < -30)
02433 { //so that we can get a good boost when force jumping in a fall
02434 self->client->ps.velocity[2] = -30;
02435 }
02436
02437 VectorMA( self->client->ps.velocity, pushFwd, forward, jumpVel );
02438 VectorMA( self->client->ps.velocity, pushRt, right, jumpVel );
02439 jumpVel[2] += self->client->ps.fd.forceJumpCharge;
02440 if ( pushFwd > 0 && self->client->ps.fd.forceJumpCharge > 200 )
02441 {
02442 return FJ_FORWARD;
02443 }
02444 else if ( pushFwd < 0 && self->client->ps.fd.forceJumpCharge > 200 )
02445 {
02446 return FJ_BACKWARD;
02447 }
02448 else if ( pushRt > 0 && self->client->ps.fd.forceJumpCharge > 200 )
02449 {
02450 return FJ_RIGHT;
02451 }
02452 else if ( pushRt < 0 && self->client->ps.fd.forceJumpCharge > 200 )
02453 {
02454 return FJ_LEFT;
02455 }
02456 else
02457 {
02458 return FJ_UP;
02459 }
02460 }
|
|
|
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 }
|
|
||||||||||||||||
|
Definition at line 203 of file NPC_AI_Jedi.c. References atof(), BG_CrouchAnim(), BG_FlippingAnim(), BG_SpinningSaberAnim(), BOTH_RESISTPUSH, CLASS_DESANN, CLASS_LUKE, gentity_s::client, ENTITYNUM_NONE, playerState_s::fd, floor(), FORCE_LEVEL_3, forcedata_s::forcePowerLevel, forcedata_s::forcePowersActive, FP_PULL, FP_PUSH, FP_SPEED, gentity_t, playerState_s::groundEntityNum, gentity_s::health, Jedi_PlayBlockedPushSound(), playerState_s::legsAnim, level, gclient_s::NPC_class, NPC_SetAnim(), gentity_s::NPC_type, entityState_s::number, playerState_s::pm_flags, PM_InKnockDown(), PM_RollingAnim(), playerState_s::pm_time, PMF_TIME_KNOCKBACK, playerState_s::powerups, gclient_s::ps, PW_DISINT_4, PW_PULL, Q_stricmp(), qboolean, qfalse, qtrue, gentity_s::s, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, SETANIM_TORSO, level_locals_t::time, playerState_s::torsoTimer, trap_Cvar_VariableStringBuffer(), VectorClear, playerState_s::velocity, and playerState_s::weaponTime. Referenced by Boba_StopKnockdown().
00204 {
00205 int parts;
00206 qboolean runningResist = qfalse;
00207
00208 if ( !self || self->health <= 0 || !self->client || !pusher || !pusher->client )
00209 {
00210 return;
00211 }
00212 if ( (!self->s.number || self->client->NPC_class == CLASS_DESANN || !Q_stricmp("Yoda",self->NPC_type) || self->client->NPC_class == CLASS_LUKE)
00213 && (VectorLengthSquared( self->client->ps.velocity ) > 10000 || self->client->ps.fd.forcePowerLevel[FP_PUSH] >= FORCE_LEVEL_3 || self->client->ps.fd.forcePowerLevel[FP_PULL] >= FORCE_LEVEL_3 ) )
00214 {
00215 runningResist = qtrue;
00216 }
00217 if ( !runningResist
00218 && self->client->ps.groundEntityNum != ENTITYNUM_NONE
00219 && !BG_SpinningSaberAnim( self->client->ps.legsAnim )
00220 && !BG_FlippingAnim( self->client->ps.legsAnim )
00221 && !PM_RollingAnim( self->client->ps.legsAnim )
00222 && !PM_InKnockDown( &self->client->ps )
00223 && !BG_CrouchAnim( self->client->ps.legsAnim ))
00224 {//if on a surface and not in a spin or flip, play full body resist
00225 parts = SETANIM_BOTH;
00226 }
00227 else
00228 {//play resist just in torso
00229 parts = SETANIM_TORSO;
00230 }
00231 NPC_SetAnim( self, parts, BOTH_RESISTPUSH, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00232 if ( !noPenalty )
00233 {
00234 char buf[128];
00235 float tFVal = 0;
00236
00237 trap_Cvar_VariableStringBuffer("timescale", buf, sizeof(buf));
00238
00239 tFVal = atof(buf);
00240
00241 if ( !runningResist )
00242 {
00243 VectorClear( self->client->ps.velocity );
00244 //still stop them from attacking or moving for a bit, though
00245 //FIXME: maybe push just a little (like, slide)?
00246 self->client->ps.weaponTime = 1000;
00247 if ( self->client->ps.fd.forcePowersActive&(1<<FP_SPEED) )
00248 {
00249 self->client->ps.weaponTime = floor( self->client->ps.weaponTime * tFVal );
00250 }
00251 self->client->ps.pm_time = self->client->ps.weaponTime;
00252 self->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
00253 //play the full body push effect on me
00254 //self->forcePushTime = level.time + 600; // let the push effect last for 600 ms
00255 //rwwFIXMEFIXME: Do this?
00256 }
00257 else
00258 {
00259 self->client->ps.weaponTime = 600;
00260 if ( self->client->ps.fd.forcePowersActive&(1<<FP_SPEED) )
00261 {
00262 self->client->ps.weaponTime = floor( self->client->ps.weaponTime * tFVal );
00263 }
00264 }
00265 }
00266 //play my force push effect on my hand
00267 self->client->ps.powerups[PW_DISINT_4] = level.time + self->client->ps.torsoTimer + 500;
00268 self->client->ps.powerups[PW_PULL] = 0;
00269 Jedi_PlayBlockedPushSound( self );
00270 }
|
|
||||||||||||
|
Definition at line 174 of file g_weapon.c.
00175 {
00176 return 500;
00177 }
|
|
|
Definition at line 2812 of file w_saber.c. References SABER_BLUE, saber_colors_t, SABER_GREEN, SABER_ORANGE, SABER_PURPLE, SABER_RED, and SABER_YELLOW.
02813 {
02814 switch( (int)(saberColor) )
02815 {
02816 case SABER_RED:
02817 return 0x000000ff;
02818 break;
02819 case SABER_ORANGE:
02820 return 0x000088ff;
02821 break;
02822 case SABER_YELLOW:
02823 return 0x0000ffff;
02824 break;
02825 case SABER_GREEN:
02826 return 0x0000ff00;
02827 break;
02828 case SABER_BLUE:
02829 return 0x00ff0000;
02830 break;
02831 case SABER_PURPLE:
02832 return 0x00ff00ff;
02833 break;
02834 default:
02835 return 0x00ffffff;//white
02836 break;
02837 }
02838 }
|
|
|
Definition at line 91 of file NPC_AI_Jedi.c. Referenced by Jedi_ReCalcParryTime(), and PM_WeaponLightsaber(). |
|
|
Definition at line 14 of file NPC_AI_Jedi.c. Referenced by Jedi_SaberBlockGo(). |
|
|
Definition at line 13 of file NPC_AI_Jedi.c. |