Welcome, Guest! Login | Register

Tungsten Arrows [Print this Article]
Posted by: ScoBra7
Date posted: Apr 08 2003
User Rating: 4.3 out of 5.0
Number of views: 2943
Number of comments: 2
Description: Ricochets of walls.
So you want tungsten arrows that ricochet off walls. This will show you how it is done. The reason why I wrote this tutorial is because I struggled to get this right. The people on this message board helped me a lot and without their help I would not have been able to get it right. Going through the code I found some quirks. So let's start coding!

Open the mp.dll workspace. Open crossbow.cpp

Find class CCrossbowBolt : public CBaseEntity and add
 CODE  
int m_iRicochetNumber;
Vector m_vecRicochet;
bool m_bRicochet;
These are the member variables that we will use.

Find void CCrossbowBolt::Spawn( ) and add
 CODE  
m_iRicochetNumber = 5; //Will Ricochet about 5 times
m_vecRicochet = Vector(0,0,0); //Paranoid Android  :D
m_bRicochet = false; //Did we ricochet?

This just initializes the member variables, as you can see I'm a Paranoid Android.

Next find void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) and change the following from:
 CODE  
SetTouch( NULL );
SetThink( NULL );

to
 CODE  
if(m_iRicochetNumber <= 1)
{
SetTouch( NULL );
SetThink( NULL );
}

We would like to keep on thinking until the last ricochet.

Still in this function find: *
 CODE  
if (pOther->pev->takedamage)
{

add inside this "if" statement:
 CODE  
SetTouch( NULL );
SetThink( NULL );
m_iRicochetNumber = 0;

Just making sure that the arrow will be removed after hitting something that can take damage. I'll give you a suggestion, below, how to change this so that it goes through a "breakable" object or player.

Next find the "else" part of the above "if" statement and change the following from:
 CODE  
else
    {
  EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "weapons/xbow_hit1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 98 + RANDOM_LONG(0,7));

  SetThink( SUB_Remove );
  pev->nextthink = gpGlobals->time;// this will get changed below if the bolt is allowed to stick in what it hit.

  if ( FClassnameIs( pOther->pev, "worldspawn" ) )
  {
    // if what we hit is static architecture, can stay around for a while.
    Vector vecDir = pev->velocity.Normalize( );
    UTIL_SetOrigin( pev, pev->origin - vecDir * 12 );
    pev->angles = UTIL_VecToAngles( vecDir );
    pev->solid = SOLID_NOT;
    pev->movetype = MOVETYPE_FLY;
    pev->velocity = Vector( 0, 0, 0 );
    pev->avelocity.z = 0;
    pev->angles.z = RANDOM_LONG(0,360);
    pev->nextthink = gpGlobals->time + 10.0;
  }

  if (UTIL_PointContents(pev->origin) != CONTENTS_WATER)
  {
    UTIL_Sparks( pev->origin );
  }
    }

to
 CODE  
else
    {
  EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "weapons/xbow_hit1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 98 + RANDOM_LONG(0,7));

  /*Mod Begin*/
  if(m_iRicochetNumber > 1)
  {

    if ( FClassnameIs( pOther->pev, "worldspawn" ) )
    {
    
    Vector vNormalVel = pev->velocity;
    vNormalVel.Normalize();
    Vector vecSrc = pev->origin - vNormalVel * 20;
    TraceResult tr;
    UTIL_TraceLine( pev->origin - pev->velocity.Normalize( ) * 20, vecSrc + vNormalVel * 40, ignore_monsters,ENT(pev) , &tr );
    if( tr.flFraction < 1.0 ) // assuming we hit a bsp thing, this will be true
    {
        m_iRicochetNumber--;
        Vector vecDir = pev->velocity.Normalize();
        UTIL_SetOrigin( pev, pev->origin - vecDir * 12 );
        float n = -DotProduct(tr.vecPlaneNormal, vecDir);
        m_vecRicochet = 2.0 * tr.vecPlaneNormal * n + vecDir;
        m_bRicochet = true;
        Vector ang = m_vecRicochet;
        ang = UTIL_VecToAngles(ang);
        pev->angles = ang;
        pev->velocity = m_vecRicochet;
        pev->speed = m_vecRicochet.Length();
    }
    }
  }
  else
  {
    SetThink( SUB_Remove );
    pev->nextthink = gpGlobals->time;// this will get changed below if the bolt is allowed to stick in what it hit.

    if ( FClassnameIs( pOther->pev, "worldspawn" ) )
    {
    // if what we hit is static architecture, can stay around for a while.
    Vector vecDir = pev->velocity.Normalize( );
    UTIL_SetOrigin( pev, pev->origin - vecDir * 12 );
    pev->angles = UTIL_VecToAngles( vecDir );
    pev->solid = SOLID_NOT;
    pev->movetype = MOVETYPE_FLY;
    pev->velocity = Vector( 0, 0, 0 );
    pev->avelocity.z = 0;
    pev->angles.z = RANDOM_LONG(0,360);
    pev->nextthink = gpGlobals->time + 10.0;
    }
  }
  /*Mod End*/

  if (UTIL_PointContents(pev->origin) != CONTENTS_WATER)
  {
    UTIL_Sparks( pev->origin );
  }
    }

Ok, I'll go through this code piece... We start by emitting a sound when the bolt hit something. Then we decide if we should ricochet or not. Next we see if it is world stuff that we hit. Then we do some vector stuff (getting a starting and ending point for the UTIL_TraceLine), do the trace line and see if we actually hit something (tr.flFraction < 1.0). Next is the ricochet calculations, must of this comes from the gauss gun. (It is interesting to read up on dot product on the net.) The most important part here is that we store the ricochet vector, I'll explain later on.

Also, just before the end of this function change the following from:
 CODE  
if ( g_pGameRules->IsMultiplayer() )
 

to
 CODE  
if(( g_pGameRules->IsMultiplayer() ) && (m_iRicochetNumber <= 1))

We don't want the arrow to explode just yet.

Next find void CCrossbowBolt::BubbleThink( void ) and add to the top of this function the following:
 CODE  
if(m_bRicochet)
{
m_bRicochet = false;
pev->velocity = m_vecRicochet;
}

Here is why we need to store the vector: It seems that the game engine is brighter than I thought. If you just change the vector in BoltTouch, then it seems that the engine add the old vector and new vector, which then cancel out (zeros) the changed dimension of the velocity vector. Weird but it does. Also I assume it's the engine that does this because nowhere in the SDK code is any hint of this.

Right that's all, you can save crossbow.cpp

Another quirk I found (while figuring out the problems with the ricocheting of arrows) is that the arrow completely penetrates what every it hits before sending the call to BoltTouch. That's why we move the origin of the arrow when we hit a world space object. I found this by setting BOLT_AIR_VELOCITY to a very low value, say 10 or 100. Then I fired an arrow and ran to the wall where it will it, and watched what happened.


That's all folks. You can e-mail me at scobra@ananzi.co.za for comments and questions.

Rate This Article
This article is currently rated: 4.3 out of 5.0 (3 Votes)

You have to register to rate this article.
User Comments Showing comments 1-2

Posted By: whitedragon on Apr 12 2004 at 19:23:44
Error found in part of coding i found out that if you set :

m_vecRicochet = 10.0 * tr.vecPlaneNormal * n + vecDir;

to


m_vecRicochet = 1000.0 * tr.vecPlaneNormal * n + vecDir;

This would fix the problem when the arrow would hit the wall and then come back and hit the other wall.Edited by whitedragon on Apr 12 2004, 19:43:59

Posted By: thisismyname09 on Oct 16 2005 at 11:09:04
would you be able to use this to make bullets bounce off of walls/ or does it only work w/ the crossbow?


You must register to post a comment. If you have already registered, you must login.

Latest Articles
3rd person View in Multiplayer
Half-Life 2 | Coding | Client Side Tutorials
How to enable it in HL2DM

By: cct | Nov 13 2006

Making a Camera
Half-Life 2 | Level Design
This camera is good for when you join a map, it gives you a view of the map before you join a team

By: slackiller | Mar 04 2006

Making a camera , Part 2
Half-Life 2 | Level Design
these cameras are working monitors that turn on when a button is pushed.

By: slackiller | Mar 04 2006

Storing weapons on ladder
Half-Life 2 | Coding | Snippets
like Raven Sheild or BF2

By: British_Bomber | Dec 24 2005

Implementation of a string lookup table
Half-Life 2 | Coding | Snippets
A string lookup table is a set of functions that is used to convert strings to pre-defined values

By: deathz0rz | Nov 13 2005


Latest Comments
Spinning Corpses Simple Fix
Half-Life | Coding | Snippets
By: darkPhoenix | Sep 05 2008
 
Where do we go from here
General | News
By: MIFUNE | Jun 09 2008
 
The Input/Output system
Half-Life 2 | Level Design
By: nazitaco | Dec 23 2007
 
Where do we go from here
General | News
By: Rob_F | Nov 22 2007
 
Rescaling Half-Life
Half-Life | Coding | Shared Tutorials
By: christoph | Nov 12 2007
 
GameUI
Half-Life 2 | Coding | Client Side Tutorials
By: Evil_j | Oct 29 2007
 
3 State Zoom For Any Weapon
Half-Life 2 | Coding | Server Side Tutorials
By: Ennuified | Oct 18 2007
 
Storing weapons on ladder
Half-Life 2 | Coding | Snippets
By: cct | Sep 07 2007
 
CTF Gameplay Part 1
Half-Life | Coding | Shared Tutorials
By: DarkNight | Aug 28 2007
 
CTF Gameplay Part 1
Half-Life | Coding | Shared Tutorials
By: deedok | Aug 20 2007
 

Site Info
296 Approved Articless
5 Pending Articles
3940 Registered Members
0 People Online (43 guests)
About - Credits - Contact Us

Wavelength version: 3.0.0.9
Valid XHTML 1.0! Valid CSS!