void Rancor_Bite( void ) { int radiusEntNums[128]; int numEnts; const float radius = 100; const float radiusSquared = (radius*radius); int i; vec3_t boltOrg; numEnts = NPC_GetEntsNearBolt( radiusEntNums, radius, NPCS.NPC->client->renderInfo.crotchBolt, boltOrg );//was gutBolt? for ( i = 0; i < numEnts; i++ ) { gentity_t *radiusEnt = &g_entities[radiusEntNums[i]]; if ( !radiusEnt->inuse ) { continue; } if ( radiusEnt == NPCS.NPC ) {//Skip the rancor ent continue; } if ( radiusEnt->client == NULL ) {//must be a client continue; } if ( (radiusEnt->client->ps.eFlags2&EF2_HELD_BY_MONSTER) ) {//can't be one already being held continue; } if ( DistanceSquared( radiusEnt->r.currentOrigin, boltOrg ) <= radiusSquared ) { G_Damage( radiusEnt, NPCS.NPC, NPCS.NPC, vec3_origin, radiusEnt->r.currentOrigin, Q_irand( 15, 30 ), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_MELEE ); if ( radiusEnt->health <= 0 && radiusEnt->client ) {//killed them, chance of dismembering if ( !Q_irand( 0, 1 ) ) {//bite something off int hitLoc = Q_irand( G2_MODELPART_HEAD, G2_MODELPART_RLEG ); if ( hitLoc == G2_MODELPART_HEAD ) { NPC_SetAnim( radiusEnt, SETANIM_BOTH, BOTH_DEATH17, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); } else if ( hitLoc == G2_MODELPART_WAIST ) { NPC_SetAnim( radiusEnt, SETANIM_BOTH, BOTH_DEATHBACKWARD2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); } //radiusEnt->client->dismembered = qfalse; //FIXME: the limb should just disappear, cuz I ate it G_Dismember( radiusEnt, NPCS.NPC, radiusEnt->r.currentOrigin, hitLoc, 90, 0, radiusEnt->client->ps.torsoAnim, qtrue); //G_DoDismemberment( radiusEnt, radiusEnt->r.currentOrigin, MOD_SABER, 1000, hitLoc, qtrue ); } } G_Sound( radiusEnt, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/chomp.wav" ) ); } } }
void Rancor_Attack( float distance, qboolean doCharge ) { if ( !TIMER_Exists( NPCS.NPC, "attacking" ) ) { if ( NPCS.NPC->count == 2 && NPCS.NPC->activator ) { } else if ( NPCS.NPC->count == 1 && NPCS.NPC->activator ) {//holding enemy if ( NPCS.NPC->activator->health > 0 && Q_irand( 0, 1 ) ) {//quick bite NPC_SetAnim( NPCS.NPC, SETANIM_BOTH, BOTH_ATTACK1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); TIMER_Set( NPCS.NPC, "attack_dmg", 450 ); } else {//full eat NPC_SetAnim( NPCS.NPC, SETANIM_BOTH, BOTH_ATTACK3, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); TIMER_Set( NPCS.NPC, "attack_dmg", 900 ); //Make victim scream in fright if ( NPCS.NPC->activator->health > 0 && NPCS.NPC->activator->client ) { G_AddEvent( NPCS.NPC->activator, Q_irand(EV_DEATH1, EV_DEATH3), 0 ); NPC_SetAnim( NPCS.NPC->activator, SETANIM_TORSO, BOTH_FALLDEATH1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); if ( NPCS.NPC->activator->NPC ) {//no more thinking for you TossClientItems( NPCS.NPC ); NPCS.NPC->activator->NPC->nextBStateThink = Q3_INFINITE; } } } } else if ( NPCS.NPC->enemy->health > 0 && doCharge ) {//charge vec3_t fwd, yawAng; VectorSet( yawAng, 0, NPCS.NPC->client->ps.viewangles[YAW], 0 ); AngleVectors( yawAng, fwd, NULL, NULL ); VectorScale( fwd, distance*1.5f, NPCS.NPC->client->ps.velocity ); NPCS.NPC->client->ps.velocity[2] = 150; NPCS.NPC->client->ps.groundEntityNum = ENTITYNUM_NONE; NPC_SetAnim( NPCS.NPC, SETANIM_BOTH, BOTH_MELEE2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); TIMER_Set( NPCS.NPC, "attack_dmg", 1250 ); } else if ( !Q_irand(0, 1) ) {//smash NPC_SetAnim( NPCS.NPC, SETANIM_BOTH, BOTH_MELEE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); TIMER_Set( NPCS.NPC, "attack_dmg", 1000 ); } else {//try to grab NPC_SetAnim( NPCS.NPC, SETANIM_BOTH, BOTH_ATTACK2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); TIMER_Set( NPCS.NPC, "attack_dmg", 1000 ); } TIMER_Set( NPCS.NPC, "attacking", NPCS.NPC->client->ps.legsTimer + random() * 200 ); } // Need to do delayed damage since the attack animations encapsulate multiple mini-attacks if ( TIMER_Done2( NPCS.NPC, "attack_dmg", qtrue ) ) { vec3_t shakePos; switch ( NPCS.NPC->client->ps.legsAnim ) { case BOTH_MELEE1: Rancor_Smash(); G_GetBoltPosition( NPCS.NPC, NPCS.NPC->client->renderInfo.handLBolt, shakePos, 0 ); G_ScreenShake( shakePos, NULL, 4.0f, 1000, qfalse ); //CGCam_Shake( 1.0f*playerDist/128.0f, 1000 ); break; case BOTH_MELEE2: Rancor_Bite(); TIMER_Set( NPCS.NPC, "attack_dmg2", 450 ); break; case BOTH_ATTACK1: if ( NPCS.NPC->count == 1 && NPCS.NPC->activator ) { G_Damage( NPCS.NPC->activator, NPCS.NPC, NPCS.NPC, vec3_origin, NPCS.NPC->activator->r.currentOrigin, Q_irand( 25, 40 ), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_MELEE ); if ( NPCS.NPC->activator->health <= 0 ) {//killed him //make it look like we bit his head off //NPC->activator->client->dismembered = qfalse; G_Dismember( NPCS.NPC->activator, NPCS.NPC, NPCS.NPC->activator->r.currentOrigin, G2_MODELPART_HEAD, 90, 0, NPCS.NPC->activator->client->ps.torsoAnim, qtrue); //G_DoDismemberment( NPC->activator, NPC->activator->r.currentOrigin, MOD_SABER, 1000, HL_HEAD, qtrue ); NPCS.NPC->activator->client->ps.forceHandExtend = HANDEXTEND_NONE; NPCS.NPC->activator->client->ps.forceHandExtendTime = 0; NPC_SetAnim( NPCS.NPC->activator, SETANIM_BOTH, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); } G_Sound( NPCS.NPC->activator, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/chomp.wav" ) ); } break; case BOTH_ATTACK2: //try to grab Rancor_Swing( qtrue ); break; case BOTH_ATTACK3: if ( NPCS.NPC->count == 1 && NPCS.NPC->activator ) { //cut in half if ( NPCS.NPC->activator->client ) { //NPC->activator->client->dismembered = qfalse; G_Dismember( NPCS.NPC->activator, NPCS.NPC, NPCS.NPC->activator->r.currentOrigin, G2_MODELPART_WAIST, 90, 0, NPCS.NPC->activator->client->ps.torsoAnim, qtrue); //G_DoDismemberment( NPC->activator, NPC->enemy->r.currentOrigin, MOD_SABER, 1000, HL_WAIST, qtrue ); } //KILL G_Damage( NPCS.NPC->activator, NPCS.NPC, NPCS.NPC, vec3_origin, NPCS.NPC->activator->r.currentOrigin, NPCS.NPC->enemy->health+10, DAMAGE_NO_PROTECTION|DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, MOD_MELEE );//, HL_NONE );// if ( NPCS.NPC->activator->client ) { NPCS.NPC->activator->client->ps.forceHandExtend = HANDEXTEND_NONE; NPCS.NPC->activator->client->ps.forceHandExtendTime = 0; NPC_SetAnim( NPCS.NPC->activator, SETANIM_BOTH, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); } TIMER_Set( NPCS.NPC, "attack_dmg2", 1350 ); G_Sound( NPCS.NPC->activator, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/swipehit.wav" ) ); G_AddEvent( NPCS.NPC->activator, EV_JUMP, NPCS.NPC->activator->health ); } break; } } else if ( TIMER_Done2( NPCS.NPC, "attack_dmg2", qtrue ) ) { switch ( NPCS.NPC->client->ps.legsAnim ) { case BOTH_MELEE1: break; case BOTH_MELEE2: Rancor_Bite(); break; case BOTH_ATTACK1: break; case BOTH_ATTACK2: break; case BOTH_ATTACK3: if ( NPCS.NPC->count == 1 && NPCS.NPC->activator ) {//swallow victim G_Sound( NPCS.NPC->activator, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/chomp.wav" ) ); //FIXME: sometimes end up with a live one in our mouths? //just make sure they're dead if ( NPCS.NPC->activator->health > 0 ) { //cut in half //NPC->activator->client->dismembered = qfalse; G_Dismember( NPCS.NPC->activator, NPCS.NPC, NPCS.NPC->activator->r.currentOrigin, G2_MODELPART_WAIST, 90, 0, NPCS.NPC->activator->client->ps.torsoAnim, qtrue); //G_DoDismemberment( NPC->activator, NPC->enemy->r.currentOrigin, MOD_SABER, 1000, HL_WAIST, qtrue ); //KILL G_Damage( NPCS.NPC->activator, NPCS.NPC, NPCS.NPC, vec3_origin, NPCS.NPC->activator->r.currentOrigin, NPCS.NPC->enemy->health+10, DAMAGE_NO_PROTECTION|DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, MOD_MELEE );//, HL_NONE ); NPCS.NPC->activator->client->ps.forceHandExtend = HANDEXTEND_NONE; NPCS.NPC->activator->client->ps.forceHandExtendTime = 0; NPC_SetAnim( NPCS.NPC->activator, SETANIM_BOTH, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); G_AddEvent( NPCS.NPC->activator, EV_JUMP, NPCS.NPC->activator->health ); } if ( NPCS.NPC->activator->client ) {//*sigh*, can't get tags right, just remove them? NPCS.NPC->activator->client->ps.eFlags |= EF_NODRAW; } NPCS.NPC->count = 2; TIMER_Set( NPCS.NPC, "clearGrabbed", 2600 ); } break; } } else if ( NPCS.NPC->client->ps.legsAnim == BOTH_ATTACK2 ) { if ( NPCS.NPC->client->ps.legsTimer >= 1200 && NPCS.NPC->client->ps.legsTimer <= 1350 ) { if ( Q_irand( 0, 2 ) ) { Rancor_Swing( qfalse ); } else { Rancor_Swing( qtrue ); } } else if ( NPCS.NPC->client->ps.legsTimer >= 1100 && NPCS.NPC->client->ps.legsTimer <= 1550 ) { Rancor_Swing( qtrue ); } } // Just using this to remove the attacking flag at the right time TIMER_Done2( NPCS.NPC, "attacking", qtrue ); }
void Wampa_Slash( int boltIndex, qboolean backhand ) { int radiusEntNums[128]; int numEnts; const float radius = 88; const float radiusSquared = (radius*radius); int i; vec3_t boltOrg; int damage = (backhand)?Q_irand(10,15):Q_irand(20,30); numEnts = NPC_GetEntsNearBolt( radiusEntNums, radius, boltIndex, boltOrg ); for ( i = 0; i < numEnts; i++ ) { gentity_t *radiusEnt = &g_entities[radiusEntNums[i]]; if ( !radiusEnt->inuse ) { continue; } if ( radiusEnt == NPC ) {//Skip the wampa ent continue; } if ( radiusEnt->client == NULL ) {//must be a client continue; } if ( DistanceSquared( radiusEnt->r.currentOrigin, boltOrg ) <= radiusSquared ) { //smack G_Damage( radiusEnt, NPC, NPC, vec3_origin, radiusEnt->r.currentOrigin, damage, ((backhand)?DAMAGE_NO_ARMOR:(DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK)), MOD_MELEE ); if ( backhand ) { //actually push the enemy vec3_t pushDir; vec3_t angs; VectorCopy( NPC->client->ps.viewangles, angs ); angs[YAW] += flrand( 25, 50 ); angs[PITCH] = flrand( -25, -15 ); AngleVectors( angs, pushDir, NULL, NULL ); if ( radiusEnt->client->NPC_class != CLASS_WAMPA && radiusEnt->client->NPC_class != CLASS_RANCOR && radiusEnt->client->NPC_class != CLASS_ATST ) { G_Throw( radiusEnt, pushDir, 65 ); if ( BG_KnockDownable(&radiusEnt->client->ps) && radiusEnt->health > 0 && Q_irand( 0, 1 ) ) {//do pain on enemy radiusEnt->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN; radiusEnt->client->ps.forceDodgeAnim = 0; radiusEnt->client->ps.forceHandExtendTime = level.time + 1100; radiusEnt->client->ps.quickerGetup = qfalse; } } } else if ( radiusEnt->health <= 0 && radiusEnt->client ) {//killed them, chance of dismembering if ( !Q_irand( 0, 1 ) ) {//bite something off int hitLoc = Q_irand( G2_MODELPART_HEAD, G2_MODELPART_RLEG ); if ( hitLoc == G2_MODELPART_HEAD ) { NPC_SetAnim( radiusEnt, SETANIM_BOTH, BOTH_DEATH17, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); } else if ( hitLoc == G2_MODELPART_WAIST ) { NPC_SetAnim( radiusEnt, SETANIM_BOTH, BOTH_DEATHBACKWARD2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); } G_Dismember( radiusEnt, NPC, radiusEnt->r.currentOrigin, hitLoc, 90, 0, radiusEnt->client->ps.torsoAnim, qtrue); } } else if ( !Q_irand( 0, 3 ) && radiusEnt->health > 0 ) {//one out of every 4 normal hits does a knockdown, too vec3_t pushDir; vec3_t angs; VectorCopy( NPC->client->ps.viewangles, angs ); angs[YAW] += flrand( 25, 50 ); angs[PITCH] = flrand( -25, -15 ); AngleVectors( angs, pushDir, NULL, NULL ); //[KnockdownSys] //ported multi-direction knockdowns from SP. G_Knockdown( radiusEnt, NPC, pushDir, 35, qtrue ); //G_Knockdown( radiusEnt ); //[/KnockdownSys] } G_Sound( radiusEnt, CHAN_WEAPON, G_SoundIndex( "sound/chars/rancor/swipehit.wav" ) ); } } }