Wirehead Studios

Wirehead Modifications => General Development ('Laced Neptune') => Topic started by: Orbital-S2D on 2016-02-29, 02:25



Title: Modifying the shotgun
Post by: Orbital-S2D on 2016-02-29, 02:25
I would like to changed the spread of the shotgun. I would like to do something similar to com/cq3 where the spread is consistent and circular. How can I achieve this

Thanks!


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-02-29, 20:17
I'm not familiar with what com/cq3 is... however, you can change the spread of the shotgun to be non-random pretty easily.  You'll want to look at this function in g_weapon.c:

Code:
// this should match CG_ShotgunPattern
void ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, gentity_t *ent ) {
int i;
float r, u;
vec3_t end;
vec3_t forward, right, up;
int oldScore;
qboolean hitClient = qfalse;

// derive the right and up vectors from the forward vector, because
// the client won't have any other information
VectorNormalize2( origin2, forward );
PerpendicularVector( right, forward );
CrossProduct( forward, right, up );

oldScore = ent->client->ps.persistant[PERS_SCORE];

// generate the "random" spread pattern
for ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT ; i++ ) {
r = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
u = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
VectorMA( origin, 8192 * 16, forward, end);
VectorMA (end, r, right, end);
VectorMA (end, u, up, end);
if( ShotgunPellet( origin, end, ent ) && !hitClient ) {
hitClient = qtrue;
ent->client->accuracy_hits++;
}
}
}

You'll notice the value DEFAULT_SHOTGUN_SPREAD.  That's a defined constant that's set in bg_public.h:

Code:
#define DEFAULT_SHOTGUN_SPREAD 700

The r and u values stand for "right" and "up".  A shot in Q3 is calculated forward from the player by 8192 units, then right and up perpendicular to that line by the values "r" and "u"  What the current shotgun code does is takes a seeded random and multiplies it by the spread value, and then by 16.  The seeded random is not a true random, it's a pattern determined by the "seed" number.  This calculation is duplicated on the client-side to save on network code.  This was done because Q3 was written when dialup modems were the norm, so bandwidth savings was important then.  The thing to remember now is that the same math has to be run on the client and server.  More on that later.  For now, what you need to do is figure out the size you want the pattern, and then replace the "r" and "u" calculations with fixed distances from the forward line.  Since this function is running a loop from 0 to DEFAULT_SHOTGUN_COUNT (defined in bg_public.h as 11), you have 11 pellets to distribute, though if you want to change that you can.  Just change the 11 to another value, but be mindful of the damage increase since damage is calculated per-pellet.  Anyway, what you want to do is use the loop counter "i" to determine where each pellet is going to be.  There's two ways to do this.  You can calculate the r and u values (think X and Y on a graph) in horizontal and vertical lines, or you can calculate them radially from a center point using sin and cos functions.  For the first method, just graph out your pattern, then set hard values for r and u based on what i is.  Example:

Code:
if (i == 0)
{
  r = -18;
  u = 350;
}
if (i == 1)
{
 r = 18
 u = 350;
}
// etc...
For the second method, use i to determine which pellet number you're on, calculate a degree value (remember that sin and cos are in RADIANS, so if you're using degrees you'll need to use DEG2RAD to convert them), then multiply from the center point by a fixed distance, where dist is your distance value, angle = (desired degrees) * i, and r = dist * cos(DEG2RAD(angle)), and u = dist * sin(DEG2RAD(angle)).  I might have cos and sin backward, but you get the idea.  So if you want 6 pellets that will be adding 60 degrees every time i increments, and then you'll have to multiply by a distance - however far you want - from center up until i == 6.  Remember, we're starting at 0, so 0 to 5 is 6 pellets.  After that, assuming you're still using 11 pellets total, you'll need to calculate 72 degrees every time i increments, then calculate out however far out you want your second ring to be.

Just remember that whatever changes you do to ShotgunPattern in g_weapon.c need to be mirrored in CG_ShotgunPattern in cg_weapons.c or the visual representation of the server-side damage traces will be out of sync.  You will need to compile both qagame.qvm and cgame.qvm any time you change these or if you change any file beginning with bg_.

Hope that helps!


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-02-29, 22:26
AWESOME! You are the man!

I mean CPM/CQ3 by the way. Challenge ProMode and Challenge Quake 3 from Challenge ProMode Arena.

here is a pic of cpma shotgun blast.


Title: Re: Modifying the shotgun
Post by: ~Va^^pyrA~ on 2016-03-01, 01:39
That spread pattern is very aesthetically pleasing. Though now, I really want it to look like a star, or a heart, or something. LOL :)


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-03-01, 18:06
Technically I am the bird, but that looks like a radial calculation alright.  :doom_thumb:


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-01, 18:23
Trying to figure it out is not very awesome.



Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-01, 21:38
My head popped... I never liked plotting points.

GAH!!!


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-03-01, 22:05
I am not too fond of mathematics myself.  It's necessary for programming, yes, but I find it to be the most frustrating of obstacles.  Still, if you want it enough you'll find a way to make it work.  My programming efforts for Generations consist of 99% answered prayer, 0.9999% pure stubbornness, and 0.00001% actual ability on my part.  The remaining 0.00009% I attribute to quantum fluctuations of dark energy interacting with Heisenberg's uncertainty principle to create pure and utter BS that for some reason results in functioning code that I don't understand why it even works, yet somehow it does.

Or for a visual reference, my programming process ends up being something like this (though not as cute):

https://i.chzbgr.com/full/8752820480/h213BA74D/


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-01, 22:39
I do better when I have something to go on. if you could give me an example of what im trying to do then im good.... otherwise I sit and stare and say duh. :)

I think there is something in the CPM docs. I should put those up for sharing too... :P


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-03-01, 23:37
I don't have time to tinker tonight, but I think I might be able to whip up an example calculation in the next day or two.


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-03-02, 19:28
Here, try this:

In g_weapon.c, change ShotgunPattern to this:

Code:
// this should match CG_ShotgunPattern
void ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, gentity_t *ent ) {
int i;
float r, u;
vec3_t end;
vec3_t forward, right, up;
int oldScore;
qboolean hitClient = qfalse;

float range;


// derive the right and up vectors from the forward vector, because
// the client won't have any other information
VectorNormalize2( origin2, forward );
PerpendicularVector( right, forward );
CrossProduct( forward, right, up );

oldScore = ent->client->ps.persistant[PERS_SCORE];

// generate the "random" spread pattern
for ( i = 0 ; i < 16 ; i++ ) {

r = sin(DEG2RAD(22.5 + (45 * i)) );
u = cos(DEG2RAD(22.5 + (45 * i)) );

if (i < 8){
range = 175;
} else {
range = 350;
}

r *= range * 16;
u *= range * 16;

VectorMA( origin, 8192 * 16, forward, end);
VectorMA (end, r, right, end);
VectorMA (end, u, up, end);
if( ShotgunPellet( origin, end, ent ) && !hitClient ) {
hitClient = qtrue;
ent->client->accuracy_hits++;
}
}
}

In cg_weapon.c, change CG_ShotgunPattern to this:

Code:
/*
================
CG_ShotgunPattern

Perform the same traces the server did to locate the
hit splashes
================
*/
static void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, int otherEntNum ) {
int i;
float r, u;
vec3_t end;
vec3_t forward, right, up;

float range;

// derive the right and up vectors from the forward vector, because
// the client won't have any other information
VectorNormalize2( origin2, forward );
PerpendicularVector( right, forward );
CrossProduct( forward, right, up );

// generate the "random" spread pattern
for ( i = 0 ; i < 16; i++ ) {

r = sin(DEG2RAD(22.5 + (45 * i)) );
u = cos(DEG2RAD(22.5 + (45 * i)) );

if (i < 8){
range = 175;
} else {
range = 350;
}

r *= range * 16;
u *= range * 16;
VectorMA( origin, 8192 * 16, forward, end);
VectorMA (end, r, right, end);
VectorMA (end, u, up, end);

CG_ShotgunPellet( origin, end, otherEntNum );
}
}

That should produce a pattern like what you're looking for.  I've hard coded in "16" for the count and the two range values for the rings, but you can modify those however you like.  If you prefer to use DEFAULT_SHOTGUN_COUNT and DEFAULT_SHOTGUN_SPREAD #define statements, by all means do so.  I just hard coded the values to make it easier to interpret here.

Note that the sin/cos calculations use 45 degrees.  That's 360/8 since we're doing 8 pellets per ring, and I've rotated it by 22.5 degrees so that the top and sides are flat instead of points.  Since we're making a full circle once i == 8, I change the range calculation based on whether i is between 0 and 7, and between 8 and 15 so that one circle is twice the distance from center.  If you change the count, say, to 12 and want 6 pellets per ring, you'd use 60 degrees (360/6), and 30 degrees for the offset, and your range would be based on 0 to 5, and 6 to 11.  Also, if you want a "dead center" pellet, you can start with a special case for i == 0, then just offset your range loop calculations by 1.

One thing to note:  just be aware of how Q3 handles CrossProduct calculations... if you have an asymmetrical pattern, aiming up and down can cause the pattern to flip because the "right" and "up" vectors become inverted.  For example, if you had pellets in a flat line from left to right, similar to how Doom's shotgun works, then aim at the ceiling, it will flip to running the pellets top to bottom.  I had to ditch CrossProduct and calculate the angles differently for Doom's weapons in Generations, so try to stick with even pellet counts - 4, 6, 8, 10, etc, so that any flipping of the pattern is irrelevant.


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-02, 23:34
If i kept
DEFAULT_SHOTGUN_COUNT
but changed it to 16
and remove the
DEFAULT_SHOTGUN_SPREAD above it in bg_public.h

then for ( i = 0 ; i < 16; i++ ) would need to be changed to

for ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT; i++ )

? or did i just completely miss the boat :P


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-03-03, 00:11
You can certainly do it that way.  In fact, you could still use both the #defined values.  If you went into bg_public.h, you could do something like this:

in bg_public.h:

Code:
#define DEFAULT_SHOTGUN_COUNT 16;  // MAKE SURE THIS IS AN EVEN NUMBER!!
#define DEFAULT_SHOTGUN_SPREAD 700;

Then change your shotgun gun code to work like this:

Code:
// this should match CG_ShotgunPattern
void ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, gentity_t *ent ) {
int i;
float r, u;
vec3_t end;
vec3_t forward, right, up;
int oldScore;
qboolean hitClient = qfalse;

        float range;  // How far away from center we're placing our pellets.
        int interval;  // How many times we're incrementing.
        float deg;  // How many degrees we're rotating by.  This should be half the total count.

        interval = DEFAULT_SHOTGUN_COUNT;
        if (interval <= 0){   // I always sanity check for divide by zero when doing a divide by any variable.
                interval = 16;
        }
        deg = 360 / 0.5f * interval;

// derive the right and up vectors from the forward vector, because
// the client won't have any other information
VectorNormalize2( origin2, forward );
PerpendicularVector( right, forward );
CrossProduct( forward, right, up );

oldScore = ent->client->ps.persistant[PERS_SCORE];

// generate the "random" spread pattern
for ( i = 0 ; i < interval ; i++ ) {

r = sin(DEG2RAD( (0.5f * deg) + (deg * i)) );
u = cos(DEG2RAD( (0.5f * deg ) + (deg * i)) );

if (i < interval * 0.5){
range = 0.5f * DEFAULT_SHOTGUN_SPREAD;
} else {
range = DEFAULT_SHOTGUN_SPREAD;
}

r *= range * 16;
u *= range * 16;

VectorMA( origin, 8192 *16, forward, end);
VectorMA (end, r, right, end);
VectorMA (end, u, up, end);
if( ShotgunPellet( origin, end, ent ) && !hitClient ) {
hitClient = qtrue;
ent->client->accuracy_hits++;
}
}
}

Mirror those changes in CG_ShotgunPattern and Then all you have to do is edit DEFAULT_SHOTGUN_COUNT to determine how many pellets you want, and DEFAULT_SHOTGUN_SPREAD to determine the size of the pattern.  The degree calculations and how many pellets per ring are completely automated at this point, so you can grow or shrink your pattern size by changing one number, and increase or decrease your pellet count by changing one number.  Pretty nifty, eh?


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-03, 00:46
Ah yes.. then we need to be concerned about  define_shotgun_damage

10 is default which means that 110 dmg is dealt at point blank with original shotgun
16 pellets with 10 dmg would be 160 dmg at pointblank.

so if i changed def_sg_count to 20
and changed def_sg_dmg too 5.5
that would keep the dmg at the q3 default.

and 20 would be an even number >:) oooh this could get fun :>

You know what would be really cool and unique if the inside of the outer ring were randomized hah.

I cannot test the code yet because in a turn of shxtty events my cpu fan just died... so next week i will be up and running. i wanted an excuse to upgrade my cpu from an i5 to an i7 anyway. im going to also add another 8gigs of ram.

Im so greatful for you help phoe... thanks


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-03, 01:50
Just to verify because i am going to use unlagged :)

Code:
// this should match CG_ShotgunPattern
void ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, gentity_t *ent ) {
int i;
float r, u;
vec3_t end;
vec3_t forward, right, up;
int oldScore;
qboolean hitClient = qfalse;


//Phoenix/Orb —— Shotgun
        float range;  // How far away from center we're placing our pellets.
        int interval;  // How many times we're incrementing.
        float deg;  // How many degrees we're rotating by.  This should be half the total count.

        interval = DEFAULT_SHOTGUN_COUNT;
        if (interval <= 0){   // I always sanity check for divide by zero when doing a divide by any variable.
                interval = 16;
        }
        deg = 360 / 0.5f * interval;
//Phoenix/Orb — — Shotgun

//unlagged - attack prediction #2
// use this for testing
//Com_Printf( "Server seed: %d\n", seed );
//unlagged - attack prediction #2

// derive the right and up vectors from the forward vector, because
// the client won't have any other information
VectorNormalize2( origin2, forward );
PerpendicularVector( right, forward );
CrossProduct( forward, right, up );

oldScore = ent->client->ps.persistant[PERS_SCORE];

//unlagged - backward reconciliation #2
// backward-reconcile the other clients
G_DoTimeShiftFor( ent );
//unlagged - backward reconciliation #2

// generate the “Phoenix/Orb” spread pattern
for ( i = 0 ; i < interval ; i++ ) {

r = sin(DEG2RAD( (0.5f * deg) + (deg * i)) );
u = cos(DEG2RAD( (0.5f * deg ) + (deg * i)) );

if (i < interval * 0.5){
range = 0.5f * DEFAULT_SHOTGUN_SPREAD;
} else {
range = DEFAULT_SHOTGUN_SPREAD;
}

r *= range * 16;
u *= range * 16;

VectorMA( origin, 8192 *16, forward, end);
VectorMA (end, r, right, end);
VectorMA (end, u, up, end);
if( ShotgunPellet( origin, end, ent ) && !hitClient ) {
hitClient = qtrue;
ent->client->accuracy_hits++;
}
}

//unlagged - backward reconciliation #2
// put them back
G_UndoTimeShiftFor( ent );
//unlagged - backward reconciliation #2
}

Look good?

PEW PEW PEW


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-03-03, 17:51
Looks good to me!  :doom_thumb:


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-11, 06:06
Code: (cg_weapons.c)
/*
================
CG_ShotgunPattern

Perform the same traces the server did to locate the
hit splashes
================
*/
static void ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, gentity_t *ent ) {
int i;
float r, u;
vec3_t end;
vec3_t forward, right, up;

        float range;  // How far away from center we're placing our pellets.
        int interval;  // How many times we're incrementing.
        float deg;  // How many degrees we're rotating by.  This should be half the total count.

        interval = DEFAULT_SHOTGUN_COUNT;
        if (interval <= 0){   // I always sanity check for divide by zero when doing a divide by any variable.
                interval = 16;
        }
        deg = 360 / 0.5f * interval;

// derive the right and up vectors from the forward vector, because
// the client won't have any other information
VectorNormalize2( origin2, forward );
PerpendicularVector( right, forward );
CrossProduct( forward, right, up );

// generate the "random" spread pattern
for ( i = 0 ; i < interval ; i++ ) {

r = sin(DEG2RAD( (0.5f * deg) + (deg * i)) );
u = cos(DEG2RAD( (0.5f * deg ) + (deg * i)) );

if (i < interval * 0.5){
range = 0.5f * DEFAULT_SHOTGUN_SPREAD;
} else {
range = DEFAULT_SHOTGUN_SPREAD;
}

r *= range * 16;
u *= range * 16;

VectorMA( origin, 8192 *16, forward, end);
VectorMA (end, r, right, end);
VectorMA (end, u, up, end);

CG_ShotgunPellet( origin, end, otherEntNum );
}
}
}

whad i miss?

Code:
XPMUser@xxxxxxxxxxxx-xxxxxxxx ~/q3req
$ make
D:/Mingw/msys/1.0/home/q3dev/q3req/misc/q3lcc.exe -DCGAME -o D:/Mingw/msys/1.0/home/q3dev/q3req/build/win32/baseq3/cgame/cg_weapons.asm D:/Mingw/msys/1.0/home/q3dev/q3req/code/cgame/cg_weapons.c
D:/Mingw/msys/1.0/home/q3dev/q3req/code/cgame/cg_weapons.c:2392: missing parameter type
D:/Mingw/msys/1.0/home/q3dev/q3req/code/cgame/cg_weapons.c:2392: syntax error; found `*' expecting `)'
D:/Mingw/msys/1.0/home/q3dev/q3req/code/cgame/cg_weapons.c:2392: skipping `*' `ent'
D:/Mingw/msys/1.0/home/q3dev/q3req/code/cgame/cg_weapons.c:2433: undeclared identifier `otherEntNum'
D:/Mingw/msys/1.0/home/q3dev/q3req/code/cgame/cg_weapons.c:2436: unrecognized declaration
make: *** [D:/Mingw/msys/1.0/home/q3dev/q3req/build/win32/baseq3/cgame/cg_weapons.asm] Error 1

XPMUser@VirtualXP-42519 ~/q3req


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-03-11, 18:46
You have an extra close bracket directly under CG_ShotgunPellet( origin, end, otherEntNum );.  Remove that bracket and it should compile.


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-11, 18:57
 :wall: :wall: :wall: :wall: :wall:

omg..........Well in my defence it was 12am... I was excited because I just had gotten my computer back up and running.. I have 16gb of ram now :)


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-11, 22:38
Hmm strange I must have missed something

I can see that it is wanting to turn around the center of the screen ...
these are all separate shots


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-11, 22:41
and  what I mean is



Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-03-12, 13:23
One other thing I did notice is you have a gentity_t at the end of your arguments to CG_ShotgunPattern.  That should be an "int otherEntNum".  That shouldn't really affect the spread pattern itself but it may affect the drawing of impact marks.


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-12, 22:46
/*
==================
ReQWave Shotgun Spread
Thanks Phoenix Gen Arena
This should match CG_ShotgunPattern
==================
*/
void ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, gentity_t *ent ) {
   int         i;
   float      r, u;
   vec3_t      end;
   vec3_t      forward, right, up;
   int         oldScore;
   qboolean   hitClient = qfalse;

        float range;  // How far away from center we're placing our pellets.
        int interval;  // How many times we're incrementing.
        float deg;  // How many degrees we're rotating by.  This should be half the total count.

        interval = DEFAULT_SHOTGUN_COUNT;
        if (interval <= 0){   // I always sanity check for divide by zero when doing a divide by any variable.
                interval = 16;
        }
        deg = 360 / 0.5f * interval;

// derive the right and up vectors from the forward vector, because
   // the client won't have any other information
   VectorNormalize2( origin2, forward );
   PerpendicularVector( right, forward );
   CrossProduct( forward, right, up );

   oldScore = ent->client->ps.persistant[PERS_SCORE];

   // generate the "random" spread pattern
   for ( i = 0 ; i < interval ; i++ ) {

      r = sin(DEG2RAD( (0.5f * deg) + (deg * i)) );
      u = cos(DEG2RAD( (0.5f * deg ) + (deg * i)) );

      if (i < interval * 0.5){
         range = 0.5f * DEFAULT_SHOTGUN_SPREAD;
       } else {
         range = DEFAULT_SHOTGUN_SPREAD;
      }

      r *= range * 16;
      u *= range * 16;

      VectorMA( origin, 8192 *16, forward, end);
      VectorMA (end, r, right, end);
      VectorMA (end, u, up, end);
      if( ShotgunPellet( origin, end, ent ) && !hitClient ) {
         hitClient = qtrue;
         ent->client->accuracy_hits++;
      }
   }
}



/*
================
CG_ShotgunPattern
ReQWave Thanks Phoenix Gen Arena
Perform the same traces the server did to locate the
hit splashes
================
*/
static void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, int otherEntNum ) {
   int         i;
   float      r, u;
   vec3_t      end;
   vec3_t      forward, right, up;

        float range;  // How far away from center we're placing our pellets.
        int interval;  // How many times we're incrementing.
        float deg;  // How many degrees we're rotating by.  This should be half the total count.

        interval = DEFAULT_SHOTGUN_COUNT;
        if (interval <= 0){   // I always sanity check for divide by zero when doing a divide by any variable.
                interval = 16;
        }
        deg = 360 / 0.5f * interval;

// derive the right and up vectors from the forward vector, because
   // the client won't have any other information
   VectorNormalize2( origin2, forward );
   PerpendicularVector( right, forward );
   CrossProduct( forward, right, up );

   // generate the "random" spread pattern
   for ( i = 0 ; i < interval ; i++ ) {

      r = sin(DEG2RAD( (0.5f * deg) + (deg * i)) );
      u = cos(DEG2RAD( (0.5f * deg ) + (deg * i)) );

      if (i < interval * 0.5){
         range = 0.5f * DEFAULT_SHOTGUN_SPREAD;
       } else {
         range = DEFAULT_SHOTGUN_SPREAD;
      }

      r *= range * 16;
      u *= range * 16;

      VectorMA( origin, 8192 *16, forward, end);
      VectorMA (end, r, right, end);
      VectorMA (end, u, up, end);

      CG_ShotgunPellet( origin, end, otherEntNum );
   }
}



bg_public.h

#define DEFAULT_SHOTGUN_SPREAD   700
#define DEFAULT_SHOTGUN_COUNT   16 (i tried 20 first)


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-03-13, 09:07
So... is it working ok?  :doom_?:


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-13, 10:49
Oh I'm sorry... No it's still drawing only 2 pellets.


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-03-14, 00:26
So the rotation isn't working but the distance offset is, so it's returning 0 degrees from the sin and cos functions, and the up/down/left/right positioning is CrossProduct skewing the axis data.  The lack of rotation is acting like an integer is being returned from a divide operation when a float should be.  It may need a typecast in there.  I'll tinker with it tomorrow and see what's not working correctly.


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-14, 15:05
Hmmm... Just an FYI I have been using a ioq3 based source. And I noticed team stats mod doesn't work. It won't show the armor or health of the teammates.

Another coding friend said this.
Quote
char *teamstat;
  if (cgs.clientinfo[cg.crosshairClientNum].health)
  {
    teamstat = va("Health: %i Armor: %i",
                cgs.clientinfo[ cg.crosshairClientNum ].health,
                cgs.clientinfo[ cg.crosshairClientNum ].armor);

    w = CG_DrawStrlen(teamstat) * SMALLCHAR_WIDTH;

    CG_DrawSmallString(320 - w / 2, 190, teamstat, color[3] * 0.5f);
  }

The code does not work because 'cgs.clientinfo[cg.crosshairClientNum].health' is always zero. If you comment out the 'if' statement then the health and armor values are displayed but they are always shown as zero regardless of which player you point the crosshair to.

It seems that in this version of ioquake3 the required information is not sent to the cgame module. Actually, it does not have to know the health and armor values of other players for correct operation. The comment in 'cg_local.h' before the definition of the  'clientinfo_t' structure says that you get this info only for teammates, but apparently that is not true.

BTW the above code snippet is sloppy because the 'if' statement should also check if the other player is a teammate of the local client, so that displaying junk info (zero health/armor) for enemy team members is avoided.

The way I found out was the following:

1. Tried to print the static string 'foobar' instead of the content of 'teamstate' --> nothing
2. Tried to use CG_DrawBigString (to see if CG_DrawSmallString did not work for some reason) --> nothing
3. Commented out the 'if' statement --> got health and armor shown as zero

It was then obvious that the clause of the 'if' was always false, so nothing was displayed. Searched the cgame sources to see if 'cgs.clientinfo[cg.crosshairClientNum].health' is ever updated, but it is done only for the local client. This kind of experimenting is very useful when you want to locate the source of a bug. Also 'Com_Printf' can be very useful to dump the current values of variables at different points in the code.


I don't know if this may help with the shotgun pattern at all but because of changes like this I maybe changing my base source...


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-03-14, 23:02
It's not the ioquake3 source for the shotgun issue.  It's me forgetting how to math.  Here's the fix for the shotgun pattern.  Change this line in both ShotgunPattern and CG_ShotgunPattern:

        deg = 360 / 0.5f * interval;

to this:

        deg = 360.0f / (0.5f * interval);

That will fix the 2 pellet issue.  The reason is order of operations.  It was doing this:

when interval = 12

360 / 0.5 = 720
720 * 12 = 8640

When what we wanted was this:

0.5 * 12 = 6

360 / 6 = 60.

That's all because I forgot the ( and ).  I'm great at hacking functions together, but I tend to screw up the math a lot.   :P

Now you will notice that by using 12 pellets the pattern will flip due to PerpendicularVector and CrossProduct being implemented crappy.  If you use 16 pellets it's not noticeable.  If you decide you want to ditch the PerpendicularVector and CrossProduct so your pattern is always consistent, then here's how to get around that.

The shotgun code sends the forward vector along with the event to the client.  What we're going to do is replace the forward vector with the player's viewangles instead.  Why Id didn't do this to begin with is beyond me, but it works.  What we'll do is derive the forward, right, and up vectors from the angle vector on the client just like the server does so it will match up perfectly and without flipping our right and up vectors around when we look in different directions.

In g_weapon.c, make this change to ShotgunPattern:

Code:
// Phoenix - remarking this out.  The static forward, right, and up vectors are already derived from
// ent->client->ps.viewangles in the FireWeapon function, so we don't need to recalculate them.

// derive the right and up vectors from the forward vector, because
   // the client won't have any other information
//   VectorNormalize2( origin2, forward );
//   PerpendicularVector( right, forward );
//   CrossProduct( forward, right, up );

Next, again in g_weapon.c, look at weapon_supershotgun_fire and make this change:

Code:
void weapon_supershotgun_fire (gentity_t *ent) {
gentity_t *tent;

// send shotgun blast
tent = G_TempEntity( muzzle, EV_SHOTGUN );
// Phoenix - remarking this out.
// VectorScale( forward, 4096, tent->s.origin2 );

// Phoenix - Send the view angles with the event instead of the forward vector.  We can derive the
// forward, right, and up vectors from that on the client.
VectorCopy(ent->client->ps.viewangles, tent->s.origin2);
// Phoenix - remarking this out.  We don't want to snap this - it needs to be precise.
// SnapVector( tent->s.origin2 );
tent->s.eventParm = rand() & 255; // seed for spread pattern
tent->s.otherEntityNum = ent->s.number;

ShotgunPattern( tent->s.pos.trBase, tent->s.origin2, tent->s.eventParm, ent );
}

In cg_weapons.c, make this change to CG_ShotgunPattern:

Code:
// Phoenix - remark all this stuff out.  We're not using it anymore.

// derive the right and up vectors from the forward vector, because
   // the client won't have any other information
//   VectorNormalize2( origin2, forward );
//   PerpendicularVector( right, forward );
//   CrossProduct( forward, right, up );


// Phoenix - we sent our angles in the origin2 vector, so we'll just derive them from that like the server does.
// This will prevent the pattern from flipping so we can use asymmetrical spreads if we want.

AngleVectors (origin2, forward, right, up);

Now your shotgun pattern shouldn't flip around.  You can use 12 pellets and it will be consistent wherever you look.


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-14, 23:18
PEMDAS

Haha
I'll let you know how it works


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-15, 01:27
Quote from: g_weapon.c
/*
==================
ReQWave Shotgun Spread
Thanks Phoenix Gen Arena
This should match CG_ShotgunPattern
==================
*/
void ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, gentity_t *ent ) {
   int         i;
   float      r, u;
   vec3_t      end;
   vec3_t      forward, right, up;
   int         oldScore;
   qboolean   hitClient = qfalse;

        float range;  // How far away from center we're placing our pellets.
        int interval;  // How many times we're incrementing.
        float deg;  // How many degrees we're rotating by.  This should be half the total count.

        interval = DEFAULT_SHOTGUN_COUNT;
        if (interval <= 0){   // I always sanity check for divide by zero when doing a divide by any variable.
                interval = 16;
        }
        deg = 360 / (0.5f * interval);

// Phoenix - remarking this out.  The static forward, right, and up vectors are already derived from
// ent->client->ps.viewangles in the FireWeapon function, so we don't need to recalculate them.
// derive the right and up vectors from the forward vector, because
   // the client won't have any other information
   //VectorNormalize2( origin2, forward );
   //PerpendicularVector( right, forward );
   //CrossProduct( forward, right, up );

   oldScore = ent->client->ps.persistant[PERS_SCORE];

   // generate the "random" spread pattern
   for ( i = 0 ; i < interval ; i++ ) {

      r = sin(DEG2RAD( (0.5f * deg) + (deg * i)) );
      u = cos(DEG2RAD( (0.5f * deg ) + (deg * i)) );

      if (i < interval * 0.5){
         range = 0.5f * DEFAULT_SHOTGUN_SPREAD;
       } else {
         range = DEFAULT_SHOTGUN_SPREAD;
      }

      r *= range * 16;
      u *= range * 16;

      VectorMA( origin, 8192 *16, forward, end);
      VectorMA (end, r, right, end);
      VectorMA (end, u, up, end);
      if( ShotgunPellet( origin, end, ent ) && !hitClient ) {
         hitClient = qtrue;
         ent->client->accuracy_hits++;
      }
   }
}


/*void
weapon_supershotgun_fire(gentity_t * ent)
{
  gentity_t *tent;

  // send shotgun blast
  tent = G_TempEntity(muzzle, EV_SHOTGUN);
  VectorScale(forward, 4096, tent->s.origin2);
  SnapVector(tent->s.origin2);
  tent->s.eventParm = rand() & 255;   // seed for spread pattern
  tent->s.otherEntityNum = ent->s.number;

  ShotgunPattern(tent->s.pos.trBase, tent->s.origin2, tent->s.eventParm, ent);
}
*/

//ReQWave Phoenix Shotgun Spread
void weapon_supershotgun_fire (gentity_t *ent) {
   gentity_t      *tent;

   // send shotgun blast
   tent = G_TempEntity( muzzle, EV_SHOTGUN );
// Phoenix - remarking this out.
//   VectorScale( forward, 4096, tent->s.origin2 );

// Phoenix - Send the view angles with the event instead of the forward vector.  We can derive the
// forward, right, and up vectors from that on the client.
   VectorCopy(ent->client->ps.viewangles, tent->s.origin2);
// Phoenix - remarking this out.  We don't want to snap this - it needs to be precise.
//   SnapVector( tent->s.origin2 );
   tent->s.eventParm = rand() & 255;      // seed for spread pattern
   tent->s.otherEntityNum = ent->s.number;

   ShotgunPattern( tent->s.pos.trBase, tent->s.origin2, tent->s.eventParm, ent );
}


Quote from: cg_weapons.c
/*
================
CG_ShotgunPattern
ReQWave Thanks Phoenix Gen Arena
Perform the same traces the server did to locate the
hit splashes
================
*/
static void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, int otherEntNum ) {
   int         i;
   float      r, u;
   vec3_t      end;
   vec3_t      forward, right, up;

        float range;  // How far away from center we're placing our pellets.
        int interval;  // How many times we're incrementing.
        float deg;  // How many degrees we're rotating by.  This should be half the total count.

        interval = DEFAULT_SHOTGUN_COUNT;
        if (interval <= 0){   // I always sanity check for divide by zero when doing a divide by any variable.
                interval = 16;
        }
        deg = 360 / 0.5f * interval;

// Phoenix - remark all this stuff out.  We're not using it anymore.

// derive the right and up vectors from the forward vector, because
   // the client won't have any other information
//   VectorNormalize2( origin2, forward );
//   PerpendicularVector( right, forward );
//   CrossProduct( forward, right, up );

// Phoenix - we sent our angles in the origin2 vector, so we'll just derive them from that like the server does.
// This will prevent the pattern from flipping so we can use asymmetrical spreads if we want.

   AngleVectors (origin2, forward, right, up);

   // generate the "random" spread pattern
   for ( i = 0 ; i < interval ; i++ ) {

      r = sin(DEG2RAD( (0.5f * deg) + (deg * i)) );
      u = cos(DEG2RAD( (0.5f * deg ) + (deg * i)) );

      if (i < interval * 0.5){
         range = 0.5f * DEFAULT_SHOTGUN_SPREAD;
       } else {
         range = DEFAULT_SHOTGUN_SPREAD;
      }

      r *= range * 16;
      u *= range * 16;

      VectorMA( origin, 8192 *16, forward, end);
      VectorMA (end, r, right, end);
      VectorMA (end, u, up, end);

      CG_ShotgunPellet( origin, end, otherEntNum );
   }
}

Quote from: bg_public.h
#define DEFAULT_SHOTGUN_SPREAD   700
#define DEFAULT_SHOTGUN_COUNT   16

I attached the VM


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-15, 11:06
Now the pellets don't flip around the center of the screen but it's still only two.


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-03-15, 17:24
You remembered the ( and ) in ShotgunPattern, but forgot them in CG_ShotgunPattern.  :smirk:


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-15, 17:32
Derp.... And after I picked at you about order of operations...


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-03-15, 17:39
(https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcQAGiBkRszc_Hgf28pENpEkyfx0QlC1aToD8IpEZ_N6kx_jTSCGmw)


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-15, 17:54
Lmfao


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-15, 22:25
:doom_thumb: :doom_thumb: :doom_thumb:
:slippy_thumb: :slippy_thumb: :slippy_thumb:
:biggun: :biggun: :biggun:


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-15, 23:32
In an interesting turn of events the pattern works great but shotgun does no damage,

I tried to change the default shotgun damage from 10 to 5.5. i though that if that was a decimal maybe it was wrong. so i changed it to a whole number. 6 and still had no damage. i changed it to 10 and still had no damage. i scaned over the modifications too the code and best i can tell the code is sound. so what actually causes the shotgun damage?


this part looks the same between the orig and the mod
    if (ShotgunPellet(origin, end, ent) && !hitClient)
     {
       hitClient = qtrue;
       ent->client->accuracy_hits++;
     }

I dont know why it wouldnt work. maybe im looking in the wrong spot


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-03-15, 23:51
ShotgunPellet is what actually does the damage, in this statement:

damage = DEFAULT_SHOTGUN_DAMAGE * s_quadFactor;

ShotgunPellet is called each iteration of the loop in ShotgunPattern.  It's definitely calling it... I'm going to see what's going on.


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-03-16, 00:25
Ahh, I found the problem.  It's a leftover gib from the crossproduct stuff in ShotgunPattern.  Remark out the line I've noted below:

Code:
void ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, gentity_t *ent ) {
   int         i;
   float      r, u;
   vec3_t      end;
// Phoenix - We don't need these local vectors overriding the static vectors or we'll lose our angle data.
//   vec3_t      forward, right, up;
   int         oldScore;
   qboolean   hitClient = qfalse;

The forward, right, and up vectors here are local to the function, but at the very beginning of g_weapon.c you'll see the same variable names as static vec3_t.  Static vars are "global" vars within that file that retain their data between functions, as opposed to local vars within the function that are not accessible to other functions unless passed in an argument.  The static vars are derived from the player's view angles in FireWeaon.  Using the same variable names for both global and local variables is BAD PROGRAMMING TECHNIQUE!!!  BAD DUFFY!!  BAD, BAD DUFFY!!  SHAME ON YOU!!!  :wall:

So remark that line out and the damage traces will work properly.  Do NOT remark the line out in CG_ShotgunPattern because the ones used there are local;  there's no static versions in that file so CG_ShotgunPattern is coded properly.


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-16, 00:26
it seems you have to aim high and point-blank to hit. also in the face

here is a vm


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-03-16, 00:27
You posted as I was working on my post.  See my previous post to this one.  :doom_thumb:


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-16, 01:11
That is fantastic! its is working great!


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-25, 02:36
so I broke my shotgun :/

I merged the unlagged code into mine since unlagged is GPLed now...
I only had one hiccup in cg_draw.c and it threw me for a loop. I left an extra { in the code :P

anyway unlagged makes this change in the CG_ShotgunPattern
Code:
//unlagged - attack prediction
// made this non-static for access from cg_unlagged.c
void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, int otherEntNum ) {
int i;
float r, u;
vec3_t end;
vec3_t forward, right, up;

That's fine because when cg_delag is 0 the shotgun works great. but when cg_delag is 1
it doesn't draw a pattern at all.

I found this part in cg_unlagged.c
Code:
// was it a shotgun attack?
else if ( ent->weapon == WP_SHOTGUN ) {
// do we have it on for the shotgun?
if ( cg_delag.integer & 1 || cg_delag.integer & 4 ) {
int contents;
vec3_t endPoint, v;

// do everything like the server does

SnapVector( muzzlePoint );

VectorScale( forward, 4096, endPoint );
SnapVector( endPoint );

VectorSubtract( endPoint, muzzlePoint, v );
VectorNormalize( v );
VectorScale( v, 32, v );
VectorAdd( muzzlePoint, v, v );

if ( cgs.glconfig.hardwareType != GLHW_RAGEPRO ) {
// ragepro can't alpha fade, so don't even bother with smoke
vec3_t up;

contents = trap_CM_PointContents( muzzlePoint, 0 );
if ( !( contents & CONTENTS_WATER ) ) {
VectorSet( up, 0, 0, 8 );
CG_SmokePuff( v, up, 32, 1, 1, 1, 0.33f, 900, cg.time, 0, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader );
}
}

// do the shotgun pellets
CG_ShotgunPattern( muzzlePoint, endPoint, cg.oldTime % 256, cg.predictedPlayerState.clientNum );
//Com_Printf( "Predicted shotgun pattern\n" );
}
}


and at the bottom the //do the shotgun pellets doesn't match what is in the CG_ShotgunFire

Bleh


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-03-25, 22:01
I'm not familiar with unlagged's codebase.  I'm sure it's fixable... a pattern is just a pattern, but I'd need to see the unmodified CG shotgun stuff for unlagged to see what exactly they're doing in comparison to normal Q3.


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-25, 22:10
Well after I posted this last night I looked into it a bit deeper and I think it has something to do with the game module. I ran out of time looking.

This is the source that I used.
http://ioquake3.org/files/unlagged-2.01-src-gpl.zip


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-03-25, 22:11
I meant to add that the cg_delag.integer takes over and then processes it in g/cg_unlagged.c


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-04-03, 14:35
Well I just noticed that the shotgun pattern is drawing. Just at random places depending o. Where you point the muzzle. Even behind you.
Another friend of mine said this
Code:
The only possible reason I can imagine is that at some point the unlagged code uses different data/function/calculation than the normal weapon code. Getting hits behind you indicates that the wrong vector component of the view angle is manipulated to calculate the position of hits. I see one diff between the relevant code of 'ShotgunPattern' in 'g_weapon.c' and that of 'CG_ShotgunPattern' in 'cg_weapon.c':

AngleVectors (origin2, forward, right, up);

In cgame you derive the angle vectors from data sent by the server. But unlagged manipulates the player state to do reconciliation


Looking into the anglevectors.


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-04-03, 21:32
I have the unlagged code, I've just been taking a break from programming for a bit.  I'll take a look into it tomorrow.


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-04-03, 23:18
No rush!


Title: Re: Modifying the shotgun
Post by: Phoenix on 2016-04-06, 21:06
I took a look at it, and I see what's happening.  The unlagged code is sending the endpoint and reconciling a forward vector instead of using the angle vectors we were sending from the server.  Since we're predicting the shotgun blast, we'll want to look at the cg.predictedPlayerState to grab the view angles.  Assuming you are using the CG_ShotgunPattern we put together, make these changes in cg_unlagged.c to the CG_PredictWeaponEffects function where noted:

Code:
// was it a shotgun attack?
else if ( ent->weapon == WP_SHOTGUN ) {
// do we have it on for the shotgun?
if ( cg_delag.integer & 1 || cg_delag.integer & 4 ) {
int contents;
vec3_t endPoint, v;

// do everything like the server does

                       
SnapVector( muzzlePoint );

VectorScale( forward, 4096, endPoint );
SnapVector( endPoint );

VectorSubtract( endPoint, muzzlePoint, v );
VectorNormalize( v );
VectorScale( v, 32, v );
VectorAdd( muzzlePoint, v, v );

if ( cgs.glconfig.hardwareType != GLHW_RAGEPRO ) {
// ragepro can't alpha fade, so don't even bother with smoke
vec3_t up;

contents = trap_CM_PointContents( muzzlePoint, 0 );
if ( !( contents & CONTENTS_WATER ) ) {
VectorSet( up, 0, 0, 8 );
CG_SmokePuff( v, up, 32, 1, 1, 1, 0.33f, 900, cg.time, 0, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader );
}
}

// do the shotgun pellets
                        // Phoenix - use the predicted view angles with our new shotgunpattern.
CG_ShotgunPattern( muzzlePoint, cg.predictedPlayerState.viewangles, cg.oldTime % 256, cg.predictedPlayerState.clientNum );
//Com_Printf( "Predicted shotgun pattern\n" );
}
}

In theory that should fix the problem.


Title: Re: Modifying the shotgun
Post by: Orbital-S2D on 2016-04-08, 02:02
that seems to have worked well! thanks