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: 5146
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 13 2004 at 01: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 13 2004, 01:43:59

Posted By: thisismyname09 on Oct 16 2005 at 17: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 05 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
knock knock
General | News
By: MIFUNE | Dec 31 2017
 
knock knock
General | News
By: omega | Dec 22 2016
 
knock knock
General | News
By: MIFUNE | Oct 10 2015
 
New HL HUD Message System
Half-Life | Coding | Shared Tutorials
By: chbrules | Dec 31 2011
 
knock knock
General | News
By: Whistler | Nov 05 2011
 
Particle Engine tutorial part 4
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 18 2010
 
Particle Engine tutorial part 2
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 11 2010
 
Particle Engine tutorial part 3
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 11 2010
 
Game Movement Series #2: Analog Jumping and Floating
Half-Life 2 | Coding | Shared Tutorials
By: mars3554 | Oct 26 2009
 
Particle Engine tutorial part 5
Half-Life | Coding | Client Side Tutorials
By: Deadpool | Aug 02 2009
 

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

Wavelength version: 3.0.0.9
Valid XHTML 1.0! Valid CSS!