diff options
| author | Michael Levin <risujin@fastmail.fm> | 2009-10-03 11:26:51 +0000 | 
|---|---|---|
| committer | Tim Angus <tim@ngus.net> | 2013-01-03 00:15:00 +0000 | 
| commit | 0cf04fe37fef2e827a95bb19926a3cbf8e98c581 (patch) | |
| tree | 93ac01309f47edb27be26fb31e3886f6082579b1 /src | |
| parent | d9709deb95375f2462e5ca9fc98ebf92fd91ce04 (diff) | |
* Added charge meter to the UI, can be disabled via GUI
* Trample and Lucifer Cannon charging reworked and moved to PMove
* Can no longer "cancel" a charging Lucifer Cannon
* STAT_MISC2 is now unused, booster and charge information can be inferred elsewhere (STAT_UNUSED)
* Trying to fire an empty weapon makes a clicking noise (also a bugfix, apparently the server would spam EV_NOAMMO which did nothing but is now used for the clicking noise -- audible to all players)
* Created an alternate, muffled Lucifer Cannon warning noise for other people's Lucifer Cannons
* Fixed bug which prevented players from switching to a different player while spectating someone in the spawn queue
* Spectators are now properly moved to the lock view position when spectating a player in the spawn queue
Diffstat (limited to 'src')
| -rw-r--r-- | src/cgame/cg_draw.c | 141 | ||||
| -rw-r--r-- | src/cgame/cg_event.c | 4 | ||||
| -rw-r--r-- | src/cgame/cg_local.h | 8 | ||||
| -rw-r--r-- | src/cgame/cg_main.c | 6 | ||||
| -rw-r--r-- | src/cgame/cg_view.c | 2 | ||||
| -rw-r--r-- | src/cgame/cg_weapons.c | 33 | ||||
| -rw-r--r-- | src/game/bg_misc.c | 15 | ||||
| -rw-r--r-- | src/game/bg_pmove.c | 192 | ||||
| -rw-r--r-- | src/game/bg_public.h | 4 | ||||
| -rw-r--r-- | src/game/g_active.c | 93 | ||||
| -rw-r--r-- | src/game/g_buildable.c | 2 | ||||
| -rw-r--r-- | src/game/g_cmds.c | 31 | ||||
| -rw-r--r-- | src/game/g_local.h | 1 | ||||
| -rw-r--r-- | src/game/g_missile.c | 13 | ||||
| -rw-r--r-- | src/game/g_weapon.c | 22 | ||||
| -rw-r--r-- | src/game/tremulous.h | 32 | 
16 files changed, 364 insertions, 235 deletions
diff --git a/src/cgame/cg_draw.c b/src/cgame/cg_draw.c index 08433c44..5002fc9a 100644 --- a/src/cgame/cg_draw.c +++ b/src/cgame/cg_draw.c @@ -588,21 +588,15 @@ CG_DrawPlayerBoosterBolt  */  static void CG_DrawPlayerBoosterBolt( rectDef_t *rect, vec4_t color, qhandle_t shader )  { -  vec4_t        localColor; -  playerState_t *ps = &cg.snap->ps; +  vec4_t localColor;    Vector4Copy( color, localColor ); -  if( ps->stats[ STAT_STATE ] & SS_BOOSTED ) -  { -    if( ps->stats[ STAT_MISC2 ] < 3000 ) -    { -      qboolean flash = ( ps->stats[ STAT_MISC2 ] / 500 ) % 2; - -      if( flash ) -        localColor[ 3 ] = 1.0f; -    } -  } +  // Flash bolts when the boost is almost out +  if( ( cg.snap->ps.stats[ STAT_STATE ] & SS_BOOSTED ) && +      cg.boostedTime > 0 && cg.time - cg.boostedTime > BOOST_TIME - 5000 && +      cg.time & 256 ) +    localColor[ 3 ] = 1.0f;    trap_R_SetColor( localColor );    CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); @@ -904,6 +898,123 @@ static void CG_DrawPlayerHealthCross3( rectDef_t *rect, vec4_t color, qhandle_t    trap_R_SetColor( NULL );  } +static float CG_ChargeProgress( void ) +{ +  float progress; +  int min = 0, max = 0; + +  if( cg.snap->ps.weapon == WP_ALEVEL3 ) +  { +    min = LEVEL3_POUNCE_TIME_MIN; +    max = LEVEL3_POUNCE_TIME; +  } +  else if( cg.snap->ps.weapon == WP_ALEVEL3_UPG ) +  { +    min = LEVEL3_POUNCE_TIME_MIN; +    max = LEVEL3_POUNCE_TIME_UPG; +  } +  else if( cg.snap->ps.weapon == WP_ALEVEL4 ) +  { +    min = LEVEL4_TRAMPLE_CHARGE_MIN; +    max = LEVEL4_TRAMPLE_CHARGE_MAX; +  } +  else if( cg.snap->ps.weapon == WP_LUCIFER_CANNON ) +  { +    min = LCANNON_CHARGE_TIME_MIN; +    max = LCANNON_CHARGE_TIME_MAX; +  } +  if( max - min < 0.0f ) +    return 0.0f; +  progress = ( (float)cg.predictedPlayerState.stats[ STAT_MISC ] - min ) / +             ( max - min ); +  if( progress > 1.0f ) +    return 1.0f; +  if( progress < 0.0f ) +    return 0.0f; +  return progress; +} + +#define CHARGE_BAR_FADE_RATE 0.002f + +static void CG_DrawPlayerChargeBarBG( rectDef_t *rect, vec4_t ref_color, +                                      qhandle_t shader ) +{ +  vec4_t color; +   +  if( !cg_drawChargeBar.integer || cg.chargeMeterAlpha <= 0.0f ) +    return; + +  color[ 0 ] = ref_color[ 0 ]; +  color[ 1 ] = ref_color[ 1 ]; +  color[ 2 ] = ref_color[ 2 ]; +  color[ 3 ] = ref_color[ 3 ] * cg.chargeMeterAlpha; + +  // Draw meter background +  trap_R_SetColor( color ); +  CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); +  trap_R_SetColor( NULL ); +} + +static void CG_DrawPlayerChargeBar( rectDef_t *rect, vec4_t ref_color, +                                    qhandle_t shader ) +{ +  vec4_t color; +  float x, y, width, height, cap_width, progress; +   +  if( !cg_drawChargeBar.integer ) +    return; +   +  // Get progress proportion and pump fade +  progress = CG_ChargeProgress(); +  if( progress <= 0.0f ) +  { +    cg.chargeMeterAlpha -= CHARGE_BAR_FADE_RATE * cg.frametime; +    if( cg.chargeMeterAlpha <= 0.0f ) +    { +      cg.chargeMeterAlpha = 0.0f; +      return; +    } +  } +  else +  { +    cg.chargeMeterValue = progress; +    cg.chargeMeterAlpha += CHARGE_BAR_FADE_RATE * cg.frametime; +    if( cg.chargeMeterAlpha > 1.0f ) +      cg.chargeMeterAlpha = 1.0f; +  } + +  color[ 0 ] = ref_color[ 0 ]; +  color[ 1 ] = ref_color[ 1 ]; +  color[ 2 ] = ref_color[ 2 ]; +  color[ 3 ] = ref_color[ 3 ] * cg.chargeMeterAlpha; +   +  // Flash red for Lucifer Cannon warning +  if( cg.snap->ps.weapon == WP_LUCIFER_CANNON && +      cg.snap->ps.stats[ STAT_MISC ] >= LCANNON_CHARGE_TIME_WARN && +      ( cg.time & 128 ) ) +  { +    color[ 0 ] = 1.0f; +    color[ 1 ] = 0.0f; +    color[ 2 ] = 0.0f; +  } + +  // Calculate bar coords   +  x = rect->x; +  y = rect->y; +  width = ( rect->w - 6 ) * cg.chargeMeterValue; +  height = rect->h; +  CG_AdjustFrom640( &x, &y, &width, &height ); +  cap_width = 3 * cgs.screenXScale; +   +  // Draw the meter +  trap_R_SetColor( color ); +  trap_R_DrawStretchPic( x, y, cap_width, height, 0, 0, 1, 1, shader ); +  trap_R_DrawStretchPic( x + width + cap_width, y, cap_width, height, +                         1, 0, 0, 1, shader ); +  trap_R_DrawStretchPic( x + cap_width, y, width, height, 1, 0, 1, 1, shader ); +  trap_R_SetColor( NULL ); +} +  static void CG_DrawProgressLabel( rectDef_t *rect, float text_x, float text_y, vec4_t color,                                    float scale, int textalign, int textvalign,                                    const char *s, float fraction ) @@ -2151,6 +2262,12 @@ void CG_OwnerDraw( float x, float y, float w, float h, float text_x,      case CG_PLAYER_HEALTH_CROSS3:        CG_DrawPlayerHealthCross3( &rect, color, shader );        break; +    case CG_PLAYER_CHARGE_BAR_BG: +      CG_DrawPlayerChargeBarBG( &rect, color, shader ); +      break; +    case CG_PLAYER_CHARGE_BAR: +      CG_DrawPlayerChargeBar( &rect, color, shader ); +      break;      case CG_PLAYER_CLIPS_RING:        CG_DrawPlayerClipsRing( &rect, color, shader );        break; diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c index 9b6afbe6..2d622088 100644 --- a/src/cgame/cg_event.c +++ b/src/cgame/cg_event.c @@ -737,8 +737,8 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )      //      case EV_NOAMMO:        DEBUGNAME( "EV_NOAMMO" ); -      { -      } +      trap_S_StartSound( NULL, es->number, CHAN_WEAPON, +                         cgs.media.weaponEmptyClick );        break;      case EV_CHANGE_WEAPON: diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h index 360dac34..8dfd09a4 100644 --- a/src/cgame/cg_local.h +++ b/src/cgame/cg_local.h @@ -1133,6 +1133,11 @@ typedef struct    playerState_t savedPmoveStates[ NUM_SAVED_STATES ];    int           stateHead, stateTail;    int           ping; +   +  float         chargeMeterAlpha; +  float         chargeMeterValue; +   +  int           nextWeaponClickTime;  } cg_t; @@ -1179,6 +1184,7 @@ typedef struct    // sounds    sfxHandle_t tracerSound; +  sfxHandle_t weaponEmptyClick;    sfxHandle_t selectSound;    sfxHandle_t footsteps[ FOOTSTEP_TOTAL ][ 4 ];    sfxHandle_t talkSound; @@ -1263,6 +1269,7 @@ typedef struct    qhandle_t   massDriverTS;    sfxHandle_t lCannonWarningSound; +  sfxHandle_t lCannonWarningSound2;    qhandle_t   buildWeaponTimerPie[ 8 ];    qhandle_t   upgradeClassIconShader; @@ -1409,6 +1416,7 @@ extern  vmCvar_t    cg_drawSnapshot;  extern  vmCvar_t    cg_draw3dIcons;  extern  vmCvar_t    cg_drawIcons;  extern  vmCvar_t    cg_drawAmmoWarning; +extern  vmCvar_t    cg_drawChargeBar;  extern  vmCvar_t    cg_drawCrosshair;  extern  vmCvar_t    cg_drawCrosshairNames;  extern  vmCvar_t    cg_drawRewards; diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c index ac0715fe..a2027b3e 100644 --- a/src/cgame/cg_main.c +++ b/src/cgame/cg_main.c @@ -125,6 +125,7 @@ vmCvar_t  cg_drawSnapshot;  vmCvar_t  cg_draw3dIcons;  vmCvar_t  cg_drawIcons;  vmCvar_t  cg_drawAmmoWarning; +vmCvar_t  cg_drawChargeBar;  vmCvar_t  cg_drawCrosshair;  vmCvar_t  cg_drawCrosshairNames;  vmCvar_t  cg_drawRewards; @@ -268,6 +269,7 @@ static cvarTable_t cvarTable[ ] =    { &cg_draw3dIcons, "cg_draw3dIcons", "1", CVAR_ARCHIVE  },    { &cg_drawIcons, "cg_drawIcons", "1", CVAR_ARCHIVE  },    { &cg_drawAmmoWarning, "cg_drawAmmoWarning", "1", CVAR_ARCHIVE  }, +  { &cg_drawChargeBar, "cg_drawChargeBar", "1", CVAR_ARCHIVE  },    { &cg_drawAttacker, "cg_drawAttacker", "1", CVAR_ARCHIVE  },    { &cg_drawCrosshair, "cg_drawCrosshair", "1", CVAR_ARCHIVE },    { &cg_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE }, @@ -692,6 +694,7 @@ static void CG_RegisterSounds( void )    cgs.media.tracerSound           = trap_S_RegisterSound( "sound/weapons/tracer.wav", qfalse );    cgs.media.selectSound           = trap_S_RegisterSound( "sound/weapons/change.wav", qfalse );    cgs.media.turretSpinupSound     = trap_S_RegisterSound( "sound/buildables/mgturret/spinup.wav", qfalse ); +  cgs.media.weaponEmptyClick      = trap_S_RegisterSound( "sound/weapons/click.wav", qfalse );    cgs.media.talkSound             = trap_S_RegisterSound( "sound/misc/talk.wav", qfalse );    cgs.media.alienTalkSound        = trap_S_RegisterSound( "sound/misc/alien_talk.wav", qfalse ); @@ -760,6 +763,7 @@ static void CG_RegisterSounds( void )    cgs.media.buildableRepairedSound  = trap_S_RegisterSound( "sound/buildables/human/repaired.wav", qfalse );    cgs.media.lCannonWarningSound     = trap_S_RegisterSound( "models/weapons/lcannon/warning.wav", qfalse ); +  cgs.media.lCannonWarningSound2    = trap_S_RegisterSound( "models/weapons/lcannon/warning2.wav", qfalse );  } @@ -835,7 +839,7 @@ static void CG_RegisterGraphics( void )      cgs.media.buildWeaponTimerPie[ i ] = trap_R_RegisterShader( buildWeaponTimerPieShaders[ i ] );    cgs.media.upgradeClassIconShader    = trap_R_RegisterShader( "icons/icona_upgrade.tga" ); - +      cgs.media.balloonShader             = trap_R_RegisterShader( "gfx/sprites/chatballoon" );    cgs.media.disconnectPS              = CG_RegisterParticleSystem( "disconnectPS" ); diff --git a/src/cgame/cg_view.c b/src/cgame/cg_view.c index 2c718556..9772e1f5 100644 --- a/src/cgame/cg_view.c +++ b/src/cgame/cg_view.c @@ -471,7 +471,7 @@ static void CG_OffsetFirstPersonView( void )      if( ps->stats[ STAT_MISC ] > 0 )      {        float fraction = (float)ps->stats[ STAT_MISC ] / -        (float)LEVEL4_TRAMPLE_CHARGE_MAX; +                       LEVEL4_TRAMPLE_CHARGE_MAX;        if( fraction > 1.0f )          fraction = 1.0f; diff --git a/src/cgame/cg_weapons.c b/src/cgame/cg_weapons.c index f4c8fbf8..d0968dd9 100644 --- a/src/cgame/cg_weapons.c +++ b/src/cgame/cg_weapons.c @@ -872,8 +872,9 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent    // Lucifer cannon charge warning beep  	 	     if( weaponNum == WP_LUCIFER_CANNON && 		         ( cent->currentState.eFlags & EF_WARN_CHARGE ) ) 		  -    trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, 		  -                            vec3_origin, cgs.media.lCannonWarningSound ); +    trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, +                            vec3_origin, ps ? cgs.media.lCannonWarningSound : +                                              cgs.media.lCannonWarningSound2 );    if( !noGunModel )    { @@ -987,6 +988,9 @@ CG_AddViewWeapon  Add the weapon, and flash for the player's view  ==============  */ + +#define WEAPON_CLICK_REPEAT 500 +  void CG_AddViewWeapon( playerState_t *ps )  {    refEntity_t   hand; @@ -1072,27 +1076,16 @@ void CG_AddViewWeapon( playerState_t *ps )    VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[ 1 ], hand.origin );    VectorMA( hand.origin, ( cg_gun_z.value + fovOffset ), cg.refdef.viewaxis[ 2 ], hand.origin ); -  if( weapon == WP_LUCIFER_CANNON ) +  // Lucifer Cannon vibration effect +  if( weapon == WP_LUCIFER_CANNON && ps->stats[ STAT_MISC ] > 0 )    {      float fraction; -    if( ps->stats[ STAT_MISC ] > 0 ) -    { -      // vibration effect -      fraction = (float)ps->stats[ STAT_MISC ] / (float)LCANNON_TOTAL_CHARGE; -      VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 0 ], -        hand.origin ); -      VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 1 ], -        hand.origin ); -    } -    else if( ps->stats[ STAT_MISC2 ] > 0 ) -    { -      // reloading effect -      fraction = (float)ps->stats[ STAT_MISC2 ] / 250.0f; -      fraction = ( fraction > 1.0f ) ? 1.0f : fraction; -      VectorMA( hand.origin, fraction * -3.0f, cg.refdef.viewaxis[ 2 ], -        hand.origin ); -    } +    fraction = (float)ps->stats[ STAT_MISC ] / LCANNON_CHARGE_TIME_MAX; +    VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 0 ], +              hand.origin ); +    VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 1 ], +              hand.origin );    }    AnglesToAxis( angles, hand.axis ); diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c index 5198fb28..02db5993 100644 --- a/src/game/bg_misc.c +++ b/src/game/bg_misc.c @@ -5430,6 +5430,21 @@ int BG_GetValueOfPlayer( playerState_t *ps )  }  /* +================= +BG_PlayerCanChangeWeapon +================= +*/ +qboolean BG_PlayerCanChangeWeapon( playerState_t *ps ) +{ +  // Do not allow Lucifer Cannon "canceling" via weapon switch +  if( ps->weapon == WP_LUCIFER_CANNON && +      ps->stats[ STAT_MISC ] > LCANNON_CHARGE_TIME_MIN ) +    return qfalse; +     +  return ps->weaponTime <= 0 || ps->weaponstate != WEAPON_FIRING; +} + +/*  ===============  atof_neg diff --git a/src/game/bg_pmove.c b/src/game/bg_pmove.c index 51e1415c..d2c8acc5 100644 --- a/src/game/bg_pmove.c +++ b/src/game/bg_pmove.c @@ -404,8 +404,9 @@ static float PM_CmdScale( usercmd_t *cmd )    }    if( pm->ps->weapon == WP_ALEVEL4 && pm->ps->pm_flags & PMF_CHARGE ) -    modifier *= ( 1.0f + ( pm->ps->stats[ STAT_MISC ] / -      (float)LEVEL4_TRAMPLE_CHARGE_MAX ) * ( LEVEL4_TRAMPLE_SPEED - 1.0f ) ); +    modifier *= 1.0f + ( pm->ps->stats[ STAT_MISC ] * +                         ( LEVEL4_TRAMPLE_SPEED - 1.0f ) / +                         LEVEL4_TRAMPLE_CHARGE_MAX );    //slow player if charging up for a pounce    if( ( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG ) && @@ -847,7 +848,7 @@ static qboolean PM_CheckDodge( void )    }    // Reasons to stop a sprint -  if( pm->cmd.forwardmove <= 64 || +  if( pm->cmd.forwardmove <= 0 ||        pm->cmd.upmove < 0 ||        pm->ps->pm_type != PM_NORMAL )      pm->ps->stats[ STAT_STATE ] &= ~SS_SPEEDBOOST; @@ -2791,6 +2792,18 @@ static void PM_Weapon( void )    qboolean      attack2 = qfalse;    qboolean      attack3 = qfalse; +  // Ignore weapons in some cases +  if( pm->ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR ||  +      ( pm->ps->stats[ STAT_STATE ] & ( SS_INFESTING | SS_HOVELING ) ) ) +    return; + +  // Check for dead player +  if( pm->ps->stats[ STAT_HEALTH ] <= 0 ) +  { +    pm->ps->weapon = WP_NONE; +    return; +  } +    // Charging for a pounce or canceling a pounce    if( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG )    { @@ -2809,43 +2822,96 @@ static void PM_Weapon( void )        pm->ps->stats[ STAT_MISC ] = 0;    } -  // Set overcharging flag so other players can hear warning  	 	  +  // Trample charge mechanics +  if( pm->ps->weapon == WP_ALEVEL4 ) +  { +    // Charging up +    if( !( pm->ps->stats[ STAT_STATE ] & SS_CHARGING ) ) +    { +      // Charge button held +      if( pm->ps->stats[ STAT_MISC ] < LEVEL4_TRAMPLE_CHARGE_MAX && +          ( pm->cmd.buttons & BUTTON_ATTACK2 ) ) +      { +        pm->ps->stats[ STAT_STATE ] &= ~SS_CHARGING; +        if( pm->cmd.forwardmove > 0 ) +          pm->ps->stats[ STAT_MISC ] += pml.msec * LEVEL4_TRAMPLE_CHARGE_MAX / +                                        LEVEL4_TRAMPLE_CHARGE_TIME_MAX; +        else +          pm->ps->stats[ STAT_MISC ] = 0; +        if( pm->ps->stats[ STAT_MISC ] > LEVEL4_TRAMPLE_CHARGE_MAX ) +        { +          pm->ps->stats[ STAT_MISC ] = LEVEL4_TRAMPLE_CHARGE_MAX; +          pm->ps->stats[ STAT_STATE ] |= SS_CHARGING; +          PM_AddEvent( EV_LEV4_TRAMPLE_START ); +        } +      } +       +      // Charge button released +      else if( !( pm->ps->stats[ STAT_STATE ] & SS_CHARGING ) ) +      { +        if( pm->ps->stats[ STAT_MISC ] > LEVEL4_TRAMPLE_CHARGE_MIN ) +        { +          pm->ps->stats[ STAT_STATE ] |= SS_CHARGING; +          PM_AddEvent( EV_LEV4_TRAMPLE_START ); +        } +        else +          pm->ps->stats[ STAT_MISC ] -= pml.msec; +      } +    } +     +    // Discharging +    else +    { +      pm->ps->stats[ STAT_MISC ] -= pml.msec; +       +      // If the charger has stopped moving take a chunk of charge away +      if( VectorLength( pm->ps->velocity ) < 64.0f || pm->cmd.rightmove ) +        pm->ps->stats[ STAT_MISC ] -= LEVEL4_TRAMPLE_STOP_PENALTY * pml.msec; +    } +     +    // Charge is over +    if( pm->ps->stats[ STAT_MISC ] <= 0 || pm->cmd.forwardmove <= 0 ) +    { +      pm->ps->stats[ STAT_MISC ] = 0; +      pm->ps->stats[ STAT_STATE ] &= ~SS_CHARGING; +    } +  } + +  // Charging up a Lucifer Cannon    pm->ps->eFlags &= ~EF_WARN_CHARGE; -  if( pm->ps->weapon == WP_LUCIFER_CANNON && -      pm->ps->stats[ STAT_MISC ] > LCANNON_TOTAL_CHARGE * 2 / 3 ) -    pm->ps->eFlags |= EF_WARN_CHARGE; +  if( pm->ps->weapon == WP_LUCIFER_CANNON ) +  { +    // Charging up +    if( !pm->ps->weaponTime && pm->ps->weaponstate != WEAPON_NEEDS_RESET && +        ( pm->cmd.buttons & BUTTON_ATTACK ) ) +    { +      pm->ps->stats[ STAT_MISC ] += pml.msec; +      if( pm->ps->stats[ STAT_MISC ] >= LCANNON_CHARGE_TIME_MAX ) +        pm->ps->stats[ STAT_MISC ] = LCANNON_CHARGE_TIME_MAX; +      if( pm->ps->stats[ STAT_MISC ] > pm->ps->ammo * LCANNON_CHARGE_TIME_MAX / +                                              LCANNON_CHARGE_AMMO ) +        pm->ps->stats[ STAT_MISC ] = pm->ps->ammo * LCANNON_CHARGE_TIME_MAX / +                                            LCANNON_CHARGE_AMMO; +    } + +    // Set overcharging flag so other players can hear the warning beep +    if( pm->ps->stats[ STAT_MISC ] > LCANNON_CHARGE_TIME_WARN ) +      pm->ps->eFlags |= EF_WARN_CHARGE; +  }    // don't allow attack until all buttons are up    if( pm->ps->pm_flags & PMF_RESPAWNED )      return; -  // ignore if spectator -  if( pm->ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) -    return; - -  if( pm->ps->stats[ STAT_STATE ] & SS_INFESTING ) -    return; - -  if( pm->ps->stats[ STAT_STATE ] & SS_HOVELING ) -    return; - +  // no slash during charge    if( pm->ps->stats[ STAT_STATE ] & SS_CHARGING )      return; -  // check for dead player -  if( pm->ps->stats[ STAT_HEALTH ] <= 0 ) -  { -    pm->ps->weapon = WP_NONE; -    return; -  } -    // no bite during pounce    if( ( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG ) -    && ( pm->cmd.buttons & BUTTON_ATTACK ) -    && ( pm->ps->pm_flags & PMF_CHARGE ) ) -  { +      && ( pm->cmd.buttons & BUTTON_ATTACK ) +      && ( pm->ps->pm_flags & PMF_CHARGE ) )      return; -  }    // make weapon function    if( pm->ps->weaponTime > 0 ) @@ -2853,15 +2919,10 @@ static void PM_Weapon( void )    if( pm->ps->weaponTime < 0 )      pm->ps->weaponTime = 0; -  if( pm->ps->stats[ STAT_MISC2 ] > 0 ) -    pm->ps->stats[ STAT_MISC2 ] -= pml.msec; -  if( pm->ps->stats[ STAT_MISC2 ] < 0 ) -    pm->ps->stats[ STAT_MISC2 ] = 0; -    // check for weapon change    // can't change if weapon is firing, but can change    // again if lowering or raising -  if( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING ) +  if( BG_PlayerCanChangeWeapon( pm->ps ) )    {      // must press use to switch weapons      if( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) @@ -2902,10 +2963,6 @@ static void PM_Weapon( void )    if( pm->ps->weaponTime > 0 )      return; -  // luci uses STAT_MISC2 as an alternate weaponTime -  if( pm->ps->weapon == WP_LUCIFER_CANNON && pm->ps->stats[ STAT_MISC2 ] > 0 ) -    return; -    // change weapon if time    if( pm->ps->weaponstate == WEAPON_DROPPING )    { @@ -2913,10 +2970,10 @@ static void PM_Weapon( void )      return;    } +  // Set proper animation    if( pm->ps->weaponstate == WEAPON_RAISING )    {      pm->ps->weaponstate = WEAPON_READY; -      if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )      {        if( pm->ps->weapon == WP_BLASTER ) @@ -2928,15 +2985,22 @@ static void PM_Weapon( void )      return;    } -  // start the animation even if out of ammo -    BG_FindAmmoForWeapon( pm->ps->weapon, NULL, &maxClips );    // check for out of ammo    if( !pm->ps->ammo && !pm->ps->clips && !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) )    { -    PM_AddEvent( EV_NOAMMO ); -    pm->ps->weaponTime += 200; +    if( ( pm->cmd.buttons & BUTTON_ATTACK ) || +        ( BG_WeaponHasAltMode( pm->ps->weapon ) && +          ( pm->cmd.buttons & BUTTON_ATTACK2 ) ) || +        ( BG_WeaponHasThirdMode( pm->ps->weapon ) && +          ( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) ) ) +    { +      PM_AddEvent( EV_NOAMMO ); +      pm->ps->weaponTime += 500; +    } +    else +      pm->ps->weaponTime += 50;      if( pm->ps->weaponstate == WEAPON_FIRING )        pm->ps->weaponstate = WEAPON_READY; @@ -3002,7 +3066,6 @@ static void PM_Weapon( void )      case WP_LUCIFER_CANNON:        attack1 = pm->cmd.buttons & BUTTON_ATTACK;        attack2 = pm->cmd.buttons & BUTTON_ATTACK2; -      attack3 = qfalse;        // Prevent firing of the Lucifer Cannon after an overcharge        if( pm->ps->weaponstate == WEAPON_NEEDS_RESET ) @@ -3012,28 +3075,26 @@ static void PM_Weapon( void )          pm->ps->weaponstate = WEAPON_READY;        } +      // Can't fire secondary while primary is charging        if( attack1 || pm->ps->stats[ STAT_MISC ] > 0 )          attack2 = qfalse; -      if( ( attack1 || pm->ps->stats[ STAT_MISC ] == 0 ) && !attack2 && !attack3 ) +         +      if( ( attack1 || pm->ps->stats[ STAT_MISC ] == 0 ) && !attack2 )        { -        attack2 = qfalse; +        pm->ps->weaponTime = 0; -        if( pm->ps->stats[ STAT_MISC ] < LCANNON_TOTAL_CHARGE ) +        // Charging +        if( pm->ps->stats[ STAT_MISC ] < LCANNON_CHARGE_TIME_MAX )          { -          // Charging -          pm->ps->weaponTime = 0;            pm->ps->weaponstate = WEAPON_READY;            return;          } -        else -        { -          // Overcharge -          pm->ps->weaponTime = 0; -          pm->ps->weaponstate = WEAPON_NEEDS_RESET; -        } + +        // Overcharge +        pm->ps->weaponstate = WEAPON_NEEDS_RESET;        } -      if( pm->ps->stats[ STAT_MISC ] > LCANNON_MIN_CHARGE ) +      if( pm->ps->stats[ STAT_MISC ] > LCANNON_CHARGE_TIME_MIN )        {          // Fire primary attack          attack1 = qtrue; @@ -3091,7 +3152,6 @@ static void PM_Weapon( void )        //hacky special case for slowblob        if( pm->ps->weapon == WP_ALEVEL3_UPG && !pm->ps->ammo )        { -        PM_AddEvent( EV_NOAMMO );          pm->ps->weaponTime += 200;          return;        } @@ -3180,8 +3240,7 @@ static void PM_Weapon( void )      if( pm->ps->weapon == WP_ALEVEL4 )      {        //hack to get random attack animations -      //FIXME: does pm->ps->weaponTime cycle enough? -      int num = abs( pm->ps->weaponTime ) % 3; +      int num = abs( pm->ps->commandTime ) % 3;        if( num == 0 )          PM_ForceLegsAnim( NSPA_ATTACK1 ); @@ -3209,17 +3268,16 @@ static void PM_Weapon( void )    // take an ammo away if not infinite    if( !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) )    { -    //special case for lcannon +    // Special case for lcannon      if( pm->ps->weapon == WP_LUCIFER_CANNON && attack1 && !attack2 ) -    { -      pm->ps->ammo -= (int)( ceil( ( (float)pm->ps->stats[ STAT_MISC ] / (float)LCANNON_TOTAL_CHARGE ) * 10.0f ) ); - -      //stay on the safe side -      if( pm->ps->ammo < 0 ) -        pm->ps->ammo = 0; -    } +      pm->ps->ammo -= ( pm->ps->stats[ STAT_MISC ] * LCANNON_CHARGE_AMMO + +                LCANNON_CHARGE_TIME_MAX - 1 ) / LCANNON_CHARGE_TIME_MAX;      else        pm->ps->ammo--; + +    // Stay on the safe side +    if( pm->ps->ammo < 0 ) +      pm->ps->ammo = 0;    }    else if( pm->ps->weapon == WP_ALEVEL3_UPG && attack3 )    { diff --git a/src/game/bg_public.h b/src/game/bg_public.h index e3ffc434..54101188 100644 --- a/src/game/bg_public.h +++ b/src/game/bg_public.h @@ -217,7 +217,7 @@ typedef enum    STAT_STAMINA,   // stamina (human only)    STAT_STATE,     // client states e.g. wall climbing    STAT_MISC,      // for uh...misc stuff (pounce, trample, lcannon) -  STAT_MISC2,     // more uh...misc stuff (booster, lcannon repeat) +  STAT_UNUSED,    // *** UNUSED ***    STAT_BUILDABLE, // which ghost model to display for building    STAT_FALLDIST,  // the distance the player fell    STAT_VIEWLOCK   // direction to lock the view in @@ -1130,6 +1130,7 @@ void      BG_PositionBuildableRelativeToPlayer( const playerState_t *ps,                                                                 const vec3_t, const vec3_t, int, int ),                                                  vec3_t outOrigin, vec3_t outAngles, trace_t *tr );  int       BG_GetValueOfPlayer( playerState_t *ps ); +qboolean  BG_PlayerCanChangeWeapon( playerState_t *ps );  int       BG_FindValueOfBuildable( int bclass );  int       BG_FindBuildNumForName( char *name ); @@ -1316,7 +1317,6 @@ qboolean BG_WeaponIsAllowed( weapon_t weapon );  qboolean BG_UpgradeIsAllowed( upgrade_t upgrade );  qboolean BG_ClassIsAllowed( pClass_t class );  qboolean BG_BuildableIsAllowed( buildable_t buildable ); -qboolean BG_UpgradeClassAvailable( playerState_t *ps );  typedef struct   { diff --git a/src/game/g_active.c b/src/game/g_active.c index f232781b..74cb28e2 100644 --- a/src/game/g_active.c +++ b/src/game/g_active.c @@ -613,84 +613,6 @@ void ClientTimerActions( gentity_t *ent, int msec )      else if( client->ps.stats[ STAT_STAMINA ] < -MAX_STAMINA )        client->ps.stats[ STAT_STAMINA ] = -MAX_STAMINA; -    //client is charging up for a... charge -    if( client->ps.weapon == WP_ALEVEL4 ) -    { -      if( client->ps.stats[ STAT_MISC ] < LEVEL4_TRAMPLE_CHARGE_TRIGGER && -        ( ucmd->buttons & BUTTON_ATTACK2 ) && !client->charging ) -      { -        client->charging = qfalse; //should already be off, just making sure -        client->ps.stats[ STAT_STATE ] &= ~SS_CHARGING; - -        if( ucmd->forwardmove > 0 ) -        { -          //trigger charge sound...is quite annoying -          //if( client->ps.stats[ STAT_MISC ] <= 0 ) -          //  G_AddEvent( ent, EV_LEV4_TRAMPLE_PREPARE, 0 ); - -          client->ps.stats[ STAT_MISC ] += 100 * LEVEL4_TRAMPLE_CHARGE_RATE; - -        } -        else -          client->ps.stats[ STAT_MISC ] = 0; - -      } - -      if( !( ucmd->buttons & BUTTON_ATTACK2 ) || client->charging || -          client->ps.stats[ STAT_MISC ] >= LEVEL4_TRAMPLE_CHARGE_TRIGGER ) -      { -        if( client->ps.stats[ STAT_MISC ] > LEVEL4_TRAMPLE_CHARGE_MIN ) -        { -          client->ps.stats[ STAT_MISC ] -= 100 * LEVEL4_TRAMPLE_DISCHARGE_RATE; - -          if( client->charging == qfalse ) -            G_AddEvent( ent, EV_LEV4_TRAMPLE_START, 0 ); - -          client->charging = qtrue; -          client->ps.stats[ STAT_STATE ] |= SS_CHARGING; - -          //if the charger has stopped moving take a chunk of charge away -          if( VectorLength( client->ps.velocity ) < 64.0f || strafing ) -            client->ps.stats[ STAT_MISC ] = client->ps.stats[ STAT_MISC ] / 2; - -          //can't charge backwards -          if( ucmd->forwardmove < 0 ) -            client->ps.stats[ STAT_MISC ] = 0; -          if( client->ps.stats[ STAT_MISC ] > LEVEL4_TRAMPLE_CHARGE_MAX ) -            client->ps.stats[ STAT_MISC ] = LEVEL4_TRAMPLE_CHARGE_MAX; -        } -        else -          client->ps.stats[ STAT_MISC ] = 0; - - -        if( client->ps.stats[ STAT_MISC ] <= 0 ) -        { -          client->ps.stats[ STAT_MISC ] = 0; -          client->charging = qfalse; -          client->ps.stats[ STAT_STATE ] &= ~SS_CHARGING; -        } -      } -    } - -    //client is charging up an lcannon -    if( client->ps.weapon == WP_LUCIFER_CANNON && -        ( ucmd->buttons & BUTTON_ATTACK ) && -        client->ps.stats[ STAT_MISC2 ] <= 0 && -        client->ps.weaponstate != WEAPON_NEEDS_RESET ) -    { -      if( client->ps.stats[ STAT_MISC ] <= 0 ) -        client->lcannonStartTime = level.time; - -      if( client->ps.stats[ STAT_MISC ] < LCANNON_TOTAL_CHARGE ) -        client->ps.stats[ STAT_MISC ] += ( 100.0f / LCANNON_CHARGE_TIME ) * LCANNON_TOTAL_CHARGE; - -      if( client->ps.stats[ STAT_MISC ] > LCANNON_TOTAL_CHARGE ) -        client->ps.stats[ STAT_MISC ] = LCANNON_TOTAL_CHARGE; - -      if( client->ps.stats[ STAT_MISC ] > ( client->ps.ammo * LCANNON_TOTAL_CHARGE ) / 10 ) -        client->ps.stats[ STAT_MISC ] = client->ps.ammo * LCANNON_TOTAL_CHARGE / 10; -    } -      if( client->ps.weapon == WP_ABUILD || client->ps.weapon == WP_ABUILD2 ||          BG_InventoryContainsWeapon( WP_HBUILD, client->ps.stats ) )      { @@ -1477,20 +1399,20 @@ void ClientThink_real( gentity_t *ent )    else      client->ps.pm_type = PM_NORMAL; -  if( client->ps.stats[ STAT_STATE ] & SS_GRABBED && +  if( ( client->ps.stats[ STAT_STATE ] & SS_GRABBED ) &&        client->grabExpiryTime < level.time )      client->ps.stats[ STAT_STATE ] &= ~SS_GRABBED; -  if( client->ps.stats[ STAT_STATE ] & SS_BLOBLOCKED && +  if( ( client->ps.stats[ STAT_STATE ] & SS_BLOBLOCKED ) &&        client->lastLockTime + LOCKBLOB_LOCKTIME < level.time )      client->ps.stats[ STAT_STATE ] &= ~SS_BLOBLOCKED; -  if( client->ps.stats[ STAT_STATE ] & SS_SLOWLOCKED && +  if( ( client->ps.stats[ STAT_STATE ] & SS_SLOWLOCKED ) &&        client->lastSlowTime + ABUILDER_BLOB_TIME < level.time )      client->ps.stats[ STAT_STATE ] &= ~SS_SLOWLOCKED; -  if( client->ps.stats[ STAT_STATE ] & SS_BOOSTED && -      client->ps.stats[ STAT_MISC2 ] <= 0 ) +  if( ( client->ps.stats[ STAT_STATE ] & SS_BOOSTED ) && +      level.time - client->boostedTime >= BOOST_TIME )      client->ps.stats[ STAT_STATE ] &= ~SS_BOOSTED;    if( client->ps.stats[ STAT_STATE ] & SS_POISONCLOUDED ) @@ -1891,11 +1813,10 @@ void SpectatorClientEndFrame( gentity_t *ent )                    ( ent->client->ps.eFlags & ( EF_VOTED | EF_TEAMVOTED ) );            ent->client->ps = cl->ps;            ent->client->ps.eFlags = flags; -          ent->client->ps.pm_flags |= PMF_FOLLOW;          } -        else -          ent->client->ps.pm_flags &= ~PMF_FOLLOW; +          ent->client->ps.clientNum = clientNum; +        ent->client->ps.pm_flags |= PMF_FOLLOW;          ent->client->ps.pm_flags &= ~PMF_QUEUED;        }      } diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c index 1a532ca1..1ef65f43 100644 --- a/src/game/g_buildable.c +++ b/src/game/g_buildable.c @@ -1467,7 +1467,7 @@ void ABooster_Touch( gentity_t *self, gentity_t *other, trace_t *trace )      return;    client->ps.stats[ STAT_STATE ] |= SS_BOOSTED; -  client->ps.stats[ STAT_MISC2 ] = BOOST_TIME; +  client->boostedTime = level.time;  } diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index 88d11646..56f8e8eb 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -367,7 +367,7 @@ void Cmd_Give_f( gentity_t *ent )    if( Q_stricmp( name, "poison" ) == 0 )    {      ent->client->ps.stats[ STAT_STATE ] |= SS_BOOSTED; -    ent->client->ps.stats[ STAT_MISC2 ] = BOOST_TIME; +    ent->client->boostedTime = level.time;    }    if( give_all || Q_stricmp( name, "ammo" ) == 0 ) @@ -1830,13 +1830,14 @@ void Cmd_ActivateItem_f( gentity_t *ent )  {    char  s[ MAX_TOKEN_CHARS ];    int   upgrade, weapon; - +      trap_Argv( 1, s, sizeof( s ) );    // "weapon" aliased to whatever weapon you have    if( !Q_stricmp( "weapon", s ) )    { -    if( ent->client->ps.weapon == WP_BLASTER ) +    if( ent->client->ps.weapon == WP_BLASTER && +        BG_PlayerCanChangeWeapon( &ent->client->ps ) )        G_ForceWeaponChange( ent, WP_NONE );        return;    } @@ -1849,7 +1850,8 @@ void Cmd_ActivateItem_f( gentity_t *ent )    else if( weapon != WP_NONE &&             BG_InventoryContainsWeapon( weapon, ent->client->ps.stats ) )    { -    if( ent->client->ps.weapon != weapon ) +    if( ent->client->ps.weapon != weapon && +        BG_PlayerCanChangeWeapon( &ent->client->ps ) )        G_ForceWeaponChange( ent, weapon );    }    else @@ -1895,9 +1897,11 @@ void Cmd_ToggleItem_f( gentity_t *ent )    if( weapon != WP_NONE )    { +    if( !BG_PlayerCanChangeWeapon( &ent->client->ps ) ) +      return; +      //special case to allow switching between      //the blaster and the primary weapon -      if( ent->client->ps.weapon != WP_BLASTER )        weapon = WP_BLASTER;      else @@ -2037,6 +2041,9 @@ void Cmd_Buy_f( gentity_t *ent )        trap_SendServerCommand( ent-g_entities, va( "print \"You can't buy this item\n\"" ) );        return;      } +     +    if( !BG_PlayerCanChangeWeapon( &ent->client->ps ) ) +      return;      //add to inventory      BG_AddWeaponToInventory( weapon, ent->client->ps.stats ); @@ -2164,6 +2171,9 @@ void Cmd_Sell_f( gentity_t *ent )    if( weapon != WP_NONE )    { +    if( !BG_PlayerCanChangeWeapon( &ent->client->ps ) ) +      return; +        //are we /allowed/ to sell this?      if( !BG_FindPurchasableForWeapon( weapon ) )      { @@ -2229,6 +2239,9 @@ void Cmd_Sell_f( gentity_t *ent )    }    else if( !Q_stricmp( s, "weapons" ) )    { +    if( !BG_PlayerCanChangeWeapon( &ent->client->ps ) ) +      return; +      for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )      {        //guard against selling the HBUILD weapons exploit @@ -2502,8 +2515,10 @@ void G_FollowLockView( gentity_t *ent )    vec3_t spawn_origin, spawn_angles;    int clientNum; +  clientNum = ent->client->sess.spectatorClient;    ent->client->sess.sessionTeam = TEAM_SPECTATOR;    ent->client->sess.spectatorState = SPECTATOR_FOLLOW; +  ent->client->ps.clientNum = clientNum;    ent->client->ps.persistant[ PERS_TEAM ] = TEAM_SPECTATOR;    ent->client->ps.pm_flags &= ~PMF_FOLLOW;    ent->client->ps.stats[ STAT_PTEAM ] = ent->client->pers.teamSelection; @@ -2512,7 +2527,6 @@ void G_FollowLockView( gentity_t *ent )    ent->client->ps.stats[ STAT_VIEWLOCK ] = 0;    ent->client->ps.eFlags &= ~EF_WALLCLIMB;    ent->client->ps.viewangles[ PITCH ] = 0.0f; -  clientNum = ent->client->ps.clientNum = ent->client->sess.spectatorClient;    // Put the view at the team spectator lock position    if( level.clients[ clientNum ].pers.teamSelection == PTE_ALIENS ) @@ -2595,6 +2609,11 @@ qboolean G_FollowNewClient( gentity_t *ent, int dir )      // this is good, we can use it      ent->client->sess.spectatorClient = clientnum;      ent->client->sess.spectatorState = SPECTATOR_FOLLOW; +     +    // if this client is in the spawn queue, we need to do something special +    if( level.clients[ clientnum ].sess.sessionTeam == TEAM_SPECTATOR ) +      G_FollowLockView( ent ); +          return qtrue;    } while( clientnum != original ); diff --git a/src/game/g_local.h b/src/game/g_local.h index 0305c3c9..0c2e6d7d 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -423,6 +423,7 @@ struct gclient_s    int                 inactivityTime;   // kick players when time > this    qboolean            inactivityWarning;// qtrue if the five seoond warning has been given    int                 rewardTime;       // clear the EF_AWARD_IMPRESSIVE, etc when time > this +  int                 boostedTime;      // last time we touched a booster    int                 airOutTime; diff --git a/src/game/g_missile.c b/src/game/g_missile.c index 2991ec48..4d5a751a 100644 --- a/src/game/g_missile.c +++ b/src/game/g_missile.c @@ -438,15 +438,13 @@ gentity_t *fire_luciferCannon( gentity_t *self, vec3_t start, vec3_t dir,    int damage, int radius, int speed )  {    gentity_t *bolt; -  int localDamage = (int)( ceil( ( (float)damage / -                                   (float)LCANNON_TOTAL_CHARGE ) * (float)LCANNON_DAMAGE ) );    VectorNormalize( dir );    bolt = G_Spawn( );    bolt->classname = "lcannon"; -  if( damage == LCANNON_TOTAL_CHARGE ) +  if( damage == LCANNON_DAMAGE )      bolt->nextthink = level.time;    else      bolt->nextthink = level.time + 10000; @@ -458,8 +456,8 @@ gentity_t *fire_luciferCannon( gentity_t *self, vec3_t start, vec3_t dir,    bolt->s.generic1 = self->s.generic1; //weaponMode    bolt->r.ownerNum = self->s.number;    bolt->parent = self; -  bolt->damage = localDamage; -  bolt->splashDamage = localDamage / 2; +  bolt->damage = damage; +  bolt->splashDamage = damage / 2;    bolt->splashRadius = radius;    bolt->methodOfDeath = MOD_LCANNON;    bolt->splashMethodOfDeath = MOD_LCANNON_SPLASH; @@ -467,7 +465,10 @@ gentity_t *fire_luciferCannon( gentity_t *self, vec3_t start, vec3_t dir,    bolt->target_ent = NULL;    // Pass the missile charge through -  bolt->s.torsoAnim = damage; +  bolt->s.torsoAnim = ( damage - LCANNON_SECONDARY_DAMAGE ) * +                      255 / LCANNON_DAMAGE; +  if( bolt->s.torsoAnim < 0 ) +    bolt->s.torsoAnim = 0;    bolt->s.pos.trType = TR_LINEAR;    bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;   // move a bit on the very first frame diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c index fc915d86..f5a118fa 100644 --- a/src/game/g_weapon.c +++ b/src/game/g_weapon.c @@ -772,18 +772,13 @@ void LCChargeFire( gentity_t *ent, qboolean secondary )    gentity_t *m;    if( secondary && ent->client->ps.stats[ STAT_MISC ] <= 0 ) -  {      m = fire_luciferCannon( ent, muzzle, forward, LCANNON_SECONDARY_DAMAGE, -      LCANNON_SECONDARY_RADIUS, LCANNON_SECONDARY_SPEED ); -    ent->client->ps.stats[ STAT_MISC2 ] = LCANNON_REPEAT; -  } +                            LCANNON_SECONDARY_RADIUS, LCANNON_SECONDARY_SPEED );    else -  {      m = fire_luciferCannon( ent, muzzle, forward, -      ent->client->ps.stats[ STAT_MISC ], LCANNON_RADIUS, LCANNON_SPEED ); -    ent->client->ps.stats[ STAT_MISC2 ] = LCANNON_CHARGEREPEAT - -      ( level.time - ent->client->lcannonStartTime ); -  } +                            ent->client->ps.stats[ STAT_MISC ] * +                            LCANNON_DAMAGE / LCANNON_CHARGE_TIME_MAX, +                            LCANNON_RADIUS, LCANNON_SPEED );    ent->client->ps.stats[ STAT_MISC ] = 0;  } @@ -1360,7 +1355,8 @@ void G_ChargeAttack( gentity_t *ent, gentity_t *victim )    int       damage;    vec3_t    forward, normal; -  if( ent->client->ps.stats[ STAT_MISC ] <= 0 || !ent->client->charging ) +  if( ent->client->ps.stats[ STAT_MISC ] <= 0 || +      !( ent->client->ps.stats[ STAT_STATE ] & SS_CHARGING ) )      return;    VectorSubtract( victim->s.origin, ent->s.origin, forward ); @@ -1372,11 +1368,11 @@ void G_ChargeAttack( gentity_t *ent, gentity_t *victim )    WideBloodSpurt( ent, victim, NULL ); -  damage = (int)( ( (float)ent->client->ps.stats[ STAT_MISC ] / -    (float)LEVEL4_TRAMPLE_CHARGE_MAX ) * LEVEL4_TRAMPLE_DMG ); +  damage = LEVEL4_TRAMPLE_DMG * ent->client->ps.stats[ STAT_MISC ] / +           LEVEL4_TRAMPLE_CHARGE_MAX;    G_Damage( victim, ent, ent, forward, victim->s.origin, damage, -    0, MOD_LEVEL4_TRAMPLE ); +            0, MOD_LEVEL4_TRAMPLE );    if( !victim->client )      ent->client->ps.stats[ STAT_MISC ] = 0; diff --git a/src/game/tremulous.h b/src/game/tremulous.h index 3bbac18f..585abe5d 100644 --- a/src/game/tremulous.h +++ b/src/game/tremulous.h @@ -115,24 +115,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  #define LEVEL4_CLAW_K_SCALE         1.0f  #define LEVEL4_REGEN_RANGE          200.0f +#define LEVEL4_TRAMPLE_DMG             ADM(110)  #define LEVEL4_TRAMPLE_SPEED           2.0f -#define LEVEL4_TRAMPLE_TRIGGER_TIME    3000 -#define LEVEL4_TRAMPLE_CHARGE_MIN_TIME 375 -#define LEVEL4_TRAMPLE_CHARGE_MAX_TIME 1000 +#define LEVEL4_TRAMPLE_CHARGE_TIME_MIN 375 +#define LEVEL4_TRAMPLE_CHARGE_TIME_MAX 1000  #define LEVEL4_TRAMPLE_DURATION        3000 -#define LEVEL4_TRAMPLE_DMG             ADM(110) +#define LEVEL4_TRAMPLE_STOP_PENALTY    1     // msec of charge lost when stopped + +#define LEVEL4_TRAMPLE_CHARGE_MIN      ( LEVEL4_TRAMPLE_CHARGE_TIME_MIN * \ +                                         LEVEL4_TRAMPLE_DURATION / \ +                                         LEVEL4_TRAMPLE_CHARGE_TIME_MAX ) +#define LEVEL4_TRAMPLE_CHARGE_MAX        LEVEL4_TRAMPLE_DURATION -#define LEVEL4_TRAMPLE_CHARGE_RATE     2.0f -#define LEVEL4_TRAMPLE_CHARGE_TRIGGER  ( LEVEL4_TRAMPLE_TRIGGER_TIME * \ -                                         LEVEL4_TRAMPLE_CHARGE_RATE ) -#define LEVEL4_TRAMPLE_CHARGE_MIN      ( LEVEL4_TRAMPLE_CHARGE_MIN_TIME * \ -                                         LEVEL4_TRAMPLE_CHARGE_RATE ) -#define LEVEL4_TRAMPLE_CHARGE_MAX      ( LEVEL4_TRAMPLE_CHARGE_MAX_TIME * \ -                                         LEVEL4_TRAMPLE_CHARGE_RATE ) -#define LEVEL4_TRAMPLE_DISCHARGE_RATE  ( (float)LEVEL4_TRAMPLE_CHARGE_MAX / \ -                                         (float)LEVEL4_TRAMPLE_DURATION ) - -#define LEVEL4_CRUSH_DAMAGE_PER_V      0.5f +#define LEVEL4_CRUSH_DAMAGE_PER_V      0.5f  // damage per falling velocity  #define LEVEL4_CRUSH_DAMAGE            120   // to players only  #define LEVEL4_CRUSH_REPEAT            500   // player damage repeat @@ -471,9 +466,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  #define LCANNON_SECONDARY_SPEED     1400  #define LCANNON_SECONDARY_RELOAD    2000  #define LCANNON_SPEED               700 -#define LCANNON_CHARGE_TIME         3000 -#define LCANNON_TOTAL_CHARGE        255 -#define LCANNON_MIN_CHARGE          1 +#define LCANNON_CHARGE_TIME_MAX     3000 +#define LCANNON_CHARGE_TIME_MIN     100 +#define LCANNON_CHARGE_TIME_WARN    2000 +#define LCANNON_CHARGE_AMMO         10       // ammo cost of a full charge shot  #define HBUILD_PRICE                0  #define HBUILD_REPEAT               1000  | 
