#include "g_headers.h"#include "b_local.h"Go to the source code of this file.
Defines | |
| #define | MIN_DISTANCE 128 |
| #define | MIN_DISTANCE_SQR ( MIN_DISTANCE * MIN_DISTANCE ) |
| #define | MAX_DISTANCE 1024 |
| #define | MAX_DISTANCE_SQR ( MAX_DISTANCE * MAX_DISTANCE ) |
| #define | LSTATE_CLEAR 0 |
| #define | LSTATE_WAITING 1 |
Functions | |
| void | G_GetBoltPosition (gentity_t *self, int boltIndex, vec3_t pos, int modelIndex) |
| void | Rancor_SetBolts (gentity_t *self) |
| void | NPC_Rancor_Precache (void) |
| void | Rancor_Idle (void) |
| qboolean | Rancor_CheckRoar (gentity_t *self) |
| void | Rancor_Patrol (void) |
| void | Rancor_Move (qboolean visible) |
| void | G_Knockdown (gentity_t *victim) |
| void | G_Dismember (gentity_t *ent, gentity_t *enemy, vec3_t point, int limbType, float limbRollBase, float limbPitchBase, int deathAnim, qboolean postDeath) |
| float | NPC_EntRangeFromBolt (gentity_t *targEnt, int boltIndex) |
| int | NPC_GetEntsNearBolt (int *radiusEnts, float radius, int boltIndex, vec3_t boltOrg) |
| void | Rancor_DropVictim (gentity_t *self) |
| void | Rancor_Swing (qboolean tryGrab) |
| void | Rancor_Smash (void) |
| void | Rancor_Bite (void) |
| void | TossClientItems (gentity_t *self) |
| void | Rancor_Attack (float distance, qboolean doCharge) |
| void | Rancor_Combat (void) |
| void | NPC_Rancor_Pain (gentity_t *self, gentity_t *attacker, int damage) |
| void | Rancor_CheckDropVictim (void) |
| void | Rancor_Crush (void) |
| void | NPC_BSRancor_Default (void) |
|
|
Definition at line 16 of file NPC_AI_Rancor.c. |
|
|
Definition at line 17 of file NPC_AI_Rancor.c. |
|
|
Definition at line 13 of file NPC_AI_Rancor.c. |
|
|
Definition at line 14 of file NPC_AI_Rancor.c. |
|
|
Definition at line 10 of file NPC_AI_Rancor.c. |
|
|
Definition at line 11 of file NPC_AI_Rancor.c. |
|
||||||||||||||||||||||||||||||||||||
|
Definition at line 3311 of file g_combat.c.
03312 {
03313 vec3_t newPoint, dir, vel;
03314 gentity_t *limb;
03315 char limbName[MAX_QPATH];
03316 char stubName[MAX_QPATH];
03317 char stubCapName[MAX_QPATH];
03318
03319 if (limbType == G2_MODELPART_HEAD)
03320 {
03321 Q_strncpyz( limbName , "head", sizeof( limbName ) );
03322 Q_strncpyz( stubCapName, "torso_cap_head", sizeof( stubCapName ) );
03323 }
03324 else if (limbType == G2_MODELPART_WAIST)
03325 {
03326 Q_strncpyz( limbName, "torso", sizeof( limbName ) );
03327 Q_strncpyz( stubCapName, "hips_cap_torso", sizeof( stubCapName ) );
03328 }
03329 else if (limbType == G2_MODELPART_LARM)
03330 {
03331 BG_GetRootSurfNameWithVariant( ent->ghoul2, "l_arm", limbName, sizeof(limbName) );
03332 BG_GetRootSurfNameWithVariant( ent->ghoul2, "torso", stubName, sizeof(stubName) );
03333 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_l_arm", stubName );
03334 }
03335 else if (limbType == G2_MODELPART_RARM)
03336 {
03337 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_arm", limbName, sizeof(limbName) );
03338 BG_GetRootSurfNameWithVariant( ent->ghoul2, "torso", stubName, sizeof(stubName) );
03339 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_arm", stubName );
03340 }
03341 else if (limbType == G2_MODELPART_RHAND)
03342 {
03343 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_hand", limbName, sizeof(limbName) );
03344 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_arm", stubName, sizeof(stubName) );
03345 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_hand", stubName );
03346 }
03347 else if (limbType == G2_MODELPART_LLEG)
03348 {
03349 BG_GetRootSurfNameWithVariant( ent->ghoul2, "l_leg", limbName, sizeof(limbName) );
03350 BG_GetRootSurfNameWithVariant( ent->ghoul2, "hips", stubName, sizeof(stubName) );
03351 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_l_leg", stubName );
03352 }
03353 else if (limbType == G2_MODELPART_RLEG)
03354 {
03355 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_leg", limbName, sizeof(limbName) );
03356 BG_GetRootSurfNameWithVariant( ent->ghoul2, "hips", stubName, sizeof(stubName) );
03357 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_leg", stubName );
03358 }
03359 else
03360 {//umm... just default to the right leg, I guess (same as on client)
03361 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_leg", limbName, sizeof(limbName) );
03362 BG_GetRootSurfNameWithVariant( ent->ghoul2, "hips", stubName, sizeof(stubName) );
03363 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_leg", stubName );
03364 }
03365
03366 if (ent->ghoul2 && limbName && trap_G2API_GetSurfaceRenderStatus(ent->ghoul2, 0, limbName))
03367 { //is it already off? If so there's no reason to be doing it again, so get out of here.
03368 return;
03369 }
03370
03371 VectorCopy( point, newPoint );
03372 limb = G_Spawn();
03373 limb->classname = "playerlimb";
03374
03375 /*
03376 if (limbType == G2_MODELPART_WAIST)
03377 { //slight hack
03378 newPoint[2] += 1;
03379 }
03380 */
03381
03382 G_SetOrigin( limb, newPoint );
03383 VectorCopy( newPoint, limb->s.pos.trBase );
03384 limb->think = LimbThink;
03385 limb->touch = LimbTouch;
03386 limb->speed = level.time + Q_irand(8000, 16000);
03387 limb->nextthink = level.time + FRAMETIME;
03388
03389 limb->r.svFlags = SVF_USE_CURRENT_ORIGIN;
03390 limb->clipmask = MASK_SOLID;
03391 limb->r.contents = CONTENTS_TRIGGER;
03392 limb->physicsObject = qtrue;
03393 VectorSet( limb->r.mins, -6.0f, -6.0f, -3.0f );
03394 VectorSet( limb->r.maxs, 6.0f, 6.0f, 6.0f );
03395
03396 limb->s.g2radius = 200;
03397
03398 limb->s.eType = ET_GENERAL;
03399 limb->s.weapon = G2_MODEL_PART;
03400 limb->s.modelGhoul2 = limbType;
03401 limb->s.modelindex = ent->s.number;
03402 if (!ent->client)
03403 {
03404 limb->s.modelindex = -1;
03405 limb->s.otherEntityNum2 = ent->s.number;
03406 }
03407
03408 VectorClear(limb->s.apos.trDelta);
03409
03410 if (ent->client)
03411 {
03412 VectorCopy(ent->client->ps.viewangles, limb->r.currentAngles);
03413 VectorCopy(ent->client->ps.viewangles, limb->s.apos.trBase);
03414 }
03415 else
03416 {
03417 VectorCopy(ent->r.currentAngles, limb->r.currentAngles);
03418 VectorCopy(ent->r.currentAngles, limb->s.apos.trBase);
03419 }
03420
03421 //Set up the ExPhys values for the entity.
03422 limb->epGravFactor = 0;
03423 VectorClear(limb->epVelocity);
03424 VectorSubtract( point, ent->r.currentOrigin, dir );
03425 VectorNormalize( dir );
03426 if (ent->client)
03427 {
03428 VectorCopy(ent->client->ps.velocity, vel);
03429 }
03430 else
03431 {
03432 VectorCopy(ent->s.pos.trDelta, vel);
03433 }
03434 VectorMA( vel, 80, dir, limb->epVelocity );
03435
03436 //add some vertical velocity
03437 if (limbType == G2_MODELPART_HEAD ||
03438 limbType == G2_MODELPART_WAIST)
03439 {
03440 limb->epVelocity[2] += 10;
03441 }
03442
03443 if (enemy && enemy->client && ent && ent != enemy && ent->s.number != enemy->s.number &&
03444 enemy->client->ps.weapon == WP_SABER && enemy->client->olderIsValid &&
03445 (level.time - enemy->client->lastSaberStorageTime) < 200)
03446 { //The enemy has valid saber positions between this and last frame. Use them to factor in direction of the limb.
03447 vec3_t dif;
03448 float totalDistance;
03449 const float distScale = 1.2f;
03450
03451 //scale down the initial velocity first, which is based on the speed of the limb owner.
03452 //ExPhys object velocity operates on a slightly different scale than Q3-based physics velocity.
03453 VectorScale(limb->epVelocity, 0.4f, limb->epVelocity);
03454
03455 VectorSubtract(enemy->client->lastSaberBase_Always, enemy->client->olderSaberBase, dif);
03456 totalDistance = VectorNormalize(dif);
03457
03458 VectorScale(dif, totalDistance*distScale, dif);
03459 VectorAdd(limb->epVelocity, dif, limb->epVelocity);
03460
03461 if (ent->client && (ent->client->ps.torsoTimer > 0 || !BG_InDeathAnim(ent->client->ps.torsoAnim)))
03462 { //if he's done with his death anim we don't actually want the limbs going far
03463 vec3_t preVel;
03464
03465 VectorCopy(limb->epVelocity, preVel);
03466 preVel[2] = 0;
03467 totalDistance = VectorNormalize(preVel);
03468
03469 if (totalDistance < 40.0f)
03470 {
03471 float mAmt = 40.0f;//60.0f/totalDistance;
03472
03473 limb->epVelocity[0] = preVel[0]*mAmt;
03474 limb->epVelocity[1] = preVel[1]*mAmt;
03475 }
03476 }
03477 else if (ent->client)
03478 {
03479 VectorScale(limb->epVelocity, 0.3f, limb->epVelocity);
03480 }
03481 }
03482
03483 if (ent->s.eType == ET_NPC && ent->ghoul2 && limbName && stubCapName)
03484 { //if it's an npc remove these surfs on the server too. For players we don't even care cause there's no further dismemberment after death.
03485 trap_G2API_SetSurfaceOnOff(ent->ghoul2, limbName, 0x00000100);
03486 trap_G2API_SetSurfaceOnOff(ent->ghoul2, stubCapName, 0);
03487 }
03488
03489 limb->s.customRGBA[0] = ent->s.customRGBA[0];
03490 limb->s.customRGBA[1] = ent->s.customRGBA[1];
03491 limb->s.customRGBA[2] = ent->s.customRGBA[2];
03492 limb->s.customRGBA[3] = ent->s.customRGBA[3];
03493
03494 trap_LinkEntity( limb );
03495 }
|
|
||||||||||||||||||||
|
Definition at line 1707 of file NPC_utils.c.
01708 {
01709 mdxaBone_t boltMatrix;
01710 vec3_t result, angles;
01711
01712 if (!self || !self->inuse)
01713 {
01714 return;
01715 }
01716
01717 if (self->client)
01718 { //clients don't actually even keep r.currentAngles maintained
01719 VectorSet(angles, 0, self->client->ps.viewangles[YAW], 0);
01720 }
01721 else
01722 {
01723 VectorSet(angles, 0, self->r.currentAngles[YAW], 0);
01724 }
01725
01726 if ( !self->ghoul2 )
01727 {
01728 return;
01729 }
01730
01731 trap_G2API_GetBoltMatrix( self->ghoul2, modelIndex,
01732 boltIndex,
01733 &boltMatrix, angles, self->r.currentOrigin, level.time,
01734 NULL, self->modelScale );
01735 if ( pos )
01736 {
01737 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, result );
01738 VectorCopy( result, pos );
01739 }
01740 }
|
|
|
Definition at line 4327 of file g_combat.c.
04328 {
04329 if ( victim && victim->client && BG_KnockDownable(&victim->client->ps) )
04330 {
04331 victim->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
04332 victim->client->ps.forceDodgeAnim = 0;
04333 victim->client->ps.forceHandExtendTime = level.time + 1100;
04334 victim->client->ps.quickerGetup = qfalse;
04335 }
04336 }
|
|
|
Definition at line 828 of file NPC_AI_Rancor.c. References gentity_s::activator, AddSightEvent(), AddSoundEvent(), AEL_DANGER, AEL_DANGER_GREAT, BOTH_ATTACK3, BOTH_PAIN2, CHAN_AUTO, CLASS_RANCOR, gentity_s::client, gNPC_t::confusionTime, gentity_s::count, entityShared_t::currentOrigin, EF2_GENERIC_NPC_FLAG, EF2_USE_ALT_ANIM, playerState_s::eFlags2, gentity_s::enemy, G_SetEnemy(), G_Sound(), G_SoundIndex(), gentity_t, gentity_s::inuse, gentity_s::lastEnemy, playerState_s::legsAnim, level, NPC, NPC_CheckEnemy(), NPC_CheckEnemyExt(), gclient_s::NPC_class, NPC_FaceEnemy(), NPC_UpdateAngles(), NPCInfo, NULL, gclient_s::ps, Q_irand(), qfalse, qtrue, gentity_s::r, Rancor_CheckDropVictim(), Rancor_Combat(), Rancor_Crush(), Rancor_DropVictim(), Rancor_Idle(), Rancor_Patrol(), gentity_s::s, SCF_LOOK_FOR_ENEMIES, gNPC_t::scriptFlags, entityState_s::time, level_locals_t::time, TIMER_Done(), TIMER_Done2(), TIMER_Remove(), TIMER_Set(), va(), and ValidEnemy(). Referenced by NPC_BehaviorSet_Rancor().
00829 {
00830 AddSightEvent( NPC, NPC->r.currentOrigin, 1024, AEL_DANGER_GREAT, 50 );
00831
00832 Rancor_Crush();
00833
00834 NPC->client->ps.eFlags2 &= ~(EF2_USE_ALT_ANIM|EF2_GENERIC_NPC_FLAG);
00835 if ( NPC->count )
00836 {//holding someone
00837 NPC->client->ps.eFlags2 |= EF2_USE_ALT_ANIM;
00838 if ( NPC->count == 2 )
00839 {//in my mouth
00840 NPC->client->ps.eFlags2 |= EF2_GENERIC_NPC_FLAG;
00841 }
00842 }
00843 else
00844 {
00845 NPC->client->ps.eFlags2 &= ~(EF2_USE_ALT_ANIM|EF2_GENERIC_NPC_FLAG);
00846 }
00847
00848 if ( TIMER_Done2( NPC, "clearGrabbed", qtrue ) )
00849 {
00850 Rancor_DropVictim( NPC );
00851 }
00852 else if ( NPC->client->ps.legsAnim == BOTH_PAIN2
00853 && NPC->count == 1
00854 && NPC->activator )
00855 {
00856 if ( !Q_irand( 0, 3 ) )
00857 {
00858 Rancor_CheckDropVictim();
00859 }
00860 }
00861 if ( !TIMER_Done( NPC, "rageTime" ) )
00862 {//do nothing but roar first time we see an enemy
00863 AddSoundEvent( NPC, NPC->r.currentOrigin, 1024, AEL_DANGER_GREAT, qfalse );//, qfalse );
00864 NPC_FaceEnemy( qtrue );
00865 return;
00866 }
00867 if ( NPC->enemy )
00868 {
00869 /*
00870 if ( NPC->enemy->client //enemy is a client
00871 && (NPC->enemy->client->NPC_class == CLASS_UGNAUGHT || NPC->enemy->client->NPC_class == CLASS_JAWA )//enemy is a lowly jawa or ugnaught
00872 && NPC->enemy->enemy != NPC//enemy's enemy is not me
00873 && (!NPC->enemy->enemy || !NPC->enemy->enemy->client || NPC->enemy->enemy->client->NPC_class!=CLASS_RANCOR) )//enemy's enemy is not a client or is not a rancor (which is as scary as me anyway)
00874 {//they should be scared of ME and no-one else
00875 G_SetEnemy( NPC->enemy, NPC );
00876 }
00877 */
00878 if ( TIMER_Done(NPC,"angrynoise") )
00879 {
00880 G_Sound( NPC, CHAN_AUTO, G_SoundIndex( va("sound/chars/rancor/misc/anger%d.wav", Q_irand(1, 3))) );
00881
00882 TIMER_Set( NPC, "angrynoise", Q_irand( 5000, 10000 ) );
00883 }
00884 else
00885 {
00886 AddSoundEvent( NPC, NPC->r.currentOrigin, 512, AEL_DANGER_GREAT, qfalse );//, qfalse );
00887 }
00888 if ( NPC->count == 2 && NPC->client->ps.legsAnim == BOTH_ATTACK3 )
00889 {//we're still chewing our enemy up
00890 NPC_UpdateAngles( qtrue, qtrue );
00891 return;
00892 }
00893 //else, if he's in our hand, we eat, else if he's on the ground, we keep attacking his dead body for a while
00894 if( NPC->enemy->client && NPC->enemy->client->NPC_class == CLASS_RANCOR )
00895 {//got mad at another Rancor, look for a valid enemy
00896 if ( TIMER_Done( NPC, "rancorInfight" ) )
00897 {
00898 NPC_CheckEnemyExt( qtrue );
00899 }
00900 }
00901 else if ( !NPC->count )
00902 {
00903 if ( ValidEnemy( NPC->enemy ) == qfalse )
00904 {
00905 TIMER_Remove( NPC, "lookForNewEnemy" );//make them look again right now
00906 if ( !NPC->enemy->inuse || level.time - NPC->enemy->s.time > Q_irand( 10000, 15000 ) )
00907 {//it's been a while since the enemy died, or enemy is completely gone, get bored with him
00908 NPC->enemy = NULL;
00909 Rancor_Patrol();
00910 NPC_UpdateAngles( qtrue, qtrue );
00911 return;
00912 }
00913 }
00914 if ( TIMER_Done( NPC, "lookForNewEnemy" ) )
00915 {
00916 gentity_t *newEnemy, *sav_enemy = NPC->enemy;//FIXME: what about NPC->lastEnemy?
00917 NPC->enemy = NULL;
00918 newEnemy = NPC_CheckEnemy( NPCInfo->confusionTime < level.time, qfalse, qfalse );
00919 NPC->enemy = sav_enemy;
00920 if ( newEnemy && newEnemy != sav_enemy )
00921 {//picked up a new enemy!
00922 NPC->lastEnemy = NPC->enemy;
00923 G_SetEnemy( NPC, newEnemy );
00924 //hold this one for at least 5-15 seconds
00925 TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 5000, 15000 ) );
00926 }
00927 else
00928 {//look again in 2-5 secs
00929 TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 2000, 5000 ) );
00930 }
00931 }
00932 }
00933 Rancor_Combat();
00934 }
00935 else
00936 {
00937 if ( TIMER_Done(NPC,"idlenoise") )
00938 {
00939 G_Sound( NPC, CHAN_AUTO, G_SoundIndex( va("sound/chars/rancor/snort_%d.wav", Q_irand(1, 2))) );
00940
00941 TIMER_Set( NPC, "idlenoise", Q_irand( 2000, 4000 ) );
00942 AddSoundEvent( NPC, NPC->r.currentOrigin, 384, AEL_DANGER, qfalse );//, qfalse );
00943 }
00944 if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
00945 {
00946 Rancor_Patrol();
00947 }
00948 else
00949 {
00950 Rancor_Idle();
00951 }
00952 }
00953
00954 NPC_UpdateAngles( qtrue, qtrue );
00955 }
|
|
||||||||||||
|
Definition at line 1742 of file NPC_utils.c. References entityShared_t::currentOrigin, G_GetBoltPosition(), gentity_t, NPC, Q3_INFINITE, gentity_s::r, and vec3_t. Referenced by NPC_EnemyRangeFromBolt().
01743 {
01744 vec3_t org;
01745
01746 if ( !targEnt )
01747 {
01748 return Q3_INFINITE;
01749 }
01750
01751 G_GetBoltPosition( NPC, boltIndex, org, 0 );
01752
01753 return (Distance( targEnt->r.currentOrigin, org ));
01754 }
|
|
||||||||||||||||||||
|
Definition at line 1761 of file NPC_utils.c.
01762 {
01763 vec3_t mins, maxs;
01764 int i;
01765
01766 //get my handRBolt's position
01767 vec3_t org;
01768
01769 G_GetBoltPosition( NPC, boltIndex, org, 0 );
01770
01771 VectorCopy( org, boltOrg );
01772
01773 //Setup the bbox to search in
01774 for ( i = 0; i < 3; i++ )
01775 {
01776 mins[i] = boltOrg[i] - radius;
01777 maxs[i] = boltOrg[i] + radius;
01778 }
01779
01780 //Get the number of entities in a given space
01781 return (trap_EntitiesInBox( mins, maxs, radiusEnts, 128 ));
01782 }
|
|
||||||||||||||||
|
Definition at line 703 of file NPC_AI_Rancor.c. References gentity_s::activator, entityState_s::angles, BOTH_ATTACK2, BOTH_MELEE1, BOTH_MELEE2, BOTH_PAIN1, BOTH_PAIN2, BOTH_STAND1TO2, CLASS_RANCOR, gentity_s::client, gNPC_t::consecutiveBlockedMoves, gentity_s::count, entityShared_t::currentOrigin, gentity_s::enemy, FL_NOTARGET, gentity_s::flags, G_SetEnemy(), gentity_t, gentity_s::health, gentity_s::inuse, gNPC_t::lastPathAngles, playerState_s::legsAnim, playerState_s::legsTimer, gNPC_t::localState, LSTATE_WAITING, gentity_s::NPC, gclient_s::NPC_class, NPC_SetAnim(), entityState_s::number, gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, Rancor_CheckRoar(), gentity_s::s, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, TIMER_Done(), TIMER_Remove(), TIMER_Set(), and VectorCopy. Referenced by NPC_PainFunc(), and NPC_SetMiscDefaultData().
00704 {
00705 qboolean hitByRancor = qfalse;
00706 if ( attacker&&attacker->client&&attacker->client->NPC_class==CLASS_RANCOR )
00707 {
00708 hitByRancor = qtrue;
00709 }
00710 if ( attacker
00711 && attacker->inuse
00712 && attacker != self->enemy
00713 && !(attacker->flags&FL_NOTARGET) )
00714 {
00715 if ( !self->count )
00716 {
00717 if ( (!attacker->s.number&&!Q_irand(0,3))
00718 || !self->enemy
00719 || self->enemy->health == 0
00720 || (self->enemy->client&&self->enemy->client->NPC_class == CLASS_RANCOR)
00721 || (self->NPC && self->NPC->consecutiveBlockedMoves>=10 && DistanceSquared( attacker->r.currentOrigin, self->r.currentOrigin ) < DistanceSquared( self->enemy->r.currentOrigin, self->r.currentOrigin )) )
00722 {//if my enemy is dead (or attacked by player) and I'm not still holding/eating someone, turn on the attacker
00723 //FIXME: if can't nav to my enemy, take this guy if I can nav to him
00724 G_SetEnemy( self, attacker );
00725 TIMER_Set( self, "lookForNewEnemy", Q_irand( 5000, 15000 ) );
00726 if ( hitByRancor )
00727 {//stay mad at this Rancor for 2-5 secs before looking for attacker enemies
00728 TIMER_Set( self, "rancorInfight", Q_irand( 2000, 5000 ) );
00729 }
00730
00731 }
00732 }
00733 }
00734 if ( (hitByRancor|| (self->count==1&&self->activator&&!Q_irand(0,4)) || Q_irand( 0, 200 ) < damage )//hit by rancor, hit while holding live victim, or took a lot of damage
00735 && self->client->ps.legsAnim != BOTH_STAND1TO2
00736 && TIMER_Done( self, "takingPain" ) )
00737 {
00738 if ( !Rancor_CheckRoar( self ) )
00739 {
00740 if ( self->client->ps.legsAnim != BOTH_MELEE1
00741 && self->client->ps.legsAnim != BOTH_MELEE2
00742 && self->client->ps.legsAnim != BOTH_ATTACK2 )
00743 {//cant interrupt one of the big attack anims
00744 /*
00745 if ( self->count != 1
00746 || attacker == self->activator
00747 || (self->client->ps.legsAnim != BOTH_ATTACK1&&self->client->ps.legsAnim != BOTH_ATTACK3) )
00748 */
00749 {//if going to bite our victim, only victim can interrupt that anim
00750 if ( self->health > 100 || hitByRancor )
00751 {
00752 TIMER_Remove( self, "attacking" );
00753
00754 VectorCopy( self->NPC->lastPathAngles, self->s.angles );
00755
00756 if ( self->count == 1 )
00757 {
00758 NPC_SetAnim( self, SETANIM_BOTH, BOTH_PAIN2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00759 }
00760 else
00761 {
00762 NPC_SetAnim( self, SETANIM_BOTH, BOTH_PAIN1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00763 }
00764 TIMER_Set( self, "takingPain", self->client->ps.legsTimer+Q_irand(0, 500) );
00765
00766 if ( self->NPC )
00767 {
00768 self->NPC->localState = LSTATE_WAITING;
00769 }
00770 }
00771 }
00772 }
00773 }
00774 //let go
00775 /*
00776 if ( !Q_irand( 0, 3 ) && self->count == 1 )
00777 {
00778 Rancor_DropVictim( self );
00779 }
00780 */
00781 }
00782 }
|
|
|
Definition at line 36 of file NPC_AI_Rancor.c. References G_SoundIndex(), and va().
00037 {
00038 int i;
00039 for ( i = 1; i < 3; i ++ )
00040 {
00041 G_SoundIndex( va("sound/chars/rancor/snort_%d.wav", i) );
00042 }
00043 G_SoundIndex( "sound/chars/rancor/swipehit.wav" );
00044 G_SoundIndex( "sound/chars/rancor/chomp.wav" );
00045 }
|
|
||||||||||||
|
Definition at line 431 of file NPC_AI_Rancor.c. References gentity_s::activator, AngleVectors(), BOTH_ATTACK1, BOTH_ATTACK2, BOTH_ATTACK3, BOTH_FALLDEATH1, BOTH_MELEE1, BOTH_MELEE2, BOTH_SWIM_IDLE1, CHAN_AUTO, gentity_s::client, gentity_s::count, entityShared_t::currentOrigin, DAMAGE_NO_ARMOR, DAMAGE_NO_HIT_LOC, DAMAGE_NO_KNOCKBACK, DAMAGE_NO_PROTECTION, EF_NODRAW, playerState_s::eFlags, gentity_s::enemy, ENTITYNUM_NONE, EV_DEATH1, EV_DEATH3, EV_JUMP, playerState_s::forceHandExtend, playerState_s::forceHandExtendTime, G2_MODELPART_HEAD, G2_MODELPART_WAIST, G_AddEvent(), G_Damage(), G_Dismember(), G_GetBoltPosition(), G_ScreenShake(), G_Sound(), G_SoundIndex(), playerState_s::groundEntityNum, HANDEXTEND_NONE, renderInfo_s::handLBolt, gentity_s::health, playerState_s::legsAnim, playerState_s::legsTimer, MOD_MELEE, gNPC_t::nextBStateThink, gentity_s::NPC, NPC, NPC_SetAnim(), NULL, gclient_s::ps, Q3_INFINITE, Q_irand(), qfalse, qtrue, gentity_s::r, Rancor_Bite(), Rancor_Smash(), Rancor_Swing(), random, gclient_s::renderInfo, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, SETANIM_TORSO, TIMER_Done2(), TIMER_Exists(), TIMER_Set(), playerState_s::torsoAnim, TossClientItems(), vec3_origin, vec3_t, VectorScale, VectorSet, playerState_s::velocity, playerState_s::viewangles, and YAW. Referenced by Rancor_Combat().
00432 {
00433 if ( !TIMER_Exists( NPC, "attacking" ) )
00434 {
00435 if ( NPC->count == 2 && NPC->activator )
00436 {
00437 }
00438 else if ( NPC->count == 1 && NPC->activator )
00439 {//holding enemy
00440 if ( NPC->activator->health > 0 && Q_irand( 0, 1 ) )
00441 {//quick bite
00442 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00443 TIMER_Set( NPC, "attack_dmg", 450 );
00444 }
00445 else
00446 {//full eat
00447 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK3, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00448 TIMER_Set( NPC, "attack_dmg", 900 );
00449 //Make victim scream in fright
00450 if ( NPC->activator->health > 0 && NPC->activator->client )
00451 {
00452 G_AddEvent( NPC->activator, Q_irand(EV_DEATH1, EV_DEATH3), 0 );
00453 NPC_SetAnim( NPC->activator, SETANIM_TORSO, BOTH_FALLDEATH1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00454 if ( NPC->activator->NPC )
00455 {//no more thinking for you
00456 TossClientItems( NPC );
00457 NPC->activator->NPC->nextBStateThink = Q3_INFINITE;
00458 }
00459 }
00460 }
00461 }
00462 else if ( NPC->enemy->health > 0 && doCharge )
00463 {//charge
00464 vec3_t fwd, yawAng;
00465 VectorSet( yawAng, 0, NPC->client->ps.viewangles[YAW], 0 );
00466 AngleVectors( yawAng, fwd, NULL, NULL );
00467 VectorScale( fwd, distance*1.5f, NPC->client->ps.velocity );
00468 NPC->client->ps.velocity[2] = 150;
00469 NPC->client->ps.groundEntityNum = ENTITYNUM_NONE;
00470
00471 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_MELEE2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00472 TIMER_Set( NPC, "attack_dmg", 1250 );
00473 }
00474 else if ( !Q_irand(0, 1) )
00475 {//smash
00476 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_MELEE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00477 TIMER_Set( NPC, "attack_dmg", 1000 );
00478 }
00479 else
00480 {//try to grab
00481 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00482 TIMER_Set( NPC, "attack_dmg", 1000 );
00483 }
00484
00485 TIMER_Set( NPC, "attacking", NPC->client->ps.legsTimer + random() * 200 );
00486 }
00487
00488 // Need to do delayed damage since the attack animations encapsulate multiple mini-attacks
00489
00490 if ( TIMER_Done2( NPC, "attack_dmg", qtrue ) )
00491 {
00492 vec3_t shakePos;
00493 switch ( NPC->client->ps.legsAnim )
00494 {
00495 case BOTH_MELEE1:
00496 Rancor_Smash();
00497 G_GetBoltPosition( NPC, NPC->client->renderInfo.handLBolt, shakePos, 0 );
00498 G_ScreenShake( shakePos, NULL, 4.0f, 1000, qfalse );
00499 //CGCam_Shake( 1.0f*playerDist/128.0f, 1000 );
00500 break;
00501 case BOTH_MELEE2:
00502 Rancor_Bite();
00503 TIMER_Set( NPC, "attack_dmg2", 450 );
00504 break;
00505 case BOTH_ATTACK1:
00506 if ( NPC->count == 1 && NPC->activator )
00507 {
00508 G_Damage( NPC->activator, NPC, NPC, vec3_origin, NPC->activator->r.currentOrigin, Q_irand( 25, 40 ), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_MELEE );
00509 if ( NPC->activator->health <= 0 )
00510 {//killed him
00511 //make it look like we bit his head off
00512 //NPC->activator->client->dismembered = qfalse;
00513 G_Dismember( NPC->activator, NPC, NPC->activator->r.currentOrigin, G2_MODELPART_HEAD, 90, 0, NPC->activator->client->ps.torsoAnim, qtrue);
00514 //G_DoDismemberment( NPC->activator, NPC->activator->r.currentOrigin, MOD_SABER, 1000, HL_HEAD, qtrue );
00515 NPC->activator->client->ps.forceHandExtend = HANDEXTEND_NONE;
00516 NPC->activator->client->ps.forceHandExtendTime = 0;
00517 NPC_SetAnim( NPC->activator, SETANIM_BOTH, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00518 }
00519 G_Sound( NPC->activator, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/chomp.wav" ) );
00520 }
00521 break;
00522 case BOTH_ATTACK2:
00523 //try to grab
00524 Rancor_Swing( qtrue );
00525 break;
00526 case BOTH_ATTACK3:
00527 if ( NPC->count == 1 && NPC->activator )
00528 {
00529 //cut in half
00530 if ( NPC->activator->client )
00531 {
00532 //NPC->activator->client->dismembered = qfalse;
00533 G_Dismember( NPC->activator, NPC, NPC->activator->r.currentOrigin, G2_MODELPART_WAIST, 90, 0, NPC->activator->client->ps.torsoAnim, qtrue);
00534 //G_DoDismemberment( NPC->activator, NPC->enemy->r.currentOrigin, MOD_SABER, 1000, HL_WAIST, qtrue );
00535 }
00536 //KILL
00537 G_Damage( NPC->activator, NPC, NPC, vec3_origin, NPC->activator->r.currentOrigin, NPC->enemy->health+10, DAMAGE_NO_PROTECTION|DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, MOD_MELEE );//, HL_NONE );//
00538 if ( NPC->activator->client )
00539 {
00540 NPC->activator->client->ps.forceHandExtend = HANDEXTEND_NONE;
00541 NPC->activator->client->ps.forceHandExtendTime = 0;
00542 NPC_SetAnim( NPC->activator, SETANIM_BOTH, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00543 }
00544 TIMER_Set( NPC, "attack_dmg2", 1350 );
00545 G_Sound( NPC->activator, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/swipehit.wav" ) );
00546 G_AddEvent( NPC->activator, EV_JUMP, NPC->activator->health );
00547 }
00548 break;
00549 }
00550 }
00551 else if ( TIMER_Done2( NPC, "attack_dmg2", qtrue ) )
00552 {
00553 switch ( NPC->client->ps.legsAnim )
00554 {
00555 case BOTH_MELEE1:
00556 break;
00557 case BOTH_MELEE2:
00558 Rancor_Bite();
00559 break;
00560 case BOTH_ATTACK1:
00561 break;
00562 case BOTH_ATTACK2:
00563 break;
00564 case BOTH_ATTACK3:
00565 if ( NPC->count == 1 && NPC->activator )
00566 {//swallow victim
00567 G_Sound( NPC->activator, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/chomp.wav" ) );
00568 //FIXME: sometimes end up with a live one in our mouths?
00569 //just make sure they're dead
00570 if ( NPC->activator->health > 0 )
00571 {
00572 //cut in half
00573 //NPC->activator->client->dismembered = qfalse;
00574 G_Dismember( NPC->activator, NPC, NPC->activator->r.currentOrigin, G2_MODELPART_WAIST, 90, 0, NPC->activator->client->ps.torsoAnim, qtrue);
00575 //G_DoDismemberment( NPC->activator, NPC->enemy->r.currentOrigin, MOD_SABER, 1000, HL_WAIST, qtrue );
00576 //KILL
00577 G_Damage( NPC->activator, NPC, NPC, vec3_origin, NPC->activator->r.currentOrigin, NPC->enemy->health+10, DAMAGE_NO_PROTECTION|DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, MOD_MELEE );//, HL_NONE );
00578 NPC->activator->client->ps.forceHandExtend = HANDEXTEND_NONE;
00579 NPC->activator->client->ps.forceHandExtendTime = 0;
00580 NPC_SetAnim( NPC->activator, SETANIM_BOTH, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00581 G_AddEvent( NPC->activator, EV_JUMP, NPC->activator->health );
00582 }
00583 if ( NPC->activator->client )
00584 {//*sigh*, can't get tags right, just remove them?
00585 NPC->activator->client->ps.eFlags |= EF_NODRAW;
00586 }
00587 NPC->count = 2;
00588 TIMER_Set( NPC, "clearGrabbed", 2600 );
00589 }
00590 break;
00591 }
00592 }
00593 else if ( NPC->client->ps.legsAnim == BOTH_ATTACK2 )
00594 {
00595 if ( NPC->client->ps.legsTimer >= 1200 && NPC->client->ps.legsTimer <= 1350 )
00596 {
00597 if ( Q_irand( 0, 2 ) )
00598 {
00599 Rancor_Swing( qfalse );
00600 }
00601 else
00602 {
00603 Rancor_Swing( qtrue );
00604 }
00605 }
00606 else if ( NPC->client->ps.legsTimer >= 1100 && NPC->client->ps.legsTimer <= 1550 )
00607 {
00608 Rancor_Swing( qtrue );
00609 }
00610 }
00611
00612 // Just using this to remove the attacking flag at the right time
00613 TIMER_Done2( NPC, "attacking", qtrue );
00614 }
|
|
|
Definition at line 369 of file NPC_AI_Rancor.c. References BOTH_DEATH17, BOTH_DEATHBACKWARD2, CHAN_AUTO, gentity_s::client, renderInfo_s::crotchBolt, entityShared_t::currentOrigin, DAMAGE_NO_ARMOR, DAMAGE_NO_KNOCKBACK, EF2_HELD_BY_MONSTER, playerState_s::eFlags2, G2_MODELPART_HEAD, G2_MODELPART_RLEG, G2_MODELPART_WAIST, G_Damage(), G_Dismember(), g_entities, G_Sound(), G_SoundIndex(), gentity_t, gentity_s::health, gentity_s::inuse, MOD_MELEE, NPC, NPC_GetEntsNearBolt(), NPC_SetAnim(), NULL, gclient_s::ps, Q_irand(), qtrue, gentity_s::r, gclient_s::renderInfo, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, playerState_s::torsoAnim, vec3_origin, and vec3_t. Referenced by Rancor_Attack().
00370 {
00371 int radiusEntNums[128];
00372 int numEnts;
00373 const float radius = 100;
00374 const float radiusSquared = (radius*radius);
00375 int i;
00376 vec3_t boltOrg;
00377
00378 numEnts = NPC_GetEntsNearBolt( radiusEntNums, radius, NPC->client->renderInfo.crotchBolt, boltOrg );//was gutBolt?
00379
00380 for ( i = 0; i < numEnts; i++ )
00381 {
00382 gentity_t *radiusEnt = &g_entities[radiusEntNums[i]];
00383 if ( !radiusEnt->inuse )
00384 {
00385 continue;
00386 }
00387
00388 if ( radiusEnt == NPC )
00389 {//Skip the rancor ent
00390 continue;
00391 }
00392
00393 if ( radiusEnt->client == NULL )
00394 {//must be a client
00395 continue;
00396 }
00397
00398 if ( (radiusEnt->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
00399 {//can't be one already being held
00400 continue;
00401 }
00402
00403 if ( DistanceSquared( radiusEnt->r.currentOrigin, boltOrg ) <= radiusSquared )
00404 {
00405 G_Damage( radiusEnt, NPC, NPC, vec3_origin, radiusEnt->r.currentOrigin, Q_irand( 15, 30 ), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_MELEE );
00406 if ( radiusEnt->health <= 0 && radiusEnt->client )
00407 {//killed them, chance of dismembering
00408 if ( !Q_irand( 0, 1 ) )
00409 {//bite something off
00410 int hitLoc = Q_irand( G2_MODELPART_HEAD, G2_MODELPART_RLEG );
00411 if ( hitLoc == G2_MODELPART_HEAD )
00412 {
00413 NPC_SetAnim( radiusEnt, SETANIM_BOTH, BOTH_DEATH17, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00414 }
00415 else if ( hitLoc == G2_MODELPART_WAIST )
00416 {
00417 NPC_SetAnim( radiusEnt, SETANIM_BOTH, BOTH_DEATHBACKWARD2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00418 }
00419 //radiusEnt->client->dismembered = qfalse;
00420 //FIXME: the limb should just disappear, cuz I ate it
00421 G_Dismember( radiusEnt, NPC, radiusEnt->r.currentOrigin, hitLoc, 90, 0, radiusEnt->client->ps.torsoAnim, qtrue);
00422 //G_DoDismemberment( radiusEnt, radiusEnt->r.currentOrigin, MOD_SABER, 1000, hitLoc, qtrue );
00423 }
00424 }
00425 G_Sound( radiusEnt, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/chomp.wav" ) );
00426 }
00427 }
00428 }
|
|
|
|
Definition at line 66 of file NPC_AI_Rancor.c. References BOTH_STAND1TO2, gentity_s::client, EF2_ALERTED, playerState_s::eFlags2, gentity_t, playerState_s::legsTimer, NPC_SetAnim(), gclient_s::ps, qboolean, qfalse, qtrue, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, TIMER_Set(), and gentity_s::wait. Referenced by NPC_Rancor_Pain(), and Rancor_Patrol().
00067 {
00068 if ( !self->wait )
00069 {//haven't ever gotten mad yet
00070 self->wait = 1;//do this only once
00071 self->client->ps.eFlags2 |= EF2_ALERTED;
00072 NPC_SetAnim( self, SETANIM_BOTH, BOTH_STAND1TO2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00073 TIMER_Set( self, "rageTime", self->client->ps.legsTimer );
00074 return qtrue;
00075 }
00076 return qfalse;
00077 }
|
|
|
Definition at line 617 of file NPC_AI_Rancor.c. References gNPC_t::combatMove, gNPC_t::consecutiveBlockedMoves, gentity_s::count, entityShared_t::currentAngles, entityShared_t::currentOrigin, gentity_s::enemy, fabs(), gNPC_t::goalEntity, gNPC_t::goalRadius, gentity_s::health, InFOV3(), gNPC_t::localState, LSTATE_CLEAR, entityShared_t::maxs, MIN_DISTANCE, NPC, NPC_ClearLOS4(), NPC_FaceEnemy(), NPC_MoveToGoal(), NPC_UpdateAngles(), NPCInfo, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, Rancor_Attack(), Rancor_Move(), TIMER_Done(), TIMER_Done2(), TIMER_Set(), vec3_t, VectorSet, and YAW. Referenced by NPC_BSRancor_Default().
00618 {
00619 if ( NPC->count )
00620 {//holding my enemy
00621 if ( TIMER_Done2( NPC, "takingPain", qtrue ))
00622 {
00623 NPCInfo->localState = LSTATE_CLEAR;
00624 }
00625 else
00626 {
00627 Rancor_Attack( 0, qfalse );
00628 }
00629 NPC_UpdateAngles( qtrue, qtrue );
00630 return;
00631 }
00632 // If we cannot see our target or we have somewhere to go, then do that
00633 if ( !NPC_ClearLOS4( NPC->enemy ) )//|| UpdateGoal( ))
00634 {
00635 NPCInfo->combatMove = qtrue;
00636 NPCInfo->goalEntity = NPC->enemy;
00637 NPCInfo->goalRadius = MIN_DISTANCE;//MAX_DISTANCE; // just get us within combat range
00638
00639 if ( !NPC_MoveToGoal( qtrue ) )
00640 {//couldn't go after him? Look for a new one
00641 TIMER_Set( NPC, "lookForNewEnemy", 0 );
00642 NPCInfo->consecutiveBlockedMoves++;
00643 }
00644 else
00645 {
00646 NPCInfo->consecutiveBlockedMoves = 0;
00647 }
00648 return;
00649 }
00650
00651 // Sometimes I have problems with facing the enemy I'm attacking, so force the issue so I don't look dumb
00652 NPC_FaceEnemy( qtrue );
00653
00654 {
00655 float distance;
00656 qboolean advance;
00657 qboolean doCharge;
00658
00659 distance = Distance( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin );
00660 advance = (qboolean)( distance > (NPC->r.maxs[0]+MIN_DISTANCE) ? qtrue : qfalse );
00661 doCharge = qfalse;
00662
00663 if ( advance )
00664 {//have to get closer
00665 vec3_t yawOnlyAngles;
00666 VectorSet( yawOnlyAngles, 0, NPC->r.currentAngles[YAW], 0 );
00667 if ( NPC->enemy->health > 0
00668 && fabs(distance-250) <= 80
00669 && InFOV3( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, yawOnlyAngles, 30, 30 ) )
00670 {
00671 if ( !Q_irand( 0, 9 ) )
00672 {//go for the charge
00673 doCharge = qtrue;
00674 advance = qfalse;
00675 }
00676 }
00677 }
00678
00679 if (( advance /*|| NPCInfo->localState == LSTATE_WAITING*/ ) && TIMER_Done( NPC, "attacking" )) // waiting monsters can't attack
00680 {
00681 if ( TIMER_Done2( NPC, "takingPain", qtrue ))
00682 {
00683 NPCInfo->localState = LSTATE_CLEAR;
00684 }
00685 else
00686 {
00687 Rancor_Move( 1 );
00688 }
00689 }
00690 else
00691 {
00692 Rancor_Attack( distance, doCharge );
00693 }
00694 }
00695 }
|
|
|
Definition at line 805 of file NPC_AI_Rancor.c. References gentity_s::client, entityShared_t::currentOrigin, ENTITYNUM_WORLD, G_Damage(), g_entities, gentity_t, playerState_s::groundEntityNum, gentity_s::inuse, gentity_s::localAnimIndex, MOD_CRUSH, NPC, NULL, gclient_s::ps, and gentity_s::r. Referenced by NPC_BSRancor_Default().
00806 {
00807 gentity_t *crush;
00808
00809 if (!NPC ||
00810 !NPC->client ||
00811 NPC->client->ps.groundEntityNum >= ENTITYNUM_WORLD)
00812 { //nothing to crush
00813 return;
00814 }
00815
00816 crush = &g_entities[NPC->client->ps.groundEntityNum];
00817 if (crush->inuse && crush->client && !crush->localAnimIndex)
00818 { //a humanoid, smash them good.
00819 G_Damage(crush, NPC, NPC, NULL, NPC->r.currentOrigin, 200, 0, MOD_CRUSH);
00820 }
00821 }
|
|
|
Definition at line 140 of file NPC_AI_Rancor.c. References gentity_s::activator, gentity_s::client, gentity_s::count, entityShared_t::currentAngles, EF2_HELD_BY_MONSTER, EF_NODRAW, playerState_s::eFlags, playerState_s::eFlags2, gentity_s::enemy, ENTITYNUM_NONE, G_SetAngles(), gentity_t, playerState_s::hasLookTarget, gentity_s::health, playerState_s::legsTimer, level, playerState_s::lookTarget, gNPC_t::nextBStateThink, gentity_s::NPC, NULL, PITCH, gclient_s::ps, qfalse, gentity_s::r, ROLL, SetClientViewAngle(), level_locals_t::time, playerState_s::torsoTimer, and playerState_s::viewangles. Referenced by NPC_BSRancor_Default(), player_die(), Rancor_CheckDropVictim(), and Rancor_Swing().
00141 {
00142 //FIXME: if Rancor dies, it should drop its victim.
00143 //FIXME: if Rancor is removed, it must remove its victim.
00144 if ( self->activator )
00145 {
00146 if ( self->activator->client )
00147 {
00148 self->activator->client->ps.eFlags2 &= ~EF2_HELD_BY_MONSTER;
00149 self->activator->client->ps.hasLookTarget = qfalse;
00150 self->activator->client->ps.lookTarget = ENTITYNUM_NONE;
00151 self->activator->client->ps.viewangles[ROLL] = 0;
00152 SetClientViewAngle( self->activator, self->activator->client->ps.viewangles );
00153 self->activator->r.currentAngles[PITCH] = self->activator->r.currentAngles[ROLL] = 0;
00154 G_SetAngles( self->activator, self->activator->r.currentAngles );
00155 }
00156 if ( self->activator->health <= 0 )
00157 {
00158 //if ( self->activator->s.number )
00159 {//never free player
00160 if ( self->count == 1 )
00161 {//in my hand, just drop them
00162 if ( self->activator->client )
00163 {
00164 self->activator->client->ps.legsTimer = self->activator->client->ps.torsoTimer = 0;
00165 //FIXME: ragdoll?
00166 }
00167 }
00168 else
00169 {
00170 if ( self->activator->client )
00171 {
00172 self->activator->client->ps.eFlags |= EF_NODRAW;//so his corpse doesn't drop out of me...
00173 }
00174 //G_FreeEntity( self->activator );
00175 }
00176 }
00177 }
00178 else
00179 {
00180 if ( self->activator->NPC )
00181 {//start thinking again
00182 self->activator->NPC->nextBStateThink = level.time;
00183 }
00184 //clear their anim and let them fall
00185 self->activator->client->ps.legsTimer = self->activator->client->ps.torsoTimer = 0;
00186 }
00187 if ( self->enemy == self->activator )
00188 {
00189 self->enemy = NULL;
00190 }
00191 self->activator = NULL;
00192 }
00193 self->count = 0;//drop him
00194 }
|
|
|
Definition at line 53 of file NPC_AI_Rancor.c. References BUTTON_WALKING, usercmd_s::buttons, gNPC_t::localState, LSTATE_CLEAR, NPC_MoveToGoal(), NPCInfo, qtrue, ucmd, and UpdateGoal(). Referenced by NPC_BSRancor_Default(), and Rancor_Patrol().
00054 {
00055 NPCInfo->localState = LSTATE_CLEAR;
00056
00057 //If we have somewhere to go, then do that
00058 if ( UpdateGoal() )
00059 {
00060 ucmd.buttons &= ~BUTTON_WALKING;
00061 NPC_MoveToGoal( qtrue );
00062 }
00063 }
|
|
|
Definition at line 115 of file NPC_AI_Rancor.c. References gNPC_t::consecutiveBlockedMoves, gentity_s::enemy, gNPC_t::goalEntity, gNPC_t::goalRadius, gNPC_t::localState, LSTATE_WAITING, MAX_DISTANCE, NPC, NPC_MoveToGoal(), NPCInfo, and qtrue. Referenced by Rancor_Combat().
00116 {
00117 if ( NPCInfo->localState != LSTATE_WAITING )
00118 {
00119 NPCInfo->goalEntity = NPC->enemy;
00120 if ( !NPC_MoveToGoal( qtrue ) )
00121 {
00122 NPCInfo->consecutiveBlockedMoves++;
00123 }
00124 else
00125 {
00126 NPCInfo->consecutiveBlockedMoves = 0;
00127 }
00128 NPCInfo->goalRadius = MAX_DISTANCE; // just get us within combat range
00129 }
00130 }
|
|
|
Definition at line 83 of file NPC_AI_Rancor.c. References BUTTON_WALKING, usercmd_s::buttons, crandom, gNPC_t::localState, LSTATE_CLEAR, NPC, NPC_CheckEnemyExt(), NPC_MoveToGoal(), NPCInfo, Q_irand(), qfalse, qtrue, Rancor_CheckRoar(), Rancor_Idle(), TIMER_Done(), TIMER_Set(), ucmd, and UpdateGoal(). Referenced by NPC_BSRancor_Default().
00084 {
00085 NPCInfo->localState = LSTATE_CLEAR;
00086
00087 //If we have somewhere to go, then do that
00088 if ( UpdateGoal() )
00089 {
00090 ucmd.buttons &= ~BUTTON_WALKING;
00091 NPC_MoveToGoal( qtrue );
00092 }
00093 else
00094 {
00095 if ( TIMER_Done( NPC, "patrolTime" ))
00096 {
00097 TIMER_Set( NPC, "patrolTime", crandom() * 5000 + 5000 );
00098 }
00099 }
00100
00101 if ( NPC_CheckEnemyExt( qtrue ) == qfalse )
00102 {
00103 Rancor_Idle();
00104 return;
00105 }
00106 Rancor_CheckRoar( NPC );
00107 TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 5000, 15000 ) );
00108 }
|
|
|
Definition at line 19 of file NPC_AI_Rancor.c. References gentity_s::client, gentity_t, gentity_s::ghoul2, renderInfo_s::handLBolt, renderInfo_s::handRBolt, renderInfo_s::headBolt, gclient_s::renderInfo, renderInfo_t, renderInfo_s::torsoBolt, and trap_G2API_AddBolt(). Referenced by NPC_SetMiscDefaultData().
00020 {
00021 if ( self && self->client )
00022 {
00023 renderInfo_t *ri = &self->client->renderInfo;
00024 ri->handRBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*r_hand" );
00025 ri->handLBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*l_hand" );
00026 ri->headBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*head_eyes" );
00027 ri->torsoBolt = trap_G2API_AddBolt( self->ghoul2, 0, "jaw_bone" );
00028 }
00029 }
|
|
|
Definition at line 308 of file NPC_AI_Rancor.c. References AddSoundEvent(), AEL_DANGER, CHAN_AUTO, CLASS_ATST, CLASS_RANCOR, gentity_s::client, entityShared_t::currentOrigin, DAMAGE_NO_ARMOR, DAMAGE_NO_KNOCKBACK, EF2_HELD_BY_MONSTER, playerState_s::eFlags2, ENTITYNUM_NONE, G_Damage(), g_entities, G_Knockdown(), G_Sound(), G_SoundIndex(), gentity_t, playerState_s::groundEntityNum, renderInfo_s::handLBolt, gentity_s::health, gentity_s::inuse, MOD_MELEE, NPC, gclient_s::NPC_class, NPC_GetEntsNearBolt(), NULL, gclient_s::ps, Q_irand(), qfalse, gentity_s::r, gclient_s::renderInfo, vec3_origin, and vec3_t. Referenced by Rancor_Attack().
00309 {
00310 int radiusEntNums[128];
00311 int numEnts;
00312 const float radius = 128;
00313 const float halfRadSquared = ((radius/2)*(radius/2));
00314 const float radiusSquared = (radius*radius);
00315 float distSq;
00316 int i;
00317 vec3_t boltOrg;
00318
00319 AddSoundEvent( NPC, NPC->r.currentOrigin, 512, AEL_DANGER, qfalse );//, qtrue );
00320
00321 numEnts = NPC_GetEntsNearBolt( radiusEntNums, radius, NPC->client->renderInfo.handLBolt, boltOrg );
00322
00323 for ( i = 0; i < numEnts; i++ )
00324 {
00325 gentity_t *radiusEnt = &g_entities[radiusEntNums[i]];
00326 if ( !radiusEnt->inuse )
00327 {
00328 continue;
00329 }
00330
00331 if ( radiusEnt == NPC )
00332 {//Skip the rancor ent
00333 continue;
00334 }
00335
00336 if ( radiusEnt->client == NULL )
00337 {//must be a client
00338 continue;
00339 }
00340
00341 if ( (radiusEnt->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
00342 {//can't be one being held
00343 continue;
00344 }
00345
00346 distSq = DistanceSquared( radiusEnt->r.currentOrigin, boltOrg );
00347 if ( distSq <= radiusSquared )
00348 {
00349 G_Sound( radiusEnt, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/swipehit.wav" ) );
00350 if ( distSq < halfRadSquared )
00351 {//close enough to do damage, too
00352 G_Damage( radiusEnt, NPC, NPC, vec3_origin, radiusEnt->r.currentOrigin, Q_irand( 10, 25 ), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_MELEE );
00353 }
00354 if ( radiusEnt->health > 0
00355 && radiusEnt->client
00356 && radiusEnt->client->NPC_class != CLASS_RANCOR
00357 && radiusEnt->client->NPC_class != CLASS_ATST )
00358 {
00359 if ( distSq < halfRadSquared
00360 || radiusEnt->client->ps.groundEntityNum != ENTITYNUM_NONE )
00361 {//within range of my fist or withing ground-shaking range and not in the air
00362 G_Knockdown( radiusEnt );//, NPC, vec3_origin, 100, qtrue );
00363 }
00364 }
00365 }
00366 }
00367 }
|
|
|
Definition at line 196 of file NPC_AI_Rancor.c. References gentity_s::activator, AngleVectors(), BOTH_SWIM_IDLE1, CHAN_AUTO, CLASS_ATST, CLASS_GALAKMECH, CLASS_GONK, CLASS_INTERROGATOR, CLASS_MARK1, CLASS_MARK2, CLASS_MOUSE, CLASS_PROBE, CLASS_R2D2, CLASS_R5D2, CLASS_RANCOR, CLASS_REMOTE, CLASS_SEEKER, CLASS_SENTRY, CLASS_VEHICLE, gentity_s::client, gentity_s::count, entityShared_t::currentOrigin, DAMAGE_NO_ARMOR, DAMAGE_NO_KNOCKBACK, EF2_HELD_BY_MONSTER, playerState_s::eFlags2, gentity_s::enemy, flrand(), playerState_s::forceHandExtend, playerState_s::forceHandExtendTime, G_Damage(), g_entities, G_Knockdown(), G_Sound(), G_SoundIndex(), G_Throw(), gentity_t, HANDEXTEND_NONE, renderInfo_s::handRBolt, playerState_s::hasLookTarget, gentity_s::health, gentity_s::inuse, playerState_s::legsTimer, playerState_s::lookTarget, MOD_MELEE, NPC, gclient_s::NPC_class, NPC_GetEntsNearBolt(), NPC_SetAnim(), NULL, entityState_s::number, gentity_s::pain, PITCH, gclient_s::ps, Q_irand(), qtrue, gentity_s::r, Rancor_DropVictim(), gclient_s::renderInfo, gentity_s::s, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, TIMER_Remove(), TIMER_Set(), vec3_origin, vec3_t, VectorCopy, playerState_s::viewangles, and YAW. Referenced by Rancor_Attack().
00197 {
00198 int radiusEntNums[128];
00199 int numEnts;
00200 const float radius = 88;
00201 const float radiusSquared = (radius*radius);
00202 int i;
00203 vec3_t boltOrg;
00204
00205 numEnts = NPC_GetEntsNearBolt( radiusEntNums, radius, NPC->client->renderInfo.handRBolt, boltOrg );
00206
00207 for ( i = 0; i < numEnts; i++ )
00208 {
00209 gentity_t *radiusEnt = &g_entities[radiusEntNums[i]];
00210 if ( !radiusEnt->inuse )
00211 {
00212 continue;
00213 }
00214
00215 if ( radiusEnt == NPC )
00216 {//Skip the rancor ent
00217 continue;
00218 }
00219
00220 if ( radiusEnt->client == NULL )
00221 {//must be a client
00222 continue;
00223 }
00224
00225 if ( (radiusEnt->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
00226 {//can't be one already being held
00227 continue;
00228 }
00229
00230 if ( DistanceSquared( radiusEnt->r.currentOrigin, boltOrg ) <= radiusSquared )
00231 {
00232 if ( tryGrab
00233 && NPC->count != 1 //don't have one in hand or in mouth already - FIXME: allow one in hand and any number in mouth!
00234 && radiusEnt->client->NPC_class != CLASS_RANCOR
00235 && radiusEnt->client->NPC_class != CLASS_GALAKMECH
00236 && radiusEnt->client->NPC_class != CLASS_ATST
00237 && radiusEnt->client->NPC_class != CLASS_GONK
00238 && radiusEnt->client->NPC_class != CLASS_R2D2
00239 && radiusEnt->client->NPC_class != CLASS_R5D2
00240 && radiusEnt->client->NPC_class != CLASS_MARK1
00241 && radiusEnt->client->NPC_class != CLASS_MARK2
00242 && radiusEnt->client->NPC_class != CLASS_MOUSE
00243 && radiusEnt->client->NPC_class != CLASS_PROBE
00244 && radiusEnt->client->NPC_class != CLASS_SEEKER
00245 && radiusEnt->client->NPC_class != CLASS_REMOTE
00246 && radiusEnt->client->NPC_class != CLASS_SENTRY
00247 && radiusEnt->client->NPC_class != CLASS_INTERROGATOR
00248 && radiusEnt->client->NPC_class != CLASS_VEHICLE )
00249 {//grab
00250 if ( NPC->count == 2 )
00251 {//have one in my mouth, remove him
00252 TIMER_Remove( NPC, "clearGrabbed" );
00253 Rancor_DropVictim( NPC );
00254 }
00255 NPC->enemy = radiusEnt;//make him my new best friend
00256 radiusEnt->client->ps.eFlags2 |= EF2_HELD_BY_MONSTER;
00257 //FIXME: this makes it so that the victim can't hit us with shots! Just use activator or something
00258 radiusEnt->client->ps.hasLookTarget = qtrue;
00259 radiusEnt->client->ps.lookTarget = NPC->s.number;
00260 NPC->activator = radiusEnt;//remember him
00261 NPC->count = 1;//in my hand
00262 //wait to attack
00263 TIMER_Set( NPC, "attacking", NPC->client->ps.legsTimer + Q_irand(500, 2500) );
00264 if ( radiusEnt->health > 0 && radiusEnt->pain )
00265 {//do pain on enemy
00266 radiusEnt->pain( radiusEnt, NPC, 100 );
00267 //GEntity_PainFunc( radiusEnt, NPC, NPC, radiusEnt->r.currentOrigin, 0, MOD_CRUSH );
00268 }
00269 else if ( radiusEnt->client )
00270 {
00271 radiusEnt->client->ps.forceHandExtend = HANDEXTEND_NONE;
00272 radiusEnt->client->ps.forceHandExtendTime = 0;
00273 NPC_SetAnim( radiusEnt, SETANIM_BOTH, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00274 }
00275 }
00276 else
00277 {//smack
00278 vec3_t pushDir;
00279 vec3_t angs;
00280
00281 G_Sound( radiusEnt, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/swipehit.wav" ) );
00282 //actually push the enemy
00283 /*
00284 //VectorSubtract( radiusEnt->r.currentOrigin, boltOrg, pushDir );
00285 VectorSubtract( radiusEnt->r.currentOrigin, NPC->r.currentOrigin, pushDir );
00286 pushDir[2] = Q_flrand( 100, 200 );
00287 VectorNormalize( pushDir );
00288 */
00289 VectorCopy( NPC->client->ps.viewangles, angs );
00290 angs[YAW] += flrand( 25, 50 );
00291 angs[PITCH] = flrand( -25, -15 );
00292 AngleVectors( angs, pushDir, NULL, NULL );
00293 if ( radiusEnt->client->NPC_class != CLASS_RANCOR
00294 && radiusEnt->client->NPC_class != CLASS_ATST )
00295 {
00296 G_Damage( radiusEnt, NPC, NPC, vec3_origin, radiusEnt->r.currentOrigin, Q_irand( 25, 40 ), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_MELEE );
00297 G_Throw( radiusEnt, pushDir, 250 );
00298 if ( radiusEnt->health > 0 )
00299 {//do pain on enemy
00300 G_Knockdown( radiusEnt );//, NPC, pushDir, 100, qtrue );
00301 }
00302 }
00303 }
00304 }
00305 }
00306 }
|
|
|
Definition at line 567 of file g_combat.c. References playerState_s::ammo, weaponData_s::ammoIndex, BG_FindItemForPowerup(), BG_FindItemForWeapon(), entityState_s::bolt2, gentity_s::client, clientPersistant_t::cmd, gentity_s::count, Drop_Item(), EV_DESTROY_WEAPON_MODEL, entityState_s::eventParm, g_gametype, G_TempEntity(), gentity_t, gitem_t, GT_SIEGE, GT_TEAM, vmCvar_t::integer, level, entityState_s::number, gclient_s::pers, playerState_s::powerups, gclient_s::ps, PW_NUM_POWERUPS, gentity_s::r, gentity_s::s, STAT_WEAPONS, playerState_s::stats, SVF_BROADCAST, entityShared_t::svFlags, level_locals_t::time, vec3_origin, usercmd_s::weapon, entityState_s::weapon, WEAPON_DROPPING, weaponData, playerState_s::weaponstate, WP_BRYAR_PISTOL, WP_EMPLACED_GUN, WP_NONE, and WP_TURRET. Referenced by ClientDisconnect(), player_die(), and Rancor_Attack().
00567 {
00568 gitem_t *item;
00569 int weapon;
00570 float angle;
00571 int i;
00572 gentity_t *drop;
00573
00574 if (g_gametype.integer == GT_SIEGE)
00575 { //just don't drop anything then
00576 return;
00577 }
00578
00579 // drop the weapon if not a gauntlet or machinegun
00580 weapon = self->s.weapon;
00581
00582 // make a special check to see if they are changing to a new
00583 // weapon that isn't the mg or gauntlet. Without this, a client
00584 // can pick up a weapon, be killed, and not drop the weapon because
00585 // their weapon change hasn't completed yet and they are still holding the MG.
00586 if ( weapon == WP_BRYAR_PISTOL) {
00587 if ( self->client->ps.weaponstate == WEAPON_DROPPING ) {
00588 weapon = self->client->pers.cmd.weapon;
00589 }
00590 if ( !( self->client->ps.stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
00591 weapon = WP_NONE;
00592 }
00593 }
00594
00595 self->s.bolt2 = weapon;
00596
00597 if ( weapon > WP_BRYAR_PISTOL &&
00598 weapon != WP_EMPLACED_GUN &&
00599 weapon != WP_TURRET &&
00600 self->client->ps.ammo[ weaponData[weapon].ammoIndex ] ) {
00601 gentity_t *te;
00602
00603 // find the item type for this weapon
00604 item = BG_FindItemForWeapon( weapon );
00605
00606 // tell all clients to remove the weapon model on this guy until he respawns
00607 te = G_TempEntity( vec3_origin, EV_DESTROY_WEAPON_MODEL );
00608 te->r.svFlags |= SVF_BROADCAST;
00609 te->s.eventParm = self->s.number;
00610
00611 // spawn the item
00612 Drop_Item( self, item, 0 );
00613 }
00614
00615 // drop all the powerups if not in teamplay
00616 if ( g_gametype.integer != GT_TEAM && g_gametype.integer != GT_SIEGE ) {
00617 angle = 45;
00618 for ( i = 1 ; i < PW_NUM_POWERUPS ; i++ ) {
00619 if ( self->client->ps.powerups[ i ] > level.time ) {
00620 item = BG_FindItemForPowerup( i );
00621 if ( !item ) {
00622 continue;
00623 }
00624 drop = Drop_Item( self, item, angle );
00625 // decide how many seconds it has left
00626 drop->count = ( self->client->ps.powerups[ i ] - level.time ) / 1000;
00627 if ( drop->count < 1 ) {
00628 drop->count = 1;
00629 }
00630 angle += 45;
00631 }
00632 }
00633 }
00634 }
|