Making a weapon that heal players

From Valve Developer Community
Jump to: navigation, search

The purpose of this tutorial is to create a weapon that heals players.

Constructor

The following block of code is a integer variable,

m_bDropped = 0; // This is to make sure the Medic drops it one at a time

Primary Fire

The primary fire of the weapon is to drop one health vial per shot. Comments have been added for more clarifying.

    if (!m_bDropped) { // If the health vial hasn't been dropped, continue
#ifndef CLIENT_DLL
      CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); // Grab the wielder

      Vector   vecEye = pPlayer->EyePosition(); // Get the eye vector of the wielder
      Vector   vForward, vRight; // Create 2 new vectors

      pPlayer->EyeVectors( &vForward, &vRight, NULL );  // Getting direction forward
      Vector vecSrc = vecEye + vForward * 18.0f + vRight * 8.0f; // Finding source of spawning
      trace_t tr; // Gets the trace

      UTIL_TraceHull( vecEye, vecSrc, -Vector(6,6,6), Vector(6,6,6),
         pPlayer->PhysicsSolidMaskForEntity(), pPlayer, pPlayer->GetCollisionGroup(), &tr ); // Checks if anything in front of it
      
      if ( tr.DidHit() ) // If hit
      {
         vecSrc = tr.endpos; // Drop at location
      }

   //   CheckThrowPosition( pPlayer, vecEye, vecSrc );
   //   vForward[0] += 0.1f;
      vForward[2] += 0.1f; // Something else

      Vector vecThrow;
      AngleVectors( pPlayer->EyeAngles() + pPlayer->GetPunchAngle(), &vecThrow ); // Get Vector for Impulse on Health Vial
      // pPlayer->GetVelocity( &vecThrow, NULL );
      VectorScale( vecThrow, 1000.0f, vecThrow ); // Scale vial down
      // vecThrow += vForward * 1200;

      CBaseEntity *pVial = NULL; // Null
      pVial = CBaseEntity::Create( "item_healthvial", pPlayer->Weapon_ShootPosition(), QAngle(80,60,0), pPlayer ); // Creates
      pVial->AddSpawnFlags(SF_NORESPAWN); // Doesn't allow respawning
      if (!pVial) // Has to have to be created to throw it
      {
         DevMsg("unable to create item\n");
      }else // Works
      {
         DevMsg(2, "Starting item throw (Server)\n");

         IPhysicsObject *pPhysicsObject = pVial->VPhysicsGetObject(); // Get the physic object
         if ( pPhysicsObject )
         {
            DevMsg(2, "Throwing item (Server)\n");
            pPhysicsObject->SetVelocity( &vecThrow, NULL );// Throw vial
            
         }
      }
      m_bDropped = 1; // Change flag
#endif
   } else {
      DevMsg(2, "Already dropped one. Release the button. (Server)\n"); // Let go of button
   }

Item Post Frame

This block of code will add to the ItemPostFrame in the weapon.

if (!((pOwner->m_nButtons & IN_ATTACK) || (pOwner->m_nButtons & IN_ATTACK2) || (pOwner->m_nButtons & IN_RELOAD)))
   {
      m_bDropped = 0;
   }

Secondary Fire

If player(s) are too close from the medic or the gun, it will heal the player(s).

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponHealer::SecondaryAttack( void ) 
{
   if (CanHealPlayer()) // Checks if it can heal
      HealPlayer(); // Run method
}

bool CWeaponHealer::CanHealPlayer( void ) // Checks boolean
{
   if (!m_bFired){ // If it hasn't been fired,
      CHL2MP_Player *pOwner = ToHL2MPPlayer( GetOwner() ); // Get owner of fun

      if (!pOwner) // If owner doesn't exist
      {
         return false; // Terminate code and return false
      }

      Vector vecSrc, vecAiming; // Create vectors used for secondary fire

      // Take the eye position and direction
      vecSrc = pOwner->EyePosition();
      
      QAngle angles = pOwner->GetLocalAngles(); // Get local angles

      AngleVectors( angles, &vecAiming );

      trace_t tr; // Create a new trace to use

      Vector   vecEnd = vecSrc + (vecAiming * 42);
      UTIL_TraceLine( vecSrc, vecEnd, MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr );
      
      if (tr.fraction < 1.0)
      {
         // Don't attach to a living creature
         if (tr.m_pEnt)
         {
            CBaseEntity *pEntity = tr.m_pEnt;
            CBaseCombatCharacter *pBCC      = ToBaseCombatCharacter( pEntity );
            if (pBCC)
            {
               if (pBCC->GetHealth()<100) // If player does not have 100 health
                  return true; // Return true to 
            }
         }
         return false; // Else return false
      }
      else
      {
         return false;
      }
   }else {return false;}
}
bool CWeaponHealer::HealPlayer( void ) // Heal player declaration
{
   m_bFired = 1; // Sets it to fired

   CHL2MP_Player *pOwner = ToHL2MPPlayer( GetOwner() ); // Get owner of health vial

   if (!pOwner) // If Owner is no longer in server
   {
      return false; // Terminate code
   }

   Vector vecSrc, vecAiming;

   // Take the eye position and direction
   vecSrc = pOwner->EyePosition();
   
   QAngle angles = pOwner->GetLocalAngles();

   AngleVectors( angles, &vecAiming );

   trace_t tr;

   Vector   vecEnd = vecSrc + (vecAiming * 42);
   UTIL_TraceLine( vecSrc, vecEnd, MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr );
   
   if (tr.fraction < 1.0)
   {
      // Don't attach to a living creature
      if (tr.m_pEnt)
      {
         CBaseEntity *pEntity = tr.m_pEnt;
         if (pEntity->IsPlayer())
         {
            if (pEntity->GetHealth()<pEntity->GetMaxHealth())
            {
#ifndef CLIENT_DLL
               CBasePlayer *pPlayer = ToBasePlayer(pEntity);

               CPASAttenuationFilter filter( pPlayer, "HealthVial.Touch" ); // Filters
               EmitSound( filter, pPlayer->entindex(), "HealthVial.Touch" ); // Play HealthVial.Touch
               pEntity->TakeHealth( 20, DMG_GENERIC ); // Damage 20 health under generic reason
#endif
               return true;
            }
         }
      }
      return false;
   }
   else
   {
      return false;
   }
}