IPB

Welcome Guest ( Log In | Register )

 
Reply to this topicStart new topic
> Code Contribution, Ricochet and Penetration code
Puzzlemaker
post Jun 4 2006, 01:22 AM
Post #1


Private
*

Group: Members
Posts: 5
Joined: 4-June 06
Member No.: 4,715



Here ya go! I hope you like it! Penetration and Ricochet code! Modify it as you see fit/ask me to modify it to match your game!

There are a few bugs with it, however. The penetration code doesn't work for entities... I need to find a function in which you pass in a vector, and it returns if your inside a solid entity. Another problem is that I havn't gotten around to enabling the tracers with the ricochet code, so I disabled them or it would look stupid.

The code was done using the HL2MP code, AKA the deathmatch code, so I dont know how well it will translate to a game based on the HL2 single-palyer code. I think this mod is based on the MP code, so it shouldn't be an issue.

Here is the modified firebullets function. It goes in baseentity_shared.cpp

CODE
/*
================
FireBullets

Go to the trouble of combining multiple pellets into a single damage call.
================
*/

void CBaseEntity::FireBullets( const FireBulletsInfo_t &info )
{
    static int    tracerCount;
    trace_t  tr;
    CAmmoDef*    pAmmoDef    = GetAmmoDef();
    int      nDamageType    = pAmmoDef->DamageType(info.m_iAmmoType);
    int      nAmmoFlags    = pAmmoDef->Flags(info.m_iAmmoType);
    
    bool bDoServerEffects = true;

#if defined( HL2MP ) && defined( GAME_DLL )
    bDoServerEffects = false;
#endif

    int iPlayerDamage = info.m_iPlayerDamage;
    if ( iPlayerDamage == 0 )
    {
 if ( nAmmoFlags & AMMO_INTERPRET_PLRDAMAGE_AS_DAMAGE_TO_PLAYER )
 {
     iPlayerDamage = pAmmoDef->PlrDamage( info.m_iAmmoType );
 }
    }

    // the default attacker is ourselves
    CBaseEntity *pAttacker = info.m_pAttacker ? info.m_pAttacker : this;

    // Make sure we don't have a dangling damage target from a recursive call
    if ( g_MultiDamage.GetTarget() != NULL )
    {
 ApplyMultiDamage();
    }
 
    ClearMultiDamage();
    g_MultiDamage.SetDamageType( nDamageType | DMG_NEVERGIB );

    //Vector vecDir;
    Vector vecEnd;
    
    CTraceFilterSkipTwoEntities traceFilter( this, info.m_pAdditionalIgnoreEnt, COLLISION_GROUP_NONE );

    bool bUnderwaterBullets = ShouldDrawUnderwaterBulletBubbles();
    bool bStartedInWater = false;

    if ( bUnderwaterBullets )
    {
 bStartedInWater = ( enginetrace->GetPointContents( info.m_vecSrc ) & (CONTENTS_WATER|CONTENTS_SLIME) ) != 0;
    }

    // Prediction is only usable on players
    int iSeed = 0;
    if ( IsPlayer() )
    {
 iSeed = CBaseEntity::GetPredictionRandomSeed() & 255;
    }

#if defined( HL2MP ) && defined( GAME_DLL )
    int iEffectSeed = iSeed;
#endif
    //-----------------------------------------------------
    // Set up our shot manipulator.
    //-----------------------------------------------------
    CShotManipulator Manipulator( info.m_vecDirShooting );

    bool bDoImpacts = false;
    bool bDoTracers = false;

    Vector vecTempDir;
    Vector vecTempStart;
    int iRicPenNumber;
    float fBulletStrengthLeft;

    for (int iShot = 0; iShot < info.m_iShots; iShot++)
    {
 iRicPenNumber = 0;
 fBulletStrengthLeft = 2.0f;

 vecTempStart = info.m_vecSrc;

 // If we're firing multiple shots, and the first shot has to be bang on target, ignore spread
 if ( iShot == 0 && info.m_iShots > 1 && (info.m_nFlags & FIRE_BULLETS_FIRST_SHOT_ACCURATE) )
 {
     vecTempDir = Manipulator.GetShotDirection() + info.m_vecAngleModifier;
 }
 else
 {

     // Don't run the biasing code for the player at the moment.
     vecTempDir = Manipulator.ApplySpread( info.m_vecSpread ) + info.m_vecAngleModifier;
 }

 //Begin inner loop.
 //handles damage, triggers, and ricochets and penetration of the bullet.
 do
 {
     bool bHitWater = false;
     bool bHitGlass = false;
     
     // Prediction is only usable on players
     if ( IsPlayer() )
     {
   RandomSeed( iSeed );    // init random system with this seed
     }


     // Make sure given a valid bullet type
     if (info.m_iAmmoType == -1)
     {
   DevMsg("ERROR: Undefined ammo type!\n");
   return;
     }

     vecEnd = (vecTempStart) + (vecTempDir * info.m_flDistance);

     if( IsPlayer() && info.m_iShots > 1 && iShot % 2 )
     {
   // Half of the shotgun pellets are hulls that make it easier to hit targets with the shotgun.
   AI_TraceHull( vecTempStart, vecEnd, Vector( -3, -3, -3 ), Vector( 3, 3, 3 ), MASK_SHOT, &traceFilter, &tr );
     }
     else
     {
   AI_TraceLine(vecTempStart, vecEnd, MASK_SHOT, &traceFilter, &tr);
     }

    #ifdef GAME_DLL
     if ( ai_debug_shoot_positions.GetBool() )
   NDebugOverlay::Line( tr.startpos, vecEnd, 255, 255, 255, false, .1 );
    #endif

     if ( bStartedInWater )
     {
    #ifdef GAME_DLL
   CreateBubbleTrailTracer( tr.startpos, tr.endpos, vecTempDir );
    #endif
   bHitWater = true;
     }

     Vector vecTracerDest = tr.endpos;

     // See if we hit glass
     if ( tr.m_pEnt != NULL )
     {
    #ifdef GAME_DLL
   surfacedata_t *psurf = physprops->GetSurfaceData( tr.surface.surfaceProps );
   if ( ( psurf != NULL ) && ( psurf->game.material == CHAR_TEX_GLASS ) && ( tr.m_pEnt->ClassMatches( "func_breakable" ) ) )
   {
       bHitGlass = true;
   }
    #endif
     }

     // Now hit all triggers along the ray that respond to shots...
     // Clip the ray to the first collided solid returned from traceline
     CTakeDamageInfo triggerInfo( pAttacker, pAttacker, info.m_iDamage, nDamageType );
     CalculateBulletDamageForce( &triggerInfo, info.m_iAmmoType, vecTempDir, tr.endpos );
     triggerInfo.ScaleDamageForce( info.m_flDamageForceScale );
     triggerInfo.SetAmmoType( info.m_iAmmoType );
    #ifdef GAME_DLL
     TraceAttackToTriggers( triggerInfo, tr.startpos, tr.endpos, vecTempDir );
    #endif

     // do damage, paint decals
     if (tr.fraction != 1.0)
     {
    #ifdef GAME_DLL
   UpdateShotStatistics( tr );

   // For shots that don't need persistance
   int soundEntChannel = ( info.m_nFlags&FIRE_BULLETS_TEMPORARY_DANGER_SOUND ) ? SOUNDENT_CHANNEL_BULLET_IMPACT : SOUNDENT_CHANNEL_UNSPECIFIED;

   CSoundEnt::InsertSound( SOUND_BULLET_IMPACT, tr.endpos, 200, 0.5, this, soundEntChannel );
    #endif

   // See if the bullet ended up underwater + started out of the water
   if ( !bHitWater && ( enginetrace->GetPointContents( tr.endpos ) & (CONTENTS_WATER|CONTENTS_SLIME) ) )
   {
       bHitWater = HandleShotImpactingWater( info, vecEnd, &traceFilter, &vecTracerDest );
   }

   float flActualDamage = info.m_iDamage;

   // If we hit a player, and we have player damage specified, use that instead
   // Adrian: Make sure to use the currect value if we hit a vehicle the player is currently driving.
   if ( iPlayerDamage )
   {
       if ( tr.m_pEnt->IsPlayer() )
       {
     flActualDamage = iPlayerDamage;
       }
    #ifdef GAME_DLL
       else if ( tr.m_pEnt->GetServerVehicle() )
       {
     if ( tr.m_pEnt->GetServerVehicle()->GetPassenger() && tr.m_pEnt->GetServerVehicle()->GetPassenger()->IsPlayer() )
     {
         flActualDamage = iPlayerDamage;
     }
       }
    #endif
   }

   int nActualDamageType = nDamageType;
   if ( flActualDamage == 0.0 )
   {
       flActualDamage = g_pGameRules->GetAmmoDamage( pAttacker, tr.m_pEnt, info.m_iAmmoType );
   }
   else
   {
       nActualDamageType = nDamageType | ((flActualDamage > 16) ? DMG_ALWAYSGIB : DMG_NEVERGIB );
   }

   if ( !bHitWater || ((info.m_nFlags & FIRE_BULLETS_DONT_HIT_UNDERWATER) == 0) )
   {
       // Damage specified by function parameter
       CTakeDamageInfo dmgInfo( this, pAttacker, flActualDamage, nActualDamageType );
       CalculateBulletDamageForce( &dmgInfo, info.m_iAmmoType, vecTempDir, tr.endpos );
       dmgInfo.ScaleDamageForce( info.m_flDamageForceScale );
       dmgInfo.SetAmmoType( info.m_iAmmoType );
       tr.m_pEnt->DispatchTraceAttack( dmgInfo, vecTempDir, &tr );
   
       if ( bStartedInWater || !bHitWater || (info.m_nFlags & FIRE_BULLETS_ALLOW_WATER_SURFACE_IMPACTS) )
       {
     if ( bDoServerEffects == true )
     {
         DoImpactEffect( tr, nDamageType );
     }
     else
     {
         bDoImpacts = true;
     }
       }
       else
       {
     // We may not impact, but we DO need to affect ragdolls on the client
     CEffectData data;
     data.m_vStart = tr.startpos;
     data.m_vOrigin = tr.endpos;
     data.m_nDamageType = nDamageType;
     
     DispatchEffect( "RagdollImpact", data );
       }
 
    #ifdef GAME_DLL
       if ( nAmmoFlags & AMMO_FORCE_DROP_IF_CARRIED )
       {
     // Make sure if the player is holding this, he drops it
     Pickup_ForcePlayerToDropThisObject( tr.m_pEnt );  
       }
    #endif
   }
   //if you hit glass, dont ricochet or penetrate!  Let the hit glass function handle that!
   if(!bHitGlass)
   {
       //The code to get the bullet to ricochet; this was ripped from the crossbow code.

       //calculate the vector, making sure to convert it to angles and back to vector
       //to get the lower possible form.  I dont know a better way to do this.
       Vector vecBulletDistance = (tr.endpos - tr.startpos);
       float test = VectorNormalize(vecBulletDistance);
       QAngle angTemp;
       VectorAngles(vecBulletDistance, angTemp);
       // See if we should reflect off this surface
       AngleVectors(angTemp, &vecBulletDistance);
       float hitDot = DotProduct( tr.plane.normal, -vecBulletDistance );

       //Now we get the hitDot modifier.

       surfacedata_t *pSurf = physprops->GetSurfaceData( tr.surface.surfaceProps );

       //this is very confusing, but just trust me; its a good way to decide if the
       //bullet should ricochet.
       //BUGBUG: If hitdot is lower then 0, it is hitting from the wrong side, AKA the inside of
       //an object.  Added in  && hitDot > 0 to fight this.

       if ( hitDot < (((pSurf->physics.density/3000)+pSurf->physics.elasticity)/2) && hitDot > 0)
       {
     //this decides the angle of the bullet after ricochet.
     //the RandomVector gives you a 5 degree angle change.
     vecTempDir = 2.0f * tr.plane.normal * hitDot + vecBulletDistance + RandomVector(-0.04362, 0.04362);
     //make sure we are shooting the next bullet from the ricochet point!
     vecTempStart = tr.endpos;

     fBulletStrengthLeft -= hitDot*2;
       }
       else if((fBulletStrengthLeft - (pSurf->physics.density/6000)) > 0 && hitDot > 0)
       {
     //What this does is it checks to see when a bullet goes through an object.
     vecTempStart = tr.endpos;
     int iNumSteps = 0;

     while(fBulletStrengthLeft > 0 && iNumSteps < 20)
     {
         //MORE OUR CHECKING THINGY AHEAD A LITTLE BIT.
         vecTempStart += vecTempDir * 2;

         //As the bullet travels through the object, it loses strength.
         fBulletStrengthLeft -= (pSurf->physics.density/6000);
         if( !(enginetrace->GetPointContents( vecTempStart ) & MASK_SHOT) )
         {
       /*trace_t tr2;
       UTIL_TraceLine(vecTempStart, tr.endpos, MASK_SHOT, &traceFilter, &tr2);
       DoImpactEffect( tr2, nDamageType );*/
       break;
       //HERE IS THE PART I AM HAVING TROUBLE WITH.
       //CURRENTLY IT WORKS WITH BRUSHES.
       //However, I dont know how to check if a vector is inside a solid entity!
       //Also, the function GetPointContents (See above) that returns how solid it is
       //can also be passed in a **IHandleEntity or something, which returns what type of
       //entity is at that point.  Thus far, I was unable to get it to work.
       //So, right here, I need to put in some sort of code that checks
       //to see if there is an entity at vecTempStart, and if it is solid.
       //if it is solid, do nothing; if it isn't, break out of the loop
       //so the bullet will continue.
       
       //RIGHT NOW it checks to see if its inside a brush with the enginetrace->GetPointContents
       //function.  If it isn't solid, then break, so we stop decrementing fBulletStrengthLeft
       //and continue.  Remember, you can pass something else into GetPointContents
       //But I dont know how IHandleEntity works.
         }
         iNumSteps++;
     }
     if(iNumSteps >= 20)
     {
         //if the bullet didn't exit the solid, then...
         fBulletStrengthLeft = 0;
     }
       }
       else
       {
     //if its not going to ricochet or penetrate, then its strength left is 0.
     fBulletStrengthLeft = 0;
       }
   }
   else
   {
       // Pass through the glass.
       //BUGBUG:  Bullet strength gets reset after glass is hit!
       //Creates a new bullet!
     #ifdef GAME_DLL
       HandleShotImpactingGlass( info, tr, vecTempDir, &traceFilter );
     #endif
   }

     }
     else
     {
   //lets get out of this do while loop!
   //It didn't hit anything, so set it for 0.
   fBulletStrengthLeft = 0;
     }
     

     
     //Tracer code needs to be fixed so they work with ricochets.
     //Commenting out for now.

     /*if ( ( info.m_iTracerFreq != 0 ) && ( tracerCount++ % info.m_iTracerFreq ) == 0 && ( bHitGlass == false ) )
     {
   if ( bDoServerEffects == true )
   {
       Vector vecTracerSrc = vec3_origin;
       ComputeTracerStartPosition( info.m_vecSrc, &vecTracerSrc );

       trace_t Tracer;
       Tracer = tr;
       Tracer.endpos = vecTracerDest;
       MakeTracer( vecTracerSrc, Tracer, pAmmoDef->TracerType(info.m_iAmmoType) );
   }
   else
   {
       bDoTracers = true;
   }
     }*/

     iRicPenNumber++;
     iSeed++;
 }
 while(fBulletStrengthLeft > 0 && iRicPenNumber < 6);
    }

#if defined( HL2MP ) && defined( GAME_DLL )
    if ( bDoServerEffects == false )
    {
 TE_HL2MPFireBullets( entindex(), tr.startpos, info.m_vecDirShooting, info.m_iAmmoType, iEffectSeed, info.m_iShots, info.m_vecSpread.x, bDoTracers, bDoImpacts );
    }
#endif

#ifdef GAME_DLL
    ApplyMultiDamage();
#endif
}


This post has been edited by Puzzlemaker: Jun 4 2006, 01:28 AM
Go to the top of the page
 
+Quote Post
Forlorn_Hope
post Jun 4 2006, 10:36 AM
Post #2


Cat Herder in Chief
Group Icon

Group: BG Dev. Team
Posts: 1,712
Joined: 29-October 03
From: The land of plain speaking
Member No.: 2,023



If this works, definatly a hearty thanks o_O


--------------------
"There will be no more naked sunbathing." An actual rule for the base I was on, in the middle of Afghanistan.

"Forlorn basically said everything right." Codename:V
Go to the top of the page
 
+Quote Post
Monkwarrior
post Jun 4 2006, 11:03 AM
Post #3


Captain
******

Group: Members
Posts: 400
Joined: 10-September 05
Member No.: 3,974



Excellent work !
I hope the coders can use it in a new version :cool:

Monk.
Go to the top of the page
 
+Quote Post
Puzzlemaker
post Jun 4 2006, 01:30 PM
Post #4


Private
*

Group: Members
Posts: 5
Joined: 4-June 06
Member No.: 4,715



It worked when I tested it. However, a few wierd things started turning up...

The ricochet code looks at the density of the surface it hits and desides if it should ricochet off or attempt to penetrate through, meaning denser surfaces (Stone, Metal) are easier to ricochet off of, and can be hit at around a 45 degree angle.

However, it turns out that the default density of grass is higher then that of wood... around 3X higher. You might want to change it if you add this in.

Also, the penetration code is a little... overpowered? It also is based on density, but you may want to decrease its power, because as is it can go through 5 concrete walls...
Go to the top of the page
 
+Quote Post
McGee
post Jun 4 2006, 02:01 PM
Post #5


Corporal
**

Group: Members
Posts: 29
Joined: 28-May 06
Member No.: 4,681



Would deff be a great feature if it was implimented grin.gif
Go to the top of the page
 
+Quote Post
Skillet5151
post Jun 4 2006, 05:52 PM
Post #6


Lieutennant
*****

Group: Members
Posts: 135
Joined: 26-August 03
Member No.: 1,791



GetPointContents should work for solid model based entities too AFAIK, not sure why it isn't for you.
Go to the top of the page
 
+Quote Post
Tjoppen
post Jun 4 2006, 09:49 PM
Post #7


Major
Group Icon

Group: Team Leader
Posts: 994
Joined: 11-May 03
Member No.: 1,207



Looks decent. The biggest problem would probably be to make this work with simulated bullets. They do ricochet at the moment(off of anything that's more than 60 degrees angle to the horizon), but they don't penetrate. I think we discussed penetration a while back..
Go to the top of the page
 
+Quote Post
Forlorn_Hope
post Jun 4 2006, 10:02 PM
Post #8


Cat Herder in Chief
Group Icon

Group: BG Dev. Team
Posts: 1,712
Joined: 29-October 03
From: The land of plain speaking
Member No.: 2,023



Yes, I believe most schools do require you to take a health class that would cover such things...


--------------------
"There will be no more naked sunbathing." An actual rule for the base I was on, in the middle of Afghanistan.

"Forlorn basically said everything right." Codename:V
Go to the top of the page
 
+Quote Post
jackx
post Jun 4 2006, 10:04 PM
Post #9


midnight devcult phenomena
Group Icon

Group: Retired Team Members
Posts: 2,260
Joined: 14-May 03
Member No.: 1,223



Musket ball penetration is iffy... maybe if you could link it to dmg, or otherwise have it be reduced drastically over range.

This post has been edited by jackx: Jun 4 2006, 10:05 PM


--------------------
no truth - no justice
all false belief
blinded by morality
there shall be... no peace
no peace!

-------



Go to the top of the page
 
+Quote Post
Puzzlemaker
post Jun 5 2006, 12:37 AM
Post #10


Private
*

Group: Members
Posts: 5
Joined: 4-June 06
Member No.: 4,715



The penetration code would be easy to remove, but the ricochet code should stay in.

Plus, because of the way the code is designed, it would be easy to put in curved trajectories, and I was thinking about implementing it but got a sudden attack of lazyness.
Go to the top of the page
 
+Quote Post
Skillet5151
post Jun 5 2006, 01:11 AM
Post #11


Lieutennant
*****

Group: Members
Posts: 135
Joined: 26-August 03
Member No.: 1,791



QUOTE(Puzzlemaker @ Jun 4 2006, 07:37 PM)
The penetration code would be easy to remove, but the ricochet code should stay in.

Plus, because of the way the code is designed, it would be easy to put in curved trajectories, and I was thinking about implementing it but got a sudden attack of lazyness.
[snapback]21448[/snapback]
I'd like to see what kind of performance impact that approach to realistic ballistics has.

Post the results if you end up trying it.
Go to the top of the page
 
+Quote Post
gecko
post Jun 5 2006, 01:17 AM
Post #12


King Gecko of 1.0F Dev
Group Icon

Group: Admin
Posts: 625
Joined: 20-April 04
Member No.: 2,511



lol penetration </immature>
Go to the top of the page
 
+Quote Post
Puzzlemaker
post Jun 5 2006, 02:08 AM
Post #13


Private
*

Group: Members
Posts: 5
Joined: 4-June 06
Member No.: 4,715



QUOTE(Skillet5151 @ Jun 5 2006, 01:11 AM)
QUOTE(Puzzlemaker @ Jun 4 2006, 07:37 PM)
The penetration code would be easy to remove, but the ricochet code should stay in.

Plus, because of the way the code is designed, it would be easy to put in curved trajectories, and I was thinking about implementing it but got a sudden attack of lazyness.
[snapback]21448[/snapback]
I'd like to see what kind of performance impact that approach to realistic ballistics has.

Post the results if you end up trying it.
[snapback]21450[/snapback]




Hmm, well, it depends on several things.

The way it would work is, it would be like shooting several bullets at once, to simulate a curve. Like, you would figure out the curve of the bullet, then every so and so feet make a bullet fire to the next point so and so feet away, ect.

Depending on how close/far each point is changes the amount of bullets that would be fired, and how far away untill the bullet hits something, so there are a lot of variables. Think it akin to shooting a shotgun.

Edit: If the team want to use the ricochet code and would like to see some bullet-curving action, I would definetly code it.

This post has been edited by Puzzlemaker: Jun 5 2006, 02:11 AM
Go to the top of the page
 
+Quote Post
Skillet5151
post Jun 5 2006, 02:25 AM
Post #14


Lieutennant
*****

Group: Members
Posts: 135
Joined: 26-August 03
Member No.: 1,791



I'm not sure that you'd want to do FireBullets that many times, I'm pretty sure it sends a fair load over the network to clients.

I was thinking more along the lines of making a bootleg TraceLine function that does either GetPointContents every unit or short TraceLines every few units and simulates a curve that way. It would also then be possible to simulate the time it takes for the bullet to move, by putting a varying delay in between each trace/point contents check.
Go to the top of the page
 
+Quote Post
jackx
post Jun 5 2006, 09:27 AM
Post #15


midnight devcult phenomena
Group Icon

Group: Retired Team Members
Posts: 2,260
Joined: 14-May 03
Member No.: 1,223



Worry about how to describe the curve, first. It's a smoothbore musket, and the curve will be different and random for each shot. The ball spins and bounces within the barrel, the barrel surface changes between each shot and the balls would be quite imperfect concerning their shape and surface, the speed also can vary greatly between each shot etc...

The current combination of random CoF and simple flight curve is probably better suited to the muskets... a "proper" flight curve for the rifle(s) would be nice though. smile.gif


--------------------
no truth - no justice
all false belief
blinded by morality
there shall be... no peace
no peace!

-------



Go to the top of the page
 
+Quote Post
Tottel
post Sep 17 2008, 01:53 PM
Post #16


Sergeant
***

Group: Members
Posts: 64
Joined: 26-August 08
From: Belgium
Member No.: 6,997



If you add this piece of code in baseentity_shared.. how are you supposed to test it then? :/
All these files are only found in the svn code folder of BG. And how can you start the game with those codes?
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 User(s) are reading this topic (1 Guests and 0 Anonymous Users)
0 Members:

 



Lo-Fi Version Time is now: 17th August 2019 - 05:47 PM