diff options
| -rw-r--r-- | src/cgame/cg_event.c | 5 | ||||
| -rw-r--r-- | src/cgame/cg_local.h | 1 | ||||
| -rw-r--r-- | src/cgame/cg_weapons.c | 177 | ||||
| -rw-r--r-- | src/game/bg_misc.c | 117 | ||||
| -rw-r--r-- | src/game/bg_public.h | 13 | ||||
| -rw-r--r-- | src/game/g_cmds.c | 51 | ||||
| -rw-r--r-- | src/game/g_weapon.c | 63 | ||||
| -rw-r--r-- | src/game/tremulous.h | 10 | ||||
| -rw-r--r-- | src/ui/ui_main.c | 8 | 
9 files changed, 284 insertions, 161 deletions
diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c index 83d95424..4833346d 100644 --- a/src/cgame/cg_event.c +++ b/src/cgame/cg_event.c @@ -736,6 +736,11 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )        CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm );        break; +    case EV_SHOTGUN: +      DEBUGNAME( "EV_SHOTGUN" ); +      CG_ShotgunFire( es ); +      break; +      case EV_GENERAL_SOUND:        DEBUGNAME( "EV_GENERAL_SOUND" );        if( cgs.gameSounds[ es->eventParm ] ) diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h index b9df770d..2dd28bf2 100644 --- a/src/cgame/cg_local.h +++ b/src/cgame/cg_local.h @@ -1607,6 +1607,7 @@ void        CG_MissileHitWall( weapon_t weapon, weaponMode_t weaponMode, int cli                                 vec3_t origin, vec3_t dir, impactSound_t soundType );  void        CG_MissileHitPlayer( weapon_t weapon, weaponMode_t weaponMode, vec3_t origin, vec3_t dir, int entityNum );  void        CG_Bullet( vec3_t origin, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum ); +void        CG_ShotgunFire( entityState_t *es );  void        CG_TeslaTrail( vec3_t start, vec3_t end, int srcENum, int destENum );  void        CG_AlienZap( vec3_t start, vec3_t end, int srcENum, int destENum ); diff --git a/src/cgame/cg_weapons.c b/src/cgame/cg_weapons.c index 4f5235b2..9af1a76b 100644 --- a/src/cgame/cg_weapons.c +++ b/src/cgame/cg_weapons.c @@ -90,6 +90,75 @@ static void CG_MachineGunEjectBrass( centity_t *cent )  /*  ========================== +CG_ShotgunEjectBrass +========================== +*/ +static void CG_ShotgunEjectBrass( centity_t *cent ) +{ +  localEntity_t *le; +  refEntity_t   *re; +  vec3_t        velocity, xvelocity; +  vec3_t        offset, xoffset; +  vec3_t        v[ 3 ]; +  float         waterScale = 1.0f; + +  if( cg_brassTime.integer <= 0 ) +    return; + +  le = CG_AllocLocalEntity( ); +  re = &le->refEntity; + +  velocity[ 0 ] = 60 + 60 * crandom( ); +  velocity[ 1 ] = 40 + 10 * crandom( ); +  velocity[ 2 ] = 100 + 50 * crandom( ); + +  le->leType = LE_FRAGMENT; +  le->startTime = cg.time; +  le->endTime = le->startTime + cg_brassTime.integer * 3 + cg_brassTime.integer * random( ); + +  le->pos.trType = TR_GRAVITY; +  le->pos.trTime = cg.time; + +  AnglesToAxis( cent->lerpAngles, v ); + +  offset[ 0 ] = 8; +  offset[ 1 ] = 0; +  offset[ 2 ] = 24; + +  xoffset[ 0 ] = offset[ 0 ] * v[ 0 ][ 0 ] + offset[ 1 ] * v[ 1 ][ 0 ] + offset[ 2 ] * v[ 2 ][ 0 ]; +  xoffset[ 1 ] = offset[ 0 ] * v[ 0 ][ 1 ] + offset[ 1 ] * v[ 1 ][ 1 ] + offset[ 2 ] * v[ 2 ][ 1 ]; +  xoffset[ 2 ] = offset[ 0 ] * v[ 0 ][ 2 ] + offset[ 1 ] * v[ 1 ][ 2 ] + offset[ 2 ] * v[ 2 ][ 2 ]; +  VectorAdd( cent->lerpOrigin, xoffset, re->origin ); +  VectorCopy( re->origin, le->pos.trBase ); +   +  if( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) +    waterScale = 0.10f; + +  xvelocity[ 0 ] = velocity[ 0 ] * v[ 0 ][ 0 ] + velocity[ 1 ] * v[ 1 ][ 0 ] + velocity[ 2 ] * v[ 2 ][ 0 ]; +  xvelocity[ 1 ] = velocity[ 0 ] * v[ 0 ][ 1 ] + velocity[ 1 ] * v[ 1 ][ 1 ] + velocity[ 2 ] * v[ 2 ][ 1 ]; +  xvelocity[ 2 ] = velocity[ 0 ] * v[ 0 ][ 2 ] + velocity[ 1 ] * v[ 1 ][ 2 ] + velocity[ 2 ] * v[ 2 ][ 2 ]; +  VectorScale( xvelocity, waterScale, le->pos.trDelta ); + +  AxisCopy( axisDefault, re->axis ); +  re->hModel = cgs.media.shotgunBrassModel; +  le->bounceFactor = 0.3f; + +  le->angles.trType = TR_LINEAR; +  le->angles.trTime = cg.time; +  le->angles.trBase[ 0 ] = rand( )&31; +  le->angles.trBase[ 1 ] = rand( )&31; +  le->angles.trBase[ 2 ] = rand( )&31; +  le->angles.trDelta[ 0 ] = 1; +  le->angles.trDelta[ 1 ] = 0.5; +  le->angles.trDelta[ 2 ] = 0; + +  le->leFlags = LEF_TUMBLE; +  le->leBounceSoundType = LEBS_BRASS; +  le->leMarkType = LEMT_NONE; +} + +/* +==========================  CG_TeslaTrail  ==========================  */ @@ -758,6 +827,10 @@ void CG_RegisterWeapon( int weaponNum )      case WP_CHAINGUN:        weaponInfo->ejectBrassFunc = CG_MachineGunEjectBrass;        break; + +    case WP_SHOTGUN: +      weaponInfo->ejectBrassFunc = CG_ShotgunEjectBrass; +      break;    }  } @@ -1032,13 +1105,10 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent          CG_SetParticleSystemTag( cent->muzzlePS, gun, weapon->weaponModel, "tag_flash" );      } -    //FIXME: this leaves open the possibility for keep a persistent muzzle system going -    //       by hopping between firing buttons -- currently nothing with a persistent -    //       muzzle system has multiple fire modes however      //if the PS is infinite disable it when not firing -    if( !( cent->currentState.eFlags & EF_FIRING ) && -        !( cent->currentState.eFlags & EF_FIRING2 ) && -        !( cent->currentState.eFlags & EF_FIRING3 ) && +    if( ( ( !( cent->currentState.eFlags & EF_FIRING ) && weaponMode == WPM_PRIMARY ) || +          ( !( cent->currentState.eFlags & EF_FIRING2 ) && weaponMode == WPM_SECONDARY ) || +          ( !( cent->currentState.eFlags & EF_FIRING3 ) && weaponMode == WPM_TERTIARY ) ) &&          CG_IsParticleSystemInfinite( cent->muzzlePS ) )      {        CG_DestroyParticleSystem( cent->muzzlePS ); @@ -1845,7 +1915,6 @@ Renders bullet effects.  void CG_Bullet( vec3_t end, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum )  {    trace_t trace; -  int     sourceContentType, destContentType;    vec3_t  start;    // if the shooter is currently valid, calc a source point and possibly @@ -1854,26 +1923,8 @@ void CG_Bullet( vec3_t end, int sourceEntityNum, vec3_t normal, qboolean flesh,    {      if( CG_CalcMuzzlePoint( sourceEntityNum, start ) )      { -      sourceContentType = trap_CM_PointContents( start, 0 ); -      destContentType = trap_CM_PointContents( end, 0 ); - -      // do a complete bubble trail if necessary -      if( ( sourceContentType == destContentType ) && ( sourceContentType & CONTENTS_WATER ) ) -        CG_BubbleTrail( start, end, 32 ); +      CG_BubbleTrail( start, end, 32 ); -      // bubble trail from water into air -      else if( ( sourceContentType & CONTENTS_WATER ) ) -      { -        trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER ); -        CG_BubbleTrail( start, trace.endpos, 32 ); -      } -      // bubble trail from air into water -      else if( ( destContentType & CONTENTS_WATER ) ) -      { -        trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER ); -        CG_BubbleTrail( trace.endpos, end, 32 ); -      } -        // draw a tracer        if( random( ) < cg_tracerChance.value )          CG_Tracer( start, end ); @@ -1886,3 +1937,77 @@ void CG_Bullet( vec3_t end, int sourceEntityNum, vec3_t normal, qboolean flesh,    else      CG_MissileHitWall( WP_MACHINEGUN, WPM_PRIMARY, 0, end, normal, IMPACTSOUND_DEFAULT );  } + +/* +============================================================================ + +SHOTGUN TRACING + +============================================================================ +*/ + +/* +================ +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; +  trace_t   tr; + +  // 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 < SHOTGUN_PELLETS; i++ ) +  { +    r = Q_crandom( &seed ) * SHOTGUN_SPREAD * 16; +    u = Q_crandom( &seed ) * SHOTGUN_SPREAD * 16; +    VectorMA( origin, 8192 * 16, forward, end ); +    VectorMA( end, r, right, end ); +    VectorMA( end, u, up, end ); + +    CG_Trace( &tr, origin, NULL, NULL, end, otherEntNum, MASK_SHOT ); +    CG_BubbleTrail( origin, end, 32 ); + +    if( !( tr.surfaceFlags & SURF_NOIMPACT ) ) +    { +      if( cg_entities[ tr.entityNum ].currentState.eType == ET_PLAYER ) +        CG_MissileHitPlayer( WP_SHOTGUN, WPM_PRIMARY, tr.endpos, tr.plane.normal, tr.entityNum ); +      else if( tr.surfaceFlags & SURF_METALSTEPS ) +        CG_MissileHitWall( WP_SHOTGUN, WPM_PRIMARY, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_METAL ); +      else +        CG_MissileHitWall( WP_SHOTGUN, WPM_PRIMARY, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_DEFAULT ); +    } +  } +} + +/* +============== +CG_ShotgunFire +============== +*/ +void CG_ShotgunFire( entityState_t *es ) +{ +  vec3_t  up; +  vec3_t  v; +  int     contents; + +  VectorSubtract( es->origin2, es->pos.trBase, v ); +  VectorNormalize( v ); +  VectorScale( v, 32, v ); +  VectorAdd( es->pos.trBase, v, v ); +   +  CG_ShotgunPattern( es->pos.trBase, es->origin2, es->eventParm, es->otherEntityNum ); +} + diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c index 185d58b7..aea70b2b 100644 --- a/src/game/bg_misc.c +++ b/src/game/bg_misc.c @@ -2852,6 +2852,28 @@ weaponAttributes_t bg_weapons[ ] =      WUT_HUMANS            //WUTeam_t  team;    },    { +    WP_SHOTGUN,           //int       weaponNum; +    SHOTGUN_PRICE,        //int       price; +    ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int  stages +    SLOT_WEAPON,          //int       slots; +    "shotgun",            //char      *weaponName; +    "Shotgun",            //char      *weaponHumanName; +    SHOTGUN_SHELLS,       //int       quan; +    SHOTGUN_SPAWNCLIPS,   //int       clips; +    SHOTGUN_MAXCLIPS,     //int       maxClips; +    qfalse,               //int       infiniteAmmo; +    qfalse,               //int       usesEnergy; +    SHOTGUN_REPEAT,       //int       repeatRate1; +    0,                    //int       repeatRate2; +    0,                    //int       repeatRate3; +    SHOTGUN_RELOAD,       //int       reloadTime; +    qfalse,               //qboolean  hasAltMode; +    qfalse,               //qboolean  hasThirdMode; +    qtrue,                //qboolean  purchasable; +    0,                    //int       buildDelay; +    WUT_HUMANS            //WUTeam_t  team; +  }, +  {      WP_FLAMER,            //int       weaponNum;      FLAMER_PRICE,         //int       price;      ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int  stages @@ -3733,9 +3755,6 @@ upgradeAttributes_t bg_upgrades[ ] =      "larmour",              //char  *upgradeName;      "Light Armour",         //char  *upgradeHumanName;      "icons/iconu_larmour", -    WP_NONE,                //weapon_t weaponAmmo; -    0,                      //int   ammo; -    0,                      //int   clips;      WUT_HUMANS              //WUTeam_t  team;    },    { @@ -3746,9 +3765,6 @@ upgradeAttributes_t bg_upgrades[ ] =      "helmet",               //char  *upgradeName;      "Helmet",               //char  *upgradeHumanName;      "icons/iconu_helmet", -    WP_NONE,                //weapon_t weaponAmmo; -    0,                      //int   ammo; -    0,                      //int   clips;      WUT_HUMANS              //WUTeam_t  team;    },    { @@ -3759,9 +3775,6 @@ upgradeAttributes_t bg_upgrades[ ] =      "atoxin",               //char  *upgradeName;      "Anti-toxin",           //char  *upgradeHumanName;      "icons/iconu_atoxin", -    WP_NONE,                //weapon_t weaponAmmo; -    0,                      //int   ammo; -    0,                      //int   clips;      WUT_HUMANS              //WUTeam_t  team;    },    { @@ -3772,9 +3785,6 @@ upgradeAttributes_t bg_upgrades[ ] =      "battpack",             //char  *upgradeName;      "Battery Pack",         //char  *upgradeHumanName;      "icons/iconu_battpack", -    WP_NONE,                //weapon_t weaponAmmo; -    0,                      //int   ammo; -    0,                      //int   clips;      WUT_HUMANS              //WUTeam_t  team;    },    { @@ -3785,9 +3795,6 @@ upgradeAttributes_t bg_upgrades[ ] =      "jetpack",              //char  *upgradeName;      "Jet Pack",             //char  *upgradeHumanName;      "icons/iconu_jetpack", -    WP_NONE,                //weapon_t weaponAmmo; -    0,                      //int   ammo; -    0,                      //int   clips;      WUT_HUMANS              //WUTeam_t  team;    },    { @@ -3798,48 +3805,16 @@ upgradeAttributes_t bg_upgrades[ ] =      "bsuit",                                  //char  *upgradeName;      "Battlesuit",                             //char  *upgradeHumanName;      "icons/iconu_bsuit", -    WP_NONE,                //weapon_t weaponAmmo; -    0,                      //int   ammo; -    0,                      //int   clips;      WUT_HUMANS              //WUTeam_t  team;    },    { -    UP_MGCLIP,              //int   upgradeNum; -    MGCLIP_PRICE,           //int   price; +    UP_AMMO,                //int   upgradeNum; +    0,                      //int   price;      ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int  stages      SLOT_NONE,              //int   slots; -    "mgclip",               //char  *upgradeName; -    "1 Rifle Clip",         //char  *upgradeHumanName; +    "ammo",                 //char  *upgradeName; +    "Ammunition",           //char  *upgradeHumanName;      0, -    WP_MACHINEGUN,          //weapon_t weaponAmmo; -    0,                      //int   ammo; -    1,                      //int   clips; -    WUT_HUMANS              //WUTeam_t  team; -  }, -  { -    UP_CGAMMO,              //int   upgradeNum; -    CGAMMO_PRICE,           //int   price; -    ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int  stages -    SLOT_NONE,              //int   slots; -    "cgammo",               //char  *upgradeName; -    "Chaingun bullets",     //char  *upgradeHumanName; -    0, -    WP_CHAINGUN,            //weapon_t weaponAmmo; -    100,                    //int   ammo; -    0,                      //int   clips; -    WUT_HUMANS              //WUTeam_t  team; -  }, -  { -    UP_GAS,                 //int   upgradeNum; -    GAS_PRICE,              //int   price; -    ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int  stages -    SLOT_NONE,              //int   slots; -    "gas",                  //char  *upgradeName; -    "Flamer gas",           //char  *upgradeHumanName; -    0, -    WP_FLAMER,              //weapon_t weaponAmmo; -    200,                    //int   ammo; -    0,                      //int   clips;      WUT_HUMANS              //WUTeam_t  team;    }  }; @@ -3987,46 +3962,6 @@ char *BG_FindIconForUpgrade( int upgrade )  /*  ============== -BG_FindWeaponAmmoForUpgrade -============== -*/ -weapon_t BG_FindWeaponAmmoForUpgrade( int upgrade ) -{ -  int i; - -  for( i = 0; i < bg_numUpgrades; i++ ) -  { -    if( bg_upgrades[ i ].upgradeNum == upgrade ) -      return bg_upgrades[ i ].weaponAmmo; -  } - -  return WP_NONE; -} - -/* -============== -BG_FindAmmoForUpgrade -============== -*/ -void BG_FindAmmoForUpgrade( int upgrade, int *ammo, int *clips ) -{ -  int i; - -  for( i = 0; i < bg_numUpgrades; i++ ) -  { -    if( bg_upgrades[ i ].upgradeNum == upgrade ) -    { -      if( ammo != NULL ) -        *ammo = bg_upgrades[ i ].ammo; - -      if( clips != NULL ) -        *clips = bg_upgrades[ i ].clips; -    } -  } -} - -/* -==============  BG_FindTeamForUpgrade  ==============  */ diff --git a/src/game/bg_public.h b/src/game/bg_public.h index ade44adf..49165a49 100644 --- a/src/game/bg_public.h +++ b/src/game/bg_public.h @@ -339,6 +339,7 @@ typedef enum    WP_BLASTER,    WP_MACHINEGUN, +  WP_SHOTGUN,    WP_CHAINGUN,    WP_FLAMER,    WP_MASS_DRIVER, @@ -373,9 +374,7 @@ typedef enum    UP_JETPACK,    UP_BATTLESUIT, -  UP_MGCLIP, -  UP_CGAMMO, -  UP_GAS, +  UP_AMMO,    UP_NUM_UPGRADES  } upgrade_t; @@ -521,6 +520,8 @@ typedef enum    EV_BULLET_HIT_FLESH,    EV_BULLET_HIT_WALL, +  EV_SHOTGUN, +    EV_MISSILE_HIT,    EV_MISSILE_MISS,    EV_MISSILE_MISS_METAL, @@ -1045,10 +1046,6 @@ typedef struct    char      *icon; -  weapon_t  weaponAmmo; -  int       ammo; -  int       clips; -      WUTeam_t  team;  } upgradeAttributes_t; @@ -1164,8 +1161,6 @@ char      *BG_FindNameForUpgrade( int upgrade );  int       BG_FindUpgradeNumForName( char *name );  char      *BG_FindHumanNameForUpgrade( int upgrade );  char      *BG_FindIconForUpgrade( int upgrade ); -weapon_t  BG_FindWeaponAmmoForBuildable( int upgrade ); -void      BG_FindAmmoForUpgrade( int upgrade, int *ammo, int *clips );  WUTeam_t  BG_FindTeamForUpgrade( int upgrade );  // content masks diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index 6bc84ed9..3662a8ab 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -1338,7 +1338,6 @@ void Cmd_Buy_f( gentity_t *ent )    }    else if( upgrade != UP_NONE )    { -    int       maxAmmo, newAmmo, newClips;      weapon_t  weaponAmmo;      //already got this? @@ -1382,33 +1381,11 @@ void Cmd_Buy_f( gentity_t *ent )        return;      } -    BG_FindAmmoForUpgrade( upgrade, &newAmmo, &newClips ); - -    if( newAmmo || newClips ) -    { -      //get current ammo for the weapon in question -      weaponAmmo = BG_FindWeaponAmmoForUpgrade( upgrade ); -      BG_unpackAmmoArray( weaponAmmo, ent->client->ps.ammo, ent->client->ps.powerups, -                          &quan, &clips, &maxClips ); +    weaponAmmo = ent->client->ps.weapon; -      BG_FindAmmoForWeapon( weaponAmmo, &maxAmmo, NULL, NULL ); - -      //this ammo package would exceed max ammo -      if( clips + newClips > maxClips ) -      { -        //FIXME: different dialog? -        G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOSLOTS ); -        return; -      } -      else -        clips += newClips; - -      if( quan + newAmmo > maxAmmo ) -        quan = maxAmmo; -      else -        quan += newAmmo; - -      //updata ammo count +    if( upgrade == UP_AMMO && !BG_FindUsesEnergyForWeapon( weaponAmmo ) ) +    { +      BG_FindAmmoForWeapon( weaponAmmo, &quan, &clips, &maxClips );        BG_packAmmoArray( weaponAmmo, ent->client->ps.ammo, ent->client->ps.powerups,                          quan, clips, maxClips );      } @@ -1430,8 +1407,14 @@ void Cmd_Buy_f( gentity_t *ent )    if( numItems == 0 )      G_AddEvent( ent, EV_NEXT_WEAPON, ent->client->ps.clientNum ); -  //retrigger the armoury menu -  ent->client->retriggerArmouryMenu = level.framenum + RAM_FRAMES; +  if( trap_Argc( ) >= 2 ) +  { +    trap_Argv( 2, s, sizeof( s ) ); +     +    //retrigger the armoury menu +    if( !Q_stricmp( s, "retrigger" ) ) +      ent->client->retriggerArmouryMenu = level.framenum + RAM_FRAMES; +  }    //update ClientInfo    ClientUserinfoChanged( ent->client->ps.clientNum ); @@ -1506,8 +1489,14 @@ void Cmd_Sell_f( gentity_t *ent )    else      trap_SendServerCommand( ent-g_entities, va( "print \"Unknown item\n\"" ) ); -  //retrigger the armoury menu -  ent->client->retriggerArmouryMenu = level.framenum + RAM_FRAMES; +  if( trap_Argc( ) >= 2 ) +  { +    trap_Argv( 2, s, sizeof( s ) ); +     +    //retrigger the armoury menu +    if( !Q_stricmp( s, "retrigger" ) ) +      ent->client->retriggerArmouryMenu = level.framenum + RAM_FRAMES; +  }    //update ClientInfo    ClientUserinfoChanged( ent->client->ps.clientNum ); diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c index 4dd1d67e..107128b5 100644 --- a/src/game/g_weapon.c +++ b/src/game/g_weapon.c @@ -159,6 +159,66 @@ void bulletFire( gentity_t *ent, float spread, int damage, int mod )  /*  ====================================================================== +SHOTGUN + +====================================================================== +*/ + +// 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; +	trace_t		tr; +	gentity_t	*traceEnt; + +	// 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 < SHOTGUN_PELLETS; i++ ) +  { +		r = Q_crandom( &seed ) * SHOTGUN_SPREAD * 16; +		u = Q_crandom( &seed ) * SHOTGUN_SPREAD * 16; +		VectorMA( origin, 8192 * 16, forward, end ); +		VectorMA( end, r, right, end ); +		VectorMA( end, u, up, end ); +		 +    trap_Trace( &tr, origin, NULL, NULL, end, ent->s.number, MASK_SHOT ); +    traceEnt = &g_entities[ tr.entityNum ]; + +    // send bullet impact +    if( !( tr.surfaceFlags & SURF_NOIMPACT ) ) +    { +      if( traceEnt->takedamage ) +        G_Damage( traceEnt, ent, ent, forward, tr.endpos,	SHOTGUN_DMG, 0, MOD_SHOTGUN ); +    } +	} +} + + +void shotgunFire( 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 ); +} + +/* +====================================================================== +  MASS DRIVER  ====================================================================== @@ -1120,6 +1180,9 @@ void FireWeapon( gentity_t *ent )      case WP_MACHINEGUN:        bulletFire( ent, RIFLE_SPREAD, RIFLE_DMG, MOD_MACHINEGUN );        break; +    case WP_SHOTGUN: +      shotgunFire( ent ); +      break;      case WP_CHAINGUN:        bulletFire( ent, CHAINGUN_SPREAD, CHAINGUN_DMG, MOD_CHAINGUN );        break; diff --git a/src/game/tremulous.h b/src/game/tremulous.h index ca7c48d8..7694887d 100644 --- a/src/game/tremulous.h +++ b/src/game/tremulous.h @@ -291,6 +291,16 @@  #define RIFLE_SPREAD                200  #define RIFLE_DMG                   HDM(5) +#define SHOTGUN_SHELLS              8 +#define SHOTGUN_PELLETS             8 //used to sync server and client side +#define SHOTGUN_SPAWNCLIPS          3 +#define SHOTGUN_MAXCLIPS            3 +#define SHOTGUN_REPEAT              1200 +#define SHOTGUN_RELOAD              2000 +#define SHOTGUN_PRICE               150 +#define SHOTGUN_SPREAD              900 +#define SHOTGUN_DMG                 HDM(5) +  #define CHAINGUN_BULLETS            300  #define CHAINGUN_REPEAT             50  #define CHAINGUN_PRICE              200 diff --git a/src/ui/ui_main.c b/src/ui/ui_main.c index bf32f974..5a98d881 100644 --- a/src/ui/ui_main.c +++ b/src/ui/ui_main.c @@ -3486,7 +3486,7 @@ static void UI_LoadTremHumanArmouryBuys( )        uiInfo.tremHumanArmouryBuyList[ j ].text =          String_Alloc( BG_FindHumanNameForWeapon( i ) );        uiInfo.tremHumanArmouryBuyList[ j ].cmd = -        String_Alloc( va( "cmd buy %s", BG_FindNameForWeapon( i ) ) ); +        String_Alloc( va( "cmd buy %s retrigger", BG_FindNameForWeapon( i ) ) );        uiInfo.tremHumanArmouryBuyList[ j ].infopane =          UI_FindInfoPaneByName( va( "%sitem", BG_FindNameForWeapon( i ) ) ); @@ -3506,7 +3506,7 @@ static void UI_LoadTremHumanArmouryBuys( )        uiInfo.tremHumanArmouryBuyList[ j ].text =          String_Alloc( BG_FindHumanNameForUpgrade( i ) );        uiInfo.tremHumanArmouryBuyList[ j ].cmd = -        String_Alloc( va( "cmd buy %s", BG_FindNameForUpgrade( i ) ) ); +        String_Alloc( va( "cmd buy %s retrigger", BG_FindNameForUpgrade( i ) ) );        uiInfo.tremHumanArmouryBuyList[ j ].infopane =          UI_FindInfoPaneByName( va( "%sitem", BG_FindNameForUpgrade( i ) ) ); @@ -3536,7 +3536,7 @@ static void UI_LoadTremHumanArmourySells( )      {        uiInfo.tremHumanArmourySellList[ j ].text = String_Alloc( BG_FindHumanNameForWeapon( i ) );        uiInfo.tremHumanArmourySellList[ j ].cmd = -        String_Alloc( va( "cmd sell %s", BG_FindNameForWeapon( i ) ) ); +        String_Alloc( va( "cmd sell %s retrigger", BG_FindNameForWeapon( i ) ) );        uiInfo.tremHumanArmourySellList[ j ].infopane =          UI_FindInfoPaneByName( va( "%sitem", BG_FindNameForWeapon( i ) ) ); @@ -3552,7 +3552,7 @@ static void UI_LoadTremHumanArmourySells( )      {        uiInfo.tremHumanArmourySellList[ j ].text = String_Alloc( BG_FindHumanNameForUpgrade( i ) );        uiInfo.tremHumanArmourySellList[ j ].cmd = -        String_Alloc( va( "cmd sell %s", BG_FindNameForUpgrade( i ) ) ); +        String_Alloc( va( "cmd sell %s retrigger", BG_FindNameForUpgrade( i ) ) );        uiInfo.tremHumanArmourySellList[ j ].infopane =          UI_FindInfoPaneByName( va( "%sitem", BG_FindNameForUpgrade( i ) ) );  | 
