//========================================================= // MeleeAttack1() // Ataque cuerpo a cuerpo #1 // En este caso: //========================================================= void CNPC_Scient::MeleeAttack1() { /* Ataque cuerpo a cuerpo ¡Ejemplo! En este código el NPC aventará y empujara al usuario con un golpe. Esto es solo un ejemplo, modifique o elimine. */ // Atacar CBaseEntity *pHurt = CheckTraceHullAttack(70, Vector(-16,-16,-16), Vector(16,16,16), sk_grunt_dmg_high.GetFloat(), DMG_SLASH | DMG_ALWAYSGIB); // ¿Le hice daño? if (pHurt) { Vector forward, up; AngleVectors(GetAbsAngles(), &forward, NULL, &up); // Aturdirlo if (pHurt->GetFlags() & (FL_NPC | FL_CLIENT)) pHurt->ViewPunch(QAngle(70, 0, -70)); // Aventarlo por los aires. pHurt->ApplyAbsVelocityImpulse(400 * (up + 1*forward)); } AttackSound(); }
//========================================================= // GetSchedule - Decides which type of schedule best suits // the monster's current state and conditions. Then calls // monster's member function to get a pointer to a schedule // of the proper type. //========================================================= Schedule_t *CAGrunt :: GetSchedule ( void ) { if ( HasConditions(bits_COND_HEAR_SOUND) ) { CSound *pSound; pSound = PBestSound(); ASSERT( pSound != NULL ); if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) { // dangerous sound nearby! return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); } } switch ( m_MonsterState ) { case MONSTERSTATE_COMBAT: { // dead enemy if ( HasConditions( bits_COND_ENEMY_DEAD ) ) { // call base class, all code to handle dead enemies is centralized there. return CBaseMonster :: GetSchedule(); } if ( HasConditions(bits_COND_NEW_ENEMY) ) { return GetScheduleOfType( SCHED_WAKE_ANGRY ); } // zap player! if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) ) { AttackSound();// this is a total hack. Should be parto f the schedule return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); } if ( HasConditions ( bits_COND_HEAVY_DAMAGE ) ) { return GetScheduleOfType( SCHED_SMALL_FLINCH ); } // can attack if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) && OccupySlot ( bits_SLOTS_AGRUNT_HORNET ) ) { return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); } if ( OccupySlot ( bits_SLOT_AGRUNT_CHASE ) ) { return GetScheduleOfType ( SCHED_CHASE_ENEMY ); } return GetScheduleOfType ( SCHED_STANDOFF ); } } return CSquadMonster :: GetSchedule(); }
void CLeech::HandleAnimEvent(MonsterEvent_t *pEvent) { switch(pEvent->event) { case LEECH_AE_ATTACK: AttackSound(); CBaseEntity *pEnemy; pEnemy = m_hEnemy; if(pEnemy != NULL) { Vector dir, face; UTIL_MakeVectorsPrivate(pev->angles, face, NULL, NULL); face.z = 0; dir = (pEnemy->pev->origin - pev->origin); dir.z = 0; dir = dir.Normalize(); face = face.Normalize(); if(DotProduct(dir, face) > 0.9) // Only take damage if the leech is facing the prey pEnemy->TakeDamage(pev, pev, gSkillData.leechDmgBite, DMG_SLASH); } m_stateTime -= 2; break; case LEECH_AE_FLOP: // Play flop sound break; default: CBaseMonster::HandleAnimEvent(pEvent); break; } }
void CRocketLauncher::Fire (CPlayerEntity *Player) { vec3f offset (8, 8, Player->ViewHeight-8), start; const sint32 damage = CalcQuadVal(100 + (sint32)(frand() * 20.0)), radius_damage = CalcQuadVal(120); const float damage_radius = 120; anglef angles = Player->Client.ViewAngle.ToVectors (); Player->Client.KickOrigin = angles.Forward * -2; Player->Client.KickAngles.X = -1; Player->P_ProjectSource (offset, angles, start); CRocket::Spawn (Player, start, angles.Forward, damage, 650, damage_radius, radius_damage); // send muzzle flash Muzzle (Player, MZ_ROCKET); AttackSound (Player); Player->PlayerNoiseAt (start, PNOISE_WEAPON); FireAnimation (Player); DepleteAmmo(Player, 1); Player->Client.PlayerState.GetGunFrame()++; }
//========================================================= // GetSchedule - Decides which type of schedule best suits // the monster's current state and conditions. Then calls // monster's member function to get a pointer to a schedule // of the proper type. //========================================================= int CNPC_AlienGrunt::SelectSchedule( void ) { if ( HasCondition( COND_HEAR_DANGER ) ) { return SCHED_TAKE_COVER_FROM_BEST_SOUND; } switch ( m_NPCState ) { case NPC_STATE_COMBAT: { // dead enemy if ( HasCondition( COND_ENEMY_DEAD ) ) { // call base class, all code to handle dead enemies is centralized there. return BaseClass::SelectSchedule(); } if ( HasCondition( COND_NEW_ENEMY) ) { return SCHED_WAKE_ANGRY; } // zap player! if ( HasCondition ( COND_CAN_MELEE_ATTACK1 ) ) { AttackSound();// this is a total hack. Should be parto f the schedule return SCHED_MELEE_ATTACK1; } if ( HasCondition ( COND_HEAVY_DAMAGE ) ) { return SCHED_SMALL_FLINCH; } // can attack if ( HasCondition ( COND_CAN_RANGE_ATTACK1 ) && OccupyStrategySlotRange( AGRUNT_SQUAD_SLOT_HORNET1, AGRUNT_SQUAD_SLOT_HORNET2 ) ) { return SCHED_RANGE_ATTACK1; } if ( OccupyStrategySlot ( AGRUNT_SQUAD_SLOT_CHASE ) ) { return SCHED_CHASE_ENEMY; } return SCHED_STANDOFF; } } return BaseClass::SelectSchedule(); }
//========================================================= //========================================================= Schedule_t* CIchthyosaur :: GetScheduleOfType ( int Type ) { // ALERT( at_console, "GetScheduleOfType( %d ) %d\n", Type, m_bOnAttack ); switch ( Type ) { case SCHED_IDLE_WALK: return slSwimAround; case SCHED_STANDOFF: return slCircleEnemy; case SCHED_FAIL: return slSwimAgitated; case SCHED_DIE: return slTwitchDie; case SCHED_CHASE_ENEMY: AttackSound( ); } return CBaseMonster :: GetScheduleOfType( Type ); }
void CASW_Harvester::HandleAnimEvent( animevent_t *pEvent ) { int nEvent = pEvent->Event(); if ( nEvent == AE_HARVESTER_SPAWN_CRITTER ) { // The point in our laying animation where we should actually spawn the critter SpawnAlien(); float spawn_interval = asw_harvester_spawn_interval.GetFloat(); m_flNextAttack = gpGlobals->curtime + spawn_interval; return; } if ( nEvent == AE_HARVESTER_SPAWN_SOUND ) { AttackSound(); return; } BaseClass::HandleAnimEvent( pEvent ); }
void CProxLauncher::Fire (CPlayerEntity *Player) { vec3f offset (8, 8, Player->ViewHeight-8), start; FireAnimation (Player); anglef angles = Player->Client.ViewAngle.ToVectors(); Player->P_ProjectSource (offset, angles, start); Player->Client.KickOrigin = angles.Forward * -2; Player->Client.KickAngles.X = -1; CProx::Spawn (Player, start, angles.Forward, DamageMultiplier, 600); Muzzle (Player, MZ_GRENADE); AttackSound (Player); Player->PlayerNoiseAt (start, PNOISE_WEAPON); DepleteAmmo(Player, 1); Player->Client.PlayerState.GetGunFrame()++; }
void CLeech::HandleAnimEvent( AnimEvent_t& event ) { switch( event.event ) { case LEECH_AE_ATTACK: AttackSound(); CBaseEntity *pEnemy; pEnemy = m_hEnemy; if ( pEnemy != NULL ) { Vector dir, face; UTIL_MakeVectorsPrivate( pev->angles, &face, nullptr, nullptr ); face.z = 0; dir = (pEnemy->GetAbsOrigin() - GetAbsOrigin()); dir.z = 0; dir = dir.Normalize(); face = face.Normalize(); if ( DotProduct(dir, face) > 0.9 ) // Only take damage if the leech is facing the prey pEnemy->TakeDamage( this, this, gSkillData.GetLeechDmgBite(), DMG_SLASH ); } m_stateTime -= 2; break; case LEECH_AE_FLOP: // Play flop sound break; default: CBaseMonster::HandleAnimEvent( event ); break; } }
//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= void CNPC_Controller::HandleAnimEvent( animevent_t *pEvent ) { switch( pEvent->event ) { case CONTROLLER_AE_HEAD_OPEN: { Vector vecStart; QAngle angleGun; GetAttachment( 0, vecStart, angleGun ); // BUGBUG - attach to attachment point! CBroadcastRecipientFilter filter; te->DynamicLight( filter, 0.0, &vecStart, 255, 192, 64, 0, 1 /*radius*/, 0.2, -32 ); m_iBall[0] = 192; m_iBallTime[0] = gpGlobals->curtime + atoi( pEvent->options ) / 15.0; m_iBall[1] = 255; m_iBallTime[1] = gpGlobals->curtime + atoi( pEvent->options ) / 15.0; } break; case CONTROLLER_AE_BALL_SHOOT: { Vector vecStart; QAngle angleGun; GetAttachment( 1, vecStart, angleGun ); CBroadcastRecipientFilter filter; te->DynamicLight( filter, 0.0, &vecStart, 255, 192, 64, 0, 1 /*radius*/, 0.1, 32 ); CAI_BaseNPC *pBall = (CAI_BaseNPC*)Create( "controller_head_ball", vecStart, angleGun ); pBall->SetAbsVelocity( Vector(0,0,32) ); pBall->SetEnemy( GetEnemy() ); // DevMsg( 1, "controller shooting head ball\n" ); m_iBall[0] = 0; m_iBall[1] = 0; } break; case CONTROLLER_AE_SMALL_SHOOT: { AttackSound( ); m_flShootTime = gpGlobals->curtime; m_flShootEnd = m_flShootTime + atoi( pEvent->options ) / 15.0; } break; case CONTROLLER_AE_POWERUP_FULL: { m_iBall[0] = 255; m_iBallTime[0] = gpGlobals->curtime + atoi( pEvent->options ) / 15.0; m_iBall[1] = 255; m_iBallTime[1] = gpGlobals->curtime + atoi( pEvent->options ) / 15.0; } break; case CONTROLLER_AE_POWERUP_HALF: { m_iBall[0] = 192; m_iBallTime[0] = gpGlobals->curtime + atoi( pEvent->options ) / 15.0; m_iBall[1] = 192; m_iBallTime[1] = gpGlobals->curtime + atoi( pEvent->options ) / 15.0; } break; default: BaseClass::HandleAnimEvent( pEvent ); break; } }
//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= void CZombie :: HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { case ZOMBIE_AE_ATTACK_RANGE: { Vector vecToss; UTIL_MakeAimVectors ( pev->angles ); vecToss = VecCheckThrow( pev, GetGunPosition(), m_vecEnemyLKP, 750, 1 ); AttackMissSound(); CGuts::ShootGuts(pev, GetGunPosition(), vecToss); } break; case ZOMBIE_AE_ATTACK_RIGHT: { // do stuff for this event. CBaseEntity *pHurt = CheckTraceHullAttack( 70, zombie_dmg_melee.value, DMG_SLASH ); if ( pHurt ) { if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) { pHurt->pev->punchangle.z = -18; pHurt->pev->punchangle.x = 5; pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 100; } AttackHitSound(); } else AttackMissSound(); if (RANDOM_LONG(0,1)) AttackSound(); } break; case ZOMBIE_AE_ATTACK_LEFT: { // do stuff for this event. CBaseEntity *pHurt = CheckTraceHullAttack( 70, zombie_dmg_melee.value, DMG_SLASH ); if ( pHurt ) { if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) { pHurt->pev->punchangle.z = 18; pHurt->pev->punchangle.x = 5; pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 100; } AttackHitSound(); } else AttackMissSound(); if (RANDOM_LONG(0,1)) AttackSound(); } break; case ZOMBIE_AE_ATTACK_BOTH: { // do stuff for this event. CBaseEntity *pHurt = CheckTraceHullAttack( 70, zombie_dmg_melee.value*2, DMG_SLASH ); if ( pHurt ) { if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) { pHurt->pev->punchangle.x = 5; pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * -100; } AttackHitSound(); } else AttackMissSound(); if (RANDOM_LONG(0,1)) AttackSound(); } break; default: CBaseMonster::HandleAnimEvent( pEvent ); break; } }
//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= void CController :: HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { case CONTROLLER_AE_HEAD_OPEN: { //ALERT(at_console,"Controller Head Open\n"); Vector vecStart, angleGun; GetAttachment( 0, vecStart, angleGun ); MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_ELIGHT ); WRITE_SHORT( entindex( ) + 0x1000 ); // entity, attachment WRITE_COORD( vecStart.x ); // origin WRITE_COORD( vecStart.y ); WRITE_COORD( vecStart.z ); WRITE_COORD( 1 ); // radius WRITE_BYTE( 255 ); // R WRITE_BYTE( 192 ); // G WRITE_BYTE( 64 ); // B WRITE_BYTE( 20 ); // life * 10 WRITE_COORD( -32 ); // decay MESSAGE_END(); m_iBall[0] = 192; m_iBallTime[0] = gpGlobals->time + atoi( pEvent->options ) / 15.0; m_iBall[1] = 255; m_iBallTime[1] = gpGlobals->time + atoi( pEvent->options ) / 15.0; } break; case CONTROLLER_AE_BALL_SHOOT: { //ALERT(at_console,"Controller Ball Shoot\n"); Vector vecStart, angleGun; GetAttachment( 0, vecStart, angleGun ); MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_ELIGHT ); WRITE_SHORT( entindex( ) + 0x1000 ); // entity, attachment WRITE_COORD( 0 ); // origin WRITE_COORD( 0 ); WRITE_COORD( 0 ); WRITE_COORD( 32 ); // radius WRITE_BYTE( 255 ); // R WRITE_BYTE( 192 ); // G WRITE_BYTE( 64 ); // B WRITE_BYTE( 10 ); // life * 10 WRITE_COORD( 32 ); // decay MESSAGE_END(); CBaseMonster *pBall = (CBaseMonster*)Create( "controller_head_ball", vecStart, pev->angles, edict() ); pBall->pev->velocity = Vector( 0, 0, 32 ); if (m_pCine) { pBall->m_hEnemy = m_hTargetEnt; } else { pBall->m_hEnemy = m_hEnemy; } m_iBall[0] = 0; m_iBall[1] = 0; } break; case CONTROLLER_AE_SMALL_SHOOT: { //ALERT(at_console,"Controller Small Shoot\n"); AttackSound( ); m_flShootTime = gpGlobals->time; m_flShootEnd = m_flShootTime + atoi( pEvent->options ) / 15.0; } break; case CONTROLLER_AE_POWERUP_FULL: { //ALERT(at_console,"Controller Powerup Full\n"); m_iBall[0] = 255; m_iBallTime[0] = gpGlobals->time + atoi( pEvent->options ) / 15.0; m_iBall[1] = 255; m_iBallTime[1] = gpGlobals->time + atoi( pEvent->options ) / 15.0; } break; case CONTROLLER_AE_POWERUP_HALF: { //ALERT(at_console,"Controller Powerup Half\n"); m_iBall[0] = 192; m_iBallTime[0] = gpGlobals->time + atoi( pEvent->options ) / 15.0; m_iBall[1] = 192; m_iBallTime[1] = gpGlobals->time + atoi( pEvent->options ) / 15.0; } break; default: CBaseMonster::HandleAnimEvent( pEvent ); break; } }
//----------------------------------------------------------------------------- // Purpose: Does a jump attack at the given position. // Input : bRandomJump - Just hop in a random direction. // vecPos - Position to jump at, ignored if bRandom is set to true. // bThrown - //----------------------------------------------------------------------------- void CASW_Parasite::JumpAttack( bool bRandomJump, const Vector &vecPos, bool bThrown ) { Vector vecJumpVel; if ( !bRandomJump ) { float gravity = sv_gravity.GetFloat(); if ( gravity <= 1 ) { gravity = 1; } // How fast does the headcrab need to travel to reach the position given gravity? float flActualHeight = vecPos.z - GetAbsOrigin().z; float height = flActualHeight; if ( height < 16 ) { height = 60; //16; } else { float flMaxHeight = bThrown ? 400 : 120; if ( height > flMaxHeight ) { height = flMaxHeight; } } // overshoot the jump by an additional 8 inches // NOTE: This calculation jumps at a position INSIDE the box of the enemy (player) // so if you make the additional height too high, the crab can land on top of the // enemy's head. If we want to jump high, we'll need to move vecPos to the surface/outside // of the enemy's box. float additionalHeight = 0; if ( height < 32 ) { additionalHeight = 8; } height += additionalHeight; // NOTE: This equation here is from vf^2 = vi^2 + 2*a*d float speed = sqrt( 2 * gravity * height ); float time = speed / gravity; // add in the time it takes to fall the additional height // So the impact takes place on the downward slope at the original height time += sqrt( (2 * additionalHeight) / gravity ); // Scale the sideways velocity to get there at the right time VectorSubtract( vecPos, GetAbsOrigin(), vecJumpVel ); vecJumpVel /= time; // Speed to offset gravity at the desired height. vecJumpVel.z = speed; // Don't jump too far/fast. float flJumpSpeed = vecJumpVel.Length(); float flMaxSpeed = bThrown ? 1000.0f : 650.0f; if ( flJumpSpeed > flMaxSpeed ) { vecJumpVel *= flMaxSpeed / flJumpSpeed; } } else { // // Jump hop, don't care where. // Vector forward, up; AngleVectors( GetLocalAngles(), &forward, NULL, &up ); vecJumpVel = Vector( forward.x, forward.y, up.z ) * 350; } AttackSound(); Leap( vecJumpVel ); }
void CController :: HandleAnimEvent( AnimEvent_t& event ) { switch( event.event ) { case CONTROLLER_AE_HEAD_OPEN: { Vector vecStart, angleGun; GetAttachment( 0, vecStart, angleGun ); MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_ELIGHT ); WRITE_SHORT( entindex( ) + 0x1000 ); // entity, attachment WRITE_COORD( vecStart.x ); // origin WRITE_COORD( vecStart.y ); WRITE_COORD( vecStart.z ); WRITE_COORD( 1 ); // radius WRITE_BYTE( 255 ); // R WRITE_BYTE( 192 ); // G WRITE_BYTE( 64 ); // B WRITE_BYTE( 20 ); // life * 10 WRITE_COORD( -32 ); // decay MESSAGE_END(); m_iBall[0] = 192; m_iBallTime[0] = gpGlobals->time + atoi( event.options ) / 15.0; m_iBall[1] = 255; m_iBallTime[1] = gpGlobals->time + atoi( event.options ) / 15.0; } break; case CONTROLLER_AE_BALL_SHOOT: { Vector vecStart, angleGun; GetAttachment( 0, vecStart, angleGun ); MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_ELIGHT ); WRITE_SHORT( entindex( ) + 0x1000 ); // entity, attachment WRITE_COORD( 0 ); // origin WRITE_COORD( 0 ); WRITE_COORD( 0 ); WRITE_COORD( 32 ); // radius WRITE_BYTE( 255 ); // R WRITE_BYTE( 192 ); // G WRITE_BYTE( 64 ); // B WRITE_BYTE( 10 ); // life * 10 WRITE_COORD( 32 ); // decay MESSAGE_END(); CBaseMonster *pBall = (CBaseMonster*)Create( "controller_head_ball", vecStart, GetAbsAngles(), edict() ); pBall->SetAbsVelocity( Vector( 0, 0, 32 ) ); pBall->m_hEnemy = m_hEnemy; m_iBall[0] = 0; m_iBall[1] = 0; } break; case CONTROLLER_AE_SMALL_SHOOT: { AttackSound( ); m_flShootTime = gpGlobals->time; m_flShootEnd = m_flShootTime + atoi( event.options ) / 15.0; } break; case CONTROLLER_AE_POWERUP_FULL: { m_iBall[0] = 255; m_iBallTime[0] = gpGlobals->time + atoi( event.options ) / 15.0; m_iBall[1] = 255; m_iBallTime[1] = gpGlobals->time + atoi( event.options ) / 15.0; } break; case CONTROLLER_AE_POWERUP_HALF: { m_iBall[0] = 192; m_iBallTime[0] = gpGlobals->time + atoi( event.options ) / 15.0; m_iBall[1] = 192; m_iBallTime[1] = gpGlobals->time + atoi( event.options ) / 15.0; } break; default: CBaseMonster::HandleAnimEvent( event ); break; } }
//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= void CNPC_Bullsquid::HandleAnimEvent( animevent_t *pEvent ) { switch( pEvent->event ) { case BSQUID_AE_SPIT: { if ( GetEnemy() ) { Vector vSpitPos; QAngle vSpitAngle; GetAttachment( "Mouth", vSpitPos, vSpitAngle); Vector vTarget = GetEnemy()->GetAbsOrigin(); Vector vToss; CBaseEntity* pBlocker; float flGravity = sv_gravity.GetFloat() * SPIT_GRAVITY; ThrowLimit(vSpitPos, vTarget, flGravity, 3, Vector(0,0,0), Vector(0,0,0), GetEnemy(), &vToss, &pBlocker); CGrenadeSpit *pGrenade = (CGrenadeSpit*)CreateNoSpawn( "grenade_spit", vSpitPos, vec3_angle, this ); //pGrenade->KeyValue( "velocity", vToss ); pGrenade->Spawn( ); pGrenade->SetOwner( this ); pGrenade->SetOwnerEntity( this ); pGrenade->SetSpitSize( 2 ); pGrenade->SetAbsVelocity( vToss ); // Tumble through the air pGrenade->SetLocalAngularVelocity( QAngle( random->RandomFloat ( -100, -500 ), random->RandomFloat ( -100, -500 ), random->RandomFloat ( -100, -500 ) ) ); AttackSound(); CPVSFilter filter( vSpitPos ); te->SpriteSpray( filter, 0.0, &vSpitPos, &vToss, m_nSquidSpitSprite, 5, 10, 15 ); } } break; case BSQUID_AE_BITE: { // SOUND HERE! CBaseEntity *pHurt = CheckTraceHullAttack( 70, Vector(-16,-16,-16), Vector(16,16,16), sk_bullsquid_dmg_bite.GetFloat(), DMG_SLASH ); if ( pHurt ) { Vector forward, up; AngleVectors( GetAbsAngles(), &forward, NULL, &up ); pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() - (forward * 100) ); pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (up * 100) ); pHurt->RemoveFlag( FL_ONGROUND ); } } break; case BSQUID_AE_WHIP_SND: { EmitSound( "NPC_Bullsquid.TailWhip" ); break; } /* case BSQUID_AE_TAILWHIP: { CBaseEntity *pHurt = CheckTraceHullAttack( 70, Vector(-16,-16,-16), Vector(16,16,16), sk_bullsquid_dmg_whip.GetFloat(), DMG_SLASH | DMG_ALWAYSGIB ); if ( pHurt ) { Vector right, up; AngleVectors( GetAbsAngles(), NULL, &right, &up ); if ( pHurt->GetFlags() & ( FL_NPC | FL_CLIENT ) ) pHurt->ViewPunch( QAngle( 20, 0, -20 ) ); pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (right * 200) ); pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (up * 100) ); } } break; */ case BSQUID_AE_BLINK: { // close eye. m_nSkin = 1; } break; case BSQUID_AE_HOP: { float flGravity = sv_gravity.GetFloat(); // throw the squid up into the air on this frame. if ( GetFlags() & FL_ONGROUND ) { RemoveFlag( FL_ONGROUND ); } // jump into air for 0.8 (24/30) seconds Vector vecVel = GetAbsVelocity(); vecVel.z += ( 0.625 * flGravity ) * 0.5; SetAbsVelocity( vecVel ); } break; case BSQUID_AE_THROW: { // squid throws its prey IF the prey is a client. CBaseEntity *pHurt = CheckTraceHullAttack( 70, Vector(-16,-16,-16), Vector(16,16,16), 0, 0 ); if ( pHurt ) { pHurt->ViewPunch( QAngle(20,0,-20) ); // screeshake transforms the viewmodel as well as the viewangle. No problems with seeing the ends of the viewmodels. UTIL_ScreenShake( pHurt->GetAbsOrigin(), 25.0, 1.5, 0.7, 2, SHAKE_START ); // If the player, throw him around if ( pHurt->IsPlayer()) { Vector forward, up; AngleVectors( GetLocalAngles(), &forward, NULL, &up ); pHurt->ApplyAbsVelocityImpulse( forward * 300 + up * 300 ); } // If not the player see if has bullsquid throw interatcion else { CBaseCombatCharacter *pVictim = ToBaseCombatCharacter( pHurt ); if (pVictim) { if ( pVictim->HandleInteraction( g_interactionBullsquidThrow, NULL, this ) ) { Vector forward, up; AngleVectors( GetLocalAngles(), &forward, NULL, &up ); pVictim->ApplyAbsVelocityImpulse( forward * 300 + up * 250 ); } } } } } break; default: BaseClass::HandleAnimEvent( pEvent ); } }
void CASW_Simple_Alien::MeleeAttack( float distance, float damage, QAngle &viewPunch, Vector &shove ) { Vector vecForceDir; // Always hurt bullseyes for now if ( ( GetEnemy() != NULL ) && ( GetEnemy()->Classify() == CLASS_BULLSEYE ) ) { vecForceDir = (GetEnemy()->GetAbsOrigin() - GetAbsOrigin()); CTakeDamageInfo info( this, this, damage, DMG_SLASH ); CalculateMeleeDamageForce( &info, vecForceDir, GetEnemy()->GetAbsOrigin() ); GetEnemy()->TakeDamage( info ); return; } CBaseEntity *pHurt = CheckTraceHullAttack( distance, -Vector(16,16,32), Vector(16,16,32), damage, DMG_SLASH, 5.0f ); if ( pHurt ) { vecForceDir = ( pHurt->WorldSpaceCenter() - WorldSpaceCenter() ); CBasePlayer *pPlayer = ToBasePlayer( pHurt ); if ( pPlayer != NULL ) { //Kick the player angles pPlayer->ViewPunch( viewPunch ); Vector dir = pHurt->GetAbsOrigin() - GetAbsOrigin(); VectorNormalize(dir); QAngle angles; VectorAngles( dir, angles ); Vector forward, right; AngleVectors( angles, &forward, &right, NULL ); //Push the target back pHurt->ApplyAbsVelocityImpulse( - right * shove[1] - forward * shove[0] ); } // Play a random attack hit sound AttackSound(); // bleed em if ( UTIL_ShouldShowBlood(pHurt->BloodColor()) ) { // Hit an NPC. Bleed them! Vector vecBloodPos; Vector forward, right, up; AngleVectors( GetAbsAngles(), &forward, &right, &up ); //if( GetAttachment( "leftclaw", vecBloodPos ) ) { //Vector diff = vecBloodPos - GetAbsOrigin(); //if (diff.z < 0) //vecBloodPos.z = GetAbsOrigin().z - (diff.z * 2); vecBloodPos = GetAbsOrigin() + forward * 60 - right * 14 + up * 50; SpawnBlood( vecBloodPos, g_vecAttackDir, pHurt->BloodColor(), MIN( damage, 30 ) ); } //if( GetAttachment( "rightclaw", vecBloodPos ) ) { vecBloodPos = GetAbsOrigin() + forward * 60 + right * 14 + up * 50; SpawnBlood( vecBloodPos, g_vecAttackDir, pHurt->BloodColor(), MIN( damage, 30 ) ); } } } }
void CASW_Simple_Alien::HandleAnimEvent( animevent_t *pEvent ) { int nEvent = pEvent->Event(); if ( nEvent == AE_DRONE_WALK_FOOTSTEP ) { return; } if ( nEvent == AE_DRONE_FOOTSTEP_SOFT ) { return; } if ( nEvent == AE_DRONE_FOOTSTEP_HEAVY ) { return; } if ( nEvent == AE_DRONE_MELEE_HIT1 ) { MeleeAttack( ASW_DRONE_MELEE1_RANGE, ASWGameRules()->ModifyAlienDamageBySkillLevel(GetDamage()), QAngle( 20.0f, 0.0f, -12.0f ), Vector( -250.0f, 1.0f, 1.0f ) ); return; } if ( nEvent == AE_DRONE_MELEE_HIT2 ) { MeleeAttack( ASW_DRONE_MELEE1_RANGE, ASWGameRules()->ModifyAlienDamageBySkillLevel(GetDamage()), QAngle( 20.0f, 0.0f, 0.0f ), Vector( -350.0f, 1.0f, 1.0f ) ); return; } if ( nEvent == AE_DRONE_MELEE1_SOUND ) { AttackSound(); return; } if ( nEvent == AE_DRONE_MELEE2_SOUND ) { AttackSound(); return; } if ( nEvent == AE_DRONE_MOUTH_BLEED ) { Vector vecOrigin, vecDir; if (GetAttachment( LookupAttachment("mouth") , vecOrigin, &vecDir )) UTIL_ASW_BloodDrips( vecOrigin+vecDir*3, vecDir, BLOOD_COLOR_RED, 6 ); return; } if ( nEvent == AE_DRONE_ALERT_SOUND ) { EmitSound( "ASW_Drone.Alert" ); return; } if ( nEvent == AE_DRONE_SHADOW_ON) { RemoveEffects( EF_NOSHADOW ); return; } BaseClass::HandleAnimEvent( pEvent ); }
//----------------------------------------------------------------------------- // Purpose: Catches the monster-specific messages that occur when tagged // animation frames are played. // Input : *pEvent - //----------------------------------------------------------------------------- void CNPC_Headcrab::HandleAnimEvent( animevent_t *pEvent ) { switch ( pEvent->event ) { case HC_AE_JUMPATTACK: { RemoveFlag( FL_ONGROUND ); // // Take him off ground so engine doesn't instantly reset FL_ONGROUND. // UTIL_SetOrigin( this, GetAbsOrigin() + Vector( 0 , 0 , 1 )); Vector vecJumpDir; CBaseEntity *pEnemy = GetEnemy(); if ( pEnemy ) { Vector vecEnemyEyePos = pEnemy->EyePosition(); float gravity = sv_gravity.GetFloat(); if ( gravity <= 1 ) { gravity = 1; } // // How fast does the headcrab need to travel to reach my enemy's eyes given gravity? // float height = ( vecEnemyEyePos.z - GetAbsOrigin().z ); if ( height < 16 ) { height = 16; } else if ( height > 120 ) { height = 120; } float speed = sqrt( 2 * gravity * height ); float time = speed / gravity; // // Scale the sideways velocity to get there at the right time // vecJumpDir = vecEnemyEyePos - GetAbsOrigin(); vecJumpDir = vecJumpDir / time; // // Speed to offset gravity at the desired height. // vecJumpDir.z = speed; // // Don't jump too far/fast. // float distance = vecJumpDir.Length(); if ( distance > 650 ) { vecJumpDir = vecJumpDir * ( 650.0 / distance ); } } else { // // Jump hop, don't care where. // Vector forward, up; AngleVectors( GetAbsAngles(), &forward, NULL, &up ); vecJumpDir = Vector( forward.x, forward.y, up.z ) * 350; } int iSound = random->RandomInt( 0 , 1 ); if ( iSound != 0 ) { AttackSound(); } SetAbsVelocity( vecJumpDir ); m_flNextAttack = gpGlobals->curtime + 2; break; } default: { CAI_BaseNPC::HandleAnimEvent( pEvent ); break; } } }
//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= void CGonome :: HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { case ZOMBIE_AE_ATTACK_RIGHT: { // do stuff for this event. // ALERT( at_console, "Slash right!\n" ); CBaseEntity *pHurt = CheckTraceHullAttack( MELEE_DIST, gSkillData.gonomeDmgOneSlash, DMG_SLASH ); if ( pHurt ) { if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) { // pHurt->pev->punchangle.z = -18; // pHurt->pev->punchangle.x = 5; pHurt->pev->punchangle.z = -22; pHurt->pev->punchangle.x = 9; pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 100; } // Play a random attack hit sound EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); } else // Play a random attack miss sound EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); EMIT_SOUND( ENT(pev), CHAN_BODY, "gonome/gonome_melee1.wav", 1, ATTN_NORM ); if (RANDOM_LONG(0,1)) AttackSound(); } break; case ZOMBIE_AE_ATTACK_LEFT: { // do stuff for this event. // ALERT( at_console, "Slash left!\n" ); CBaseEntity *pHurt = CheckTraceHullAttack( MELEE_DIST, gSkillData.gonomeDmgOneSlash, DMG_SLASH ); if ( pHurt ) { if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) { // pHurt->pev->punchangle.z = 18; // pHurt->pev->punchangle.x = 5; pHurt->pev->punchangle.z = 22; pHurt->pev->punchangle.x = 9; pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 100; } EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); } else EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); EMIT_SOUND( ENT(pev), CHAN_BODY, "gonome/gonome_melee1.wav", 1, ATTN_NORM ); if (RANDOM_LONG(0,1)) AttackSound(); } break; //EMIT_SOUND( ENT(pev), CHAN_BODY, "gonome/gonome_melee1.wav", 1, ATTN_NORM ); case ZOMBIE_AE_ATTACK_BOTH: { // do stuff for this event. CBaseEntity *pHurt = CheckTraceHullAttack( MELEE_DIST, gSkillData.gonomeDmgBothSlash, DMG_SLASH ); if ( pHurt ) { if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) { // pHurt->pev->punchangle.x = 5; pHurt->pev->punchangle.x = 10; pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * -100; } EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); } else EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); if (RANDOM_LONG(0,1)) AttackSound(); } break; default: CBaseMonster::HandleAnimEvent( pEvent ); break; } }
//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= void CBullsquid :: HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { case BSQUID_AE_SPIT: { Vector vecSpitOffset; Vector vecSpitDir; UTIL_MakeVectors ( pev->angles ); // !!!HACKHACK - the spot at which the spit originates (in front of the mouth) was measured in 3ds and hardcoded here. // we should be able to read the position of bones at runtime for this info. vecSpitOffset = ( gpGlobals->v_right * 8 + gpGlobals->v_forward * 37 + gpGlobals->v_up * 23 ); vecSpitOffset = ( pev->origin + vecSpitOffset ); vecSpitDir = ( ( m_hEnemy->pev->origin + m_hEnemy->pev->view_ofs ) - vecSpitOffset ).Normalize(); vecSpitDir.x += RANDOM_FLOAT( -0.05, 0.05 ); vecSpitDir.y += RANDOM_FLOAT( -0.05, 0.05 ); vecSpitDir.z += RANDOM_FLOAT( -0.05, 0 ); // do stuff for this event. AttackSound(); // spew the spittle temporary ents. MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpitOffset ); WRITE_BYTE( TE_SPRITE_SPRAY ); WRITE_COORD( vecSpitOffset.x); // pos WRITE_COORD( vecSpitOffset.y); WRITE_COORD( vecSpitOffset.z); WRITE_COORD( vecSpitDir.x); // dir WRITE_COORD( vecSpitDir.y); WRITE_COORD( vecSpitDir.z); WRITE_SHORT( iSquidSpitSprite ); // model WRITE_BYTE ( 15 ); // count WRITE_BYTE ( 210 ); // speed WRITE_BYTE ( 25 ); // noise ( client will divide by 100 ) MESSAGE_END(); CSquidSpit::Shoot( pev, vecSpitOffset, vecSpitDir * 900 ); } break; case BSQUID_AE_BITE: { // SOUND HERE! CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.bullsquidDmgBite, DMG_SLASH ); if ( pHurt ) { //pHurt->pev->punchangle.z = -15; //pHurt->pev->punchangle.x = -45; pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_forward * 100; pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_up * 100; } } break; case BSQUID_AE_TAILWHIP: { CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.bullsquidDmgWhip, DMG_CLUB | DMG_ALWAYSGIB ); if ( pHurt ) { pHurt->pev->punchangle.z = -20; pHurt->pev->punchangle.x = 20; pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 200; pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_up * 100; } } break; case BSQUID_AE_BLINK: { // close eye. pev->skin = 1; } break; case BSQUID_AE_HOP: { float flGravity = g_psv_gravity->value; // throw the squid up into the air on this frame. if ( FBitSet ( pev->flags, FL_ONGROUND ) ) { pev->flags -= FL_ONGROUND; } // jump into air for 0.8 (24/30) seconds // pev->velocity.z += (0.875 * flGravity) * 0.5; pev->velocity.z += (0.625 * flGravity) * 0.5; } break; case BSQUID_AE_THROW: { int iPitch; // squid throws its prey IF the prey is a client. CBaseEntity *pHurt = CheckTraceHullAttack( 70, 0, 0 ); if ( pHurt ) { // croonchy bite sound iPitch = RANDOM_FLOAT( 90, 110 ); switch ( RANDOM_LONG( 0, 1 ) ) { case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_bite2.wav", 1, ATTN_NORM, 0, iPitch ); break; case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_bite3.wav", 1, ATTN_NORM, 0, iPitch ); break; } //pHurt->pev->punchangle.x = RANDOM_LONG(0,34) - 5; //pHurt->pev->punchangle.z = RANDOM_LONG(0,49) - 25; //pHurt->pev->punchangle.y = RANDOM_LONG(0,89) - 45; // screeshake transforms the viewmodel as well as the viewangle. No problems with seeing the ends of the viewmodels. UTIL_ScreenShake( pHurt->pev->origin, 25.0, 1.5, 0.7, 2 ); if ( pHurt->IsPlayer() ) { UTIL_MakeVectors( pev->angles ); pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * 300 + gpGlobals->v_up * 300; } } } break; default: CBaseMonster::HandleAnimEvent( pEvent ); } }
//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= void CZombie :: HandleAnimEvent( AnimEvent_t& event ) { switch( event.event ) { case ZOMBIE_AE_ATTACK_RIGHT: { // do stuff for this event. // ALERT( at_console, "Slash right!\n" ); CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.GetZombieDmgOneSlash(), DMG_SLASH ); if ( pHurt ) { if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) { pHurt->pev->punchangle.z = -18; pHurt->pev->punchangle.x = 5; pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 100; } // Play a random attack hit sound EMIT_SOUND_DYN ( this, CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); } else // Play a random attack miss sound EMIT_SOUND_DYN ( this, CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); if (RANDOM_LONG(0,1)) AttackSound(); } break; case ZOMBIE_AE_ATTACK_LEFT: { // do stuff for this event. // ALERT( at_console, "Slash left!\n" ); CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.GetZombieDmgOneSlash(), DMG_SLASH ); if ( pHurt ) { if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) { pHurt->pev->punchangle.z = 18; pHurt->pev->punchangle.x = 5; pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 100; } EMIT_SOUND_DYN ( this, CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); } else EMIT_SOUND_DYN ( this, CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); if (RANDOM_LONG(0,1)) AttackSound(); } break; case ZOMBIE_AE_ATTACK_BOTH: { // do stuff for this event. CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.GetZombieDmgBothSlash(), DMG_SLASH ); if ( pHurt ) { if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) { pHurt->pev->punchangle.x = 5; pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * -100; } EMIT_SOUND_DYN ( this, CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); } else EMIT_SOUND_DYN ( this, CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); if (RANDOM_LONG(0,1)) AttackSound(); } break; default: CBaseMonster::HandleAnimEvent( event ); break; } }
//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= void CNPC_Bullsquid::HandleAnimEvent( animevent_t *pEvent ) { switch( pEvent->event ) { case BSQUID_AE_SPIT: { if ( GetEnemy() ) { Vector vecSpitOffset; Vector vecSpitDir; Vector vRight, vUp, vForward; AngleVectors ( GetAbsAngles(), &vForward, &vRight, &vUp ); // !!!HACKHACK - the spot at which the spit originates (in front of the mouth) was measured in 3ds and hardcoded here. // we should be able to read the position of bones at runtime for this info. vecSpitOffset = ( vRight * 8 + vForward * 60 + vUp * 50 ); vecSpitOffset = ( GetAbsOrigin() + vecSpitOffset ); vecSpitDir = ( ( GetEnemy()->BodyTarget( GetAbsOrigin() ) ) - vecSpitOffset ); VectorNormalize( vecSpitDir ); vecSpitDir.x += random->RandomFloat( -0.05, 0.05 ); vecSpitDir.y += random->RandomFloat( -0.05, 0.05 ); vecSpitDir.z += random->RandomFloat( -0.05, 0 ); AttackSound(); CSquidSpit::Shoot( this, vecSpitOffset, vecSpitDir * 900 ); } } break; case BSQUID_AE_BITE: { // SOUND HERE! CBaseEntity *pHurt = CheckTraceHullAttack( 70, Vector(-16,-16,-16), Vector(16,16,16), sk_bullsquid_dmg_bite.GetFloat(), DMG_SLASH ); if ( pHurt ) { Vector forward, up; AngleVectors( GetAbsAngles(), &forward, NULL, &up ); pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() - (forward * 100) ); pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (up * 100) ); pHurt->SetGroundEntity( NULL ); } } break; case BSQUID_AE_TAILWHIP: { CBaseEntity *pHurt = CheckTraceHullAttack( 70, Vector(-16,-16,-16), Vector(16,16,16), sk_bullsquid_dmg_whip.GetFloat(), DMG_SLASH | DMG_ALWAYSGIB ); if ( pHurt ) { Vector right, up; AngleVectors( GetAbsAngles(), NULL, &right, &up ); if ( pHurt->GetFlags() & ( FL_NPC | FL_CLIENT ) ) pHurt->ViewPunch( QAngle( 20, 0, -20 ) ); pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (right * 200) ); pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (up * 100) ); } } break; case BSQUID_AE_BLINK: { // close eye. m_nSkin = 1; } break; case BSQUID_AE_HOP: { float flGravity = sv_gravity.GetFloat(); // throw the squid up into the air on this frame. if ( GetFlags() & FL_ONGROUND ) { SetGroundEntity( NULL ); } // jump into air for 0.8 (24/30) seconds Vector vecVel = GetAbsVelocity(); vecVel.z += ( 0.625 * flGravity ) * 0.5; SetAbsVelocity( vecVel ); } break; case BSQUID_AE_THROW: { // squid throws its prey IF the prey is a client. CBaseEntity *pHurt = CheckTraceHullAttack( 70, Vector(-16,-16,-16), Vector(16,16,16), 0, 0 ); if ( pHurt ) { // croonchy bite sound CPASAttenuationFilter filter( this ); EmitSound( filter, entindex(), "Bullsquid.Bite" ); // screeshake transforms the viewmodel as well as the viewangle. No problems with seeing the ends of the viewmodels. UTIL_ScreenShake( pHurt->GetAbsOrigin(), 25.0, 1.5, 0.7, 2, SHAKE_START ); if ( pHurt->IsPlayer() ) { Vector forward, up; AngleVectors( GetAbsAngles(), &forward, NULL, &up ); pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + forward * 300 + up * 300 ); } } } break; default: BaseClass::HandleAnimEvent( pEvent ); } }