static int JPLua_ScreenShake(lua_State *L){ vector3 *origin = JPLua_CheckVector(L, 1); float intense = luaL_checknumber(L, 2); int duration = luaL_checkinteger(L, 3); qboolean global = lua_toboolean(L, 4); G_ScreenShake(origin, NULL, intense, duration, global); return 0; }
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 ); }
static void Howler_Howl( void ) { //gentity_t *radiusEnts[ 128 ]; int radiusEntsNums[128]; gentity_t *ent; int numEnts; const float radius = (NPC->spawnflags&1)?256:128; const float halfRadSquared = ((radius/2)*(radius/2)); const float radiusSquared = (radius*radius); float distSq; int i; vec3_t boltOrg; AddSoundEvent( NPC, NPC->r.currentOrigin, 512, AEL_DANGER, qfalse, qtrue ); //RACC - handLBolt never defined for Howlers? *shrug* just use the tongue base numEnts = NPC_GetEntsNearBolt( radiusEntsNums, radius, NPC->NPC->genericBolt1, boltOrg ); //numEnts = NPC_GetEntsNearBolt( radiusEnts, radius, NPC->handLBolt, boltOrg ); for ( i = 0; i < numEnts; i++ ) { ent = &g_entities[radiusEntsNums[i]]; if ( !ent->inuse ) { continue; } if ( ent == NPC ) {//Skip the rancor ent //RACC - assume this means the source howler continue; } if ( ent->client == NULL ) {//must be a client continue; } if ( ent->client->NPC_class == CLASS_HOWLER ) {//other howlers immune continue; } distSq = DistanceSquared( ent->r.currentOrigin, boltOrg ); if ( distSq <= radiusSquared ) { if ( distSq < halfRadSquared ) {//close enough to do damage, too if ( Q_irand( 0, g_spskill.integer ) ) {//does no damage on easy, does 1 point every other frame on medium, more often on hard //RACC - Impact isn't a MOD in MP. G_Damage( ent, NPC, NPC, vec3_origin, NPC->r.currentOrigin, 1, DAMAGE_NO_KNOCKBACK, MOD_CRUSH ); //G_Damage( ent, NPC, NPC, vec3_origin, NPC->r.currentOrigin, 1, DAMAGE_NO_KNOCKBACK, MOD_IMPACT ); } } if ( ent->health > 0 && ent->client && ent->client->NPC_class != CLASS_RANCOR && ent->client->NPC_class != CLASS_ATST && !PM_InKnockDown( &ent->client->ps ) ) { if ( BG_HasAnimation( ent->localAnimIndex, BOTH_SONICPAIN_START ) ) { if ( ent->client->ps.torsoAnim != BOTH_SONICPAIN_START && ent->client->ps.torsoAnim != BOTH_SONICPAIN_HOLD ) { NPC_SetAnim( ent, SETANIM_LEGS, BOTH_SONICPAIN_START, SETANIM_FLAG_NORMAL ); NPC_SetAnim( ent, SETANIM_TORSO, BOTH_SONICPAIN_START, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); ent->client->ps.torsoTimer += 100; ent->client->ps.weaponTime = ent->client->ps.torsoTimer; } else if ( ent->client->ps.torsoTimer <= 100 ) {//at the end of the sonic pain start or hold anim NPC_SetAnim( ent, SETANIM_LEGS, BOTH_SONICPAIN_HOLD, SETANIM_FLAG_NORMAL ); NPC_SetAnim( ent, SETANIM_TORSO, BOTH_SONICPAIN_HOLD, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); ent->client->ps.torsoTimer += 100; ent->client->ps.weaponTime = ent->client->ps.torsoTimer; } } /* racc - commented out of SP code? else if ( distSq < halfRadSquared && radiusEnts[i]->client->ps.groundEntityNum != ENTITYNUM_NONE && !Q_irand( 0, 10 ) )//FIXME: base on skill {//within range G_Knockdown( radiusEnts[i], NPC, vec3_origin, 500, qfalse ); } */ } } //camera shaking distSq = Distance( boltOrg, ent->r.currentOrigin ); if ( distSq < 256.0f ) { G_ScreenShake(boltOrg, ent, 1.0f*distSq/128.0f, 200, qfalse); } } //RACC - changed to work for multiple players /* playerDist = NPC_EntRangeFromBolt( player, NPC->genericBolt1 ); if ( playerDist < 256.0f ) { CGCam_Shake( 1.0f*playerDist/128.0f, 200 ); } */ }