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
| | | int m_iRicochetNumber; Vector m_vecRicochet; bool m_bRicochet;
| These are the member variables that we will use.
Find void CCrossbowBolt::Spawn( ) and add
| | | 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:
| | | SetTouch( NULL ); SetThink( NULL );
|
to
| | | if(m_iRicochetNumber <= 1) { SetTouch( NULL ); SetThink( NULL ); }
|
We would like to keep on thinking until the last ricochet.
Still in this function find: *
| | | if (pOther->pev->takedamage) {
|
add inside this "if" statement:
| | | 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:
| | | 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
| | | 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:
| | | if ( g_pGameRules->IsMultiplayer() ) |
to
| | | 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:
| | | 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. |
|
User Comments
Showing comments 1-2
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
|
|
|
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.
|
296 Approved Articless
5 Pending Articles
3940 Registered Members
0 People Online (43 guests)
|
|