//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. // // Returns number of events handled, 0 if none. //========================================================= void CAGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { case AGRUNT_AE_HORNET1: case AGRUNT_AE_HORNET2: case AGRUNT_AE_HORNET3: case AGRUNT_AE_HORNET4: case AGRUNT_AE_HORNET5: { // m_vecEnemyLKP should be center of enemy body Vector vecArmPos, vecArmDir; Vector vecDirToEnemy; Vector angDir; if (HasConditions( bits_COND_SEE_ENEMY)) { vecDirToEnemy = ( ( m_vecEnemyLKP ) - pev->origin ); angDir = UTIL_VecToAngles( vecDirToEnemy ); vecDirToEnemy = vecDirToEnemy.Normalize(); } else { angDir = pev->angles; UTIL_MakeAimVectors( angDir ); vecDirToEnemy = gpGlobals->v_forward; } pev->effects = EF_MUZZLEFLASH; // make angles +-180 if (angDir.x > 180) { angDir.x = angDir.x - 360; } SetBlending( 0, angDir.x ); GetAttachment( 0, vecArmPos, vecArmDir ); vecArmPos = vecArmPos + vecDirToEnemy * 32; MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecArmPos ); WRITE_BYTE( TE_SPRITE ); WRITE_COORD( vecArmPos.x ); // pos WRITE_COORD( vecArmPos.y ); WRITE_COORD( vecArmPos.z ); WRITE_SHORT( iAgruntMuzzleFlash ); // model WRITE_BYTE( 6 ); // size * 10 WRITE_BYTE( 128 ); // brightness MESSAGE_END(); CBaseEntity *pHornet = CBaseEntity::Create( "hornet", vecArmPos, UTIL_VecToAngles( vecDirToEnemy ), edict() ); UTIL_MakeVectors ( pHornet->pev->angles ); pHornet->pev->velocity = gpGlobals->v_forward * 300; switch ( RANDOM_LONG ( 0 , 2 ) ) { case 0: EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, "agrunt/ag_fire1.wav", 1.0, ATTN_NORM, 0, 100 ); break; case 1: EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, "agrunt/ag_fire2.wav", 1.0, ATTN_NORM, 0, 100 ); break; case 2: EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, "agrunt/ag_fire3.wav", 1.0, ATTN_NORM, 0, 100 ); break; } CBaseMonster *pHornetMonster = pHornet->MyMonsterPointer(); if ( pHornetMonster ) { pHornetMonster->m_hEnemy = m_hEnemy; } } break; case AGRUNT_AE_LEFT_FOOT: switch (RANDOM_LONG(0,1)) { // left foot case 0: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder2.wav", 1, ATTN_NORM, 0, 70 ); break; case 1: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder4.wav", 1, ATTN_NORM, 0, 70 ); break; } break; case AGRUNT_AE_RIGHT_FOOT: // right foot switch (RANDOM_LONG(0,1)) { case 0: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder1.wav", 1, ATTN_NORM, 0, 70 ); break; case 1: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder3.wav", 1, ATTN_NORM, 0 ,70); break; } break; case AGRUNT_AE_LEFT_PUNCH: { CBaseEntity *pHurt = CheckTraceHullAttack( AGRUNT_MELEE_DIST, gSkillData.agruntDmgPunch, DMG_CLUB ); if ( pHurt ) { pHurt->pev->punchangle.y = -25; pHurt->pev->punchangle.x = 8; // OK to use gpGlobals without calling MakeVectors, cause CheckTraceHullAttack called it above. if ( pHurt->IsPlayer() ) { // this is a player. Knock him around. pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 250; } EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); Vector vecArmPos, vecArmAng; GetAttachment( 0, vecArmPos, vecArmAng ); SpawnBlood(vecArmPos, pHurt->BloodColor(), 25);// a little surface blood. } 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) ); } } break; case AGRUNT_AE_RIGHT_PUNCH: { CBaseEntity *pHurt = CheckTraceHullAttack( AGRUNT_MELEE_DIST, gSkillData.agruntDmgPunch, DMG_CLUB ); if ( pHurt ) { pHurt->pev->punchangle.y = 25; pHurt->pev->punchangle.x = 8; // OK to use gpGlobals without calling MakeVectors, cause CheckTraceHullAttack called it above. if ( pHurt->IsPlayer() ) { // this is a player. Knock him around. pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * -250; } EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); Vector vecArmPos, vecArmAng; GetAttachment( 0, vecArmPos, vecArmAng ); SpawnBlood(vecArmPos, pHurt->BloodColor(), 25);// a little surface blood. } 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) ); } } break; default: CSquadMonster::HandleAnimEvent( pEvent ); break; } }
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 ) ); } } } }
//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. // // Returns number of events handled, 0 if none. //========================================================= void CNPC_AlienGrunt::HandleAnimEvent( animevent_t *pEvent ) { switch( pEvent->event ) { case AGRUNT_AE_HORNET1: case AGRUNT_AE_HORNET2: case AGRUNT_AE_HORNET3: case AGRUNT_AE_HORNET4: case AGRUNT_AE_HORNET5: { // m_vecEnemyLKP should be center of enemy body Vector vecArmPos; QAngle angArmDir; Vector vecDirToEnemy; QAngle angDir; if (HasCondition( COND_SEE_ENEMY) && GetEnemy()) { Vector vecEnemyLKP = GetEnemy()->GetAbsOrigin(); vecDirToEnemy = ( ( vecEnemyLKP ) - GetAbsOrigin() ); VectorAngles( vecDirToEnemy, angDir ); VectorNormalize( vecDirToEnemy ); } else { angDir = GetAbsAngles(); angDir.x = -angDir.x; Vector vForward; AngleVectors( angDir, &vForward ); vecDirToEnemy = vForward; } DoMuzzleFlash(); // make angles +-180 if (angDir.x > 180) { angDir.x = angDir.x - 360; } // SetBlending( 0, angDir.x ); GetAttachment( "0", vecArmPos, angArmDir ); vecArmPos = vecArmPos + vecDirToEnemy * 32; CPVSFilter filter( GetAbsOrigin() ); te->Sprite( filter, 0.0, &vecArmPos, iAgruntMuzzleFlash, random->RandomFloat( 0.4, 0.8 ), 128 ); CBaseEntity *pHornet = CBaseEntity::Create( "hornet", vecArmPos, QAngle( 0, 0, 0 ), this ); Vector vForward; AngleVectors( angDir, &vForward ); pHornet->SetAbsVelocity( vForward * 300 ); pHornet->SetOwnerEntity( this ); EmitSound( "Weapon_Hornetgun.Single" ); CHL1BaseNPC *pHornetMonster = (CHL1BaseNPC *)pHornet->MyNPCPointer(); if ( pHornetMonster ) { pHornetMonster->SetEnemy( GetEnemy() ); } } break; case AGRUNT_AE_LEFT_FOOT: // left foot { CPASAttenuationFilter filter2( this ); EmitSound( filter2, entindex(), "AlienGrunt.LeftFoot" ); } break; case AGRUNT_AE_RIGHT_FOOT: // right foot { CPASAttenuationFilter filter3( this ); EmitSound( filter3, entindex(), "AlienGrunt.RightFoot" ); } break; case AGRUNT_AE_LEFT_PUNCH: { Vector vecMins = GetHullMins(); Vector vecMaxs = GetHullMaxs(); vecMins.z = vecMins.x; vecMaxs.z = vecMaxs.x; CBaseEntity *pHurt = CheckTraceHullAttack( AGRUNT_MELEE_DIST, vecMins, vecMaxs, sk_agrunt_dmg_punch.GetFloat(), DMG_CLUB ); CPASAttenuationFilter filter4( this ); if ( pHurt ) { if ( pHurt->GetFlags() & ( FL_NPC | FL_CLIENT ) ) pHurt->ViewPunch( QAngle( -25, 8, 0) ); Vector vRight; AngleVectors( GetAbsAngles(), NULL, &vRight, NULL ); // OK to use gpGlobals without calling MakeVectors, cause CheckTraceHullAttack called it above. if ( pHurt->IsPlayer() ) { // this is a player. Knock him around. pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + vRight * 250 ); } EmitSound(filter4, entindex(), "AlienGrunt.AttackHit" ); Vector vecArmPos; QAngle angArmAng; GetAttachment( 0, vecArmPos, angArmAng ); SpawnBlood(vecArmPos, g_vecAttackDir, pHurt->BloodColor(), 25);// a little surface blood. } else { // Play a random attack miss sound EmitSound(filter4, entindex(), "AlienGrunt.AttackMiss" ); } } break; case AGRUNT_AE_RIGHT_PUNCH: { Vector vecMins = GetHullMins(); Vector vecMaxs = GetHullMaxs(); vecMins.z = vecMins.x; vecMaxs.z = vecMaxs.x; CBaseEntity *pHurt = CheckTraceHullAttack( AGRUNT_MELEE_DIST, vecMins, vecMaxs, sk_agrunt_dmg_punch.GetFloat(), DMG_CLUB ); CPASAttenuationFilter filter5( this ); if ( pHurt ) { if ( pHurt->GetFlags() & ( FL_NPC | FL_CLIENT ) ) pHurt->ViewPunch( QAngle( 25, 8, 0) ); // OK to use gpGlobals without calling MakeVectors, cause CheckTraceHullAttack called it above. if ( pHurt->IsPlayer() ) { // this is a player. Knock him around. Vector vRight; AngleVectors( GetAbsAngles(), NULL, &vRight, NULL ); pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + vRight * -250 ); } EmitSound( filter5, entindex(), "AlienGrunt.AttackHit" ); Vector vecArmPos; QAngle angArmAng; GetAttachment( 0, vecArmPos, angArmAng ); SpawnBlood(vecArmPos, g_vecAttackDir, pHurt->BloodColor(), 25);// a little surface blood. } else { // Play a random attack miss sound EmitSound( filter5, entindex(), "AlienGrunt.AttackMiss" ); } } break; default: BaseClass::HandleAnimEvent( pEvent ); break; } }
//========================================================= // CheckTraceHullAttack - expects a length to trace, amount // of damage to do, and damage type. Returns a pointer to // the damaged entity in case the monster wishes to do // other stuff to the victim (punchangle, etc) // // Used for many contact-range melee attacks. Bites, claws, etc. //========================================================= CBaseEntity* CBaseMonster :: CheckTraceHullAttack( float flDist, float& ioDamage, int iDmgType ) { Vector vecStart = pev->origin; if(this->IsPlayer()) { // Melee attacks always originate where the view is vecStart.x += this->pev->view_ofs.x; vecStart.y += this->pev->view_ofs.y; vecStart.z += this->pev->view_ofs.z; } if (IsPlayer()) UTIL_MakeVectors( pev->v_angle ); else UTIL_MakeAimVectors( pev->angles ); //AvHSUPlayParticleEvent("JetpackEffect", this->edict(), vecStart); // First do a tracehull. If that misses, try three tracelines (dead-on center, then randomly left and randomly right). bool theHitTarget = false; for(int i = 0; (i < 4) && !theHitTarget; i++) { const float kAmount = 0.4f; float theXAmount = 0.0f; if(i == 2) { theXAmount = kAmount; } else if(i == 3) { theXAmount = -kAmount; } Vector vecDir = gpGlobals->v_forward + theXAmount*gpGlobals->v_right; vecDir.Normalize(); Vector vecEnd = vecStart + (vecDir * flDist ); TraceResult tr; if(i == 0) { int theOurHull = this->GetHull(); int theHull = AvHSUGetValveHull(theOurHull); UTIL_TraceHull(vecStart, vecEnd, dont_ignore_monsters, theHull, this->edict(), &tr); } else { //AvHSUPlayParticleEvent("JetpackEffect", this->edict(), vecEnd); UTIL_TraceLine(vecStart, vecEnd, dont_ignore_monsters, dont_ignore_glass, ENT(this->pev), &tr); } if ( tr.pHit ) { CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); if ( ioDamage > 0 ) { float theScalar = 1.0f; if(GetGameRules()->CanEntityDoDamageTo(this, pEntity, &theScalar)) { theHitTarget = true; // Multiply damage by scalar for tourny mode, etc. ioDamage *= theScalar; entvars_t* theInflictor = this->pev; AvHPlayer* thePlayer = dynamic_cast<AvHPlayer*>(this); if(thePlayer) { AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(thePlayer->m_pActiveItem); if(theBasePlayerWeapon) { theInflictor = theBasePlayerWeapon->pev; } } pEntity->TakeDamage(theInflictor, pev, ioDamage, iDmgType ); // Spawn blood if(ioDamage > 0.0f) { // a little surface blood. SpawnBlood(tr.vecEndPos, pEntity->BloodColor(), ioDamage); // on the wall/floor (don't play because blood decal is green) //TraceBleed(ioDamage, vecDir, &tr, iDmgType); } return pEntity; } } } } return NULL; }