/* ============================== PostThink ============================== */ void CBasePlayer::PostThink() { if ( !g_runfuncs ) return; // select the proper animation for the player character if ( !CL_IsDead() && (m_flTouchedByJumpPad < gpGlobals->time) ) { if (!pev->velocity.x && !pev->velocity.y) SetAnimation( PLAYER_IDLE ); else if ((pev->velocity.x || pev->velocity.y) && (FBitSet(pev->flags, FL_ONGROUND))) SetAnimation( PLAYER_WALK ); else if (pev->waterlevel > 1) SetAnimation( PLAYER_WALK ); } if ( !CL_IsDead() && ( m_flThrowTime <= 0.0 ) ) { m_Activity = ACT_BASE_WALK; m_flThrowTime = 0.0; if (!pev->velocity.x && !pev->velocity.y) { SetAnimation( PLAYER_IDLE ); } else { SetAnimation( PLAYER_WALK ); } } // Store old velocity for use in backpedalling animations m_vecOldVelocity = pev->velocity; m_vecOldVelocity.Normalize(); }
// Rotate camera and add move values to usercmd void FWGSInput::IN_Move( float frametime, usercmd_t *cmd ) { Vector viewangles; bool fLadder = false; if( gHUD.m_iIntermission ) return; // we can't move during intermission if( cl_laddermode->value != 2 ) { cl_entity_t *pplayer = gEngfuncs.GetLocalPlayer(); if( pplayer ) fLadder = pplayer->curstate.movetype == MOVETYPE_FLY; } //if(ac_forwardmove || ac_sidemove) //gEngfuncs.Con_Printf("Move: %f %f %f %f\n", ac_forwardmove, ac_sidemove, rel_pitch, rel_yaw); #if 0 if( in_mlook.state & 1 ) { V_StopPitchDrift(); } #endif if( CL_IsDead() ) { viewangles = dead_viewangles; // HACKHACK: see below } else { gEngfuncs.GetViewAngles( viewangles ); } if( gHUD.GetSensitivity() != 0 ) { rel_yaw *= gHUD.GetSensitivity(); rel_pitch *= gHUD.GetSensitivity(); } else { rel_yaw *= sensitivity->value; rel_pitch *= sensitivity->value; } viewangles[YAW] += rel_yaw; if( fLadder ) { if( cl_laddermode->value == 1 ) viewangles[YAW] -= ac_sidemove * 5; ac_sidemove = 0; } if( gHUD.m_MOTD.m_bShow ) gHUD.m_MOTD.scroll += rel_pitch; else viewangles[PITCH] += rel_pitch; if( viewangles[PITCH] > cl_pitchdown->value ) viewangles[PITCH] = cl_pitchdown->value; if( viewangles[PITCH] < -cl_pitchup->value ) viewangles[PITCH] = -cl_pitchup->value; // HACKHACK: change viewangles directly in viewcode, // so viewangles when player is dead will not be changed on server if( !CL_IsDead() ) { gEngfuncs.SetViewAngles( viewangles ); } dead_viewangles = viewangles; // keep them actual if( ac_movecount ) { IN_ToggleButtons( ac_forwardmove / ac_movecount, ac_sidemove / ac_movecount ); if( ac_forwardmove ) cmd->forwardmove = ac_forwardmove * cl_forwardspeed->value / ac_movecount; if( ac_sidemove ) cmd->sidemove = ac_sidemove * cl_sidespeed->value / ac_movecount; if( ( in_speed.state & 1 ) && ( ac_sidemove || ac_forwardmove ) ) { cmd->forwardmove *= cl_movespeedkey->value; cmd->sidemove *= cl_movespeedkey->value; } } ac_sidemove = ac_forwardmove = rel_pitch = rel_yaw = 0; ac_movecount = 0; }
/* ===================== HUD_WeaponsPostThink Run Weapon firing code on client ===================== */ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cmd, double time, unsigned int random_seed ) { int i; int buttonsChanged; CBasePlayerWeapon *pWeapon = NULL; CBasePlayerWeapon *pCurrent; weapon_data_t nulldata, *pfrom, *pto; static int lasthealth; memset( &nulldata, 0, sizeof( nulldata ) ); HUD_InitClientWeapons(); // Get current clock gpGlobals->time = time; // Fill in data based on selected weapon // FIXME, make this a method in each weapon? where you pass in an entity_state_t *? switch ( from->client.m_iId ) { case WEAPON_CROWBAR: pWeapon = &g_Crowbar; break; case WEAPON_GLOCK: pWeapon = &g_Glock; break; case WEAPON_PYTHON: pWeapon = &g_Python; break; case WEAPON_MP5: pWeapon = &g_Mp5; break; case WEAPON_CROSSBOW: pWeapon = &g_Crossbow; break; case WEAPON_SHOTGUN: pWeapon = &g_Shotgun; break; case WEAPON_RPG: pWeapon = &g_Rpg; break; case WEAPON_GAUSS: pWeapon = &g_Gauss; break; case WEAPON_EGON: pWeapon = &g_Egon; break; case WEAPON_HORNETGUN: pWeapon = &g_HGun; break; case WEAPON_HANDGRENADE: pWeapon = &g_HandGren; break; case WEAPON_SATCHEL: pWeapon = &g_Satchel; break; case WEAPON_TRIPMINE: pWeapon = &g_Tripmine; break; case WEAPON_SNARK: pWeapon = &g_Snark; break; } // Store pointer to our destination entity_state_t so we can get our origin, etc. from it // for setting up events on the client g_finalstate = to; // If we are running events/etc. go ahead and see if we // managed to die between last frame and this one // If so, run the appropriate player killed or spawn function if ( g_runfuncs ) { if ( to->client.health <= 0 && lasthealth > 0 ) { player.Killed( NULL, 0 ); } else if ( to->client.health > 0 && lasthealth <= 0 ) { player.Spawn(); } lasthealth = to->client.health; } // We are not predicting the current weapon, just bow out here. if ( !pWeapon ) return; for ( i = 0; i < 32; i++ ) { pCurrent = g_pWpns[ i ]; if ( !pCurrent ) { continue; } pfrom = &from->weapondata[ i ]; pCurrent->m_fInReload = pfrom->m_fInReload; pCurrent->m_fInSpecialReload = pfrom->m_fInSpecialReload; // pCurrent->m_flPumpTime = pfrom->m_flPumpTime; pCurrent->m_iClip = pfrom->m_iClip; pCurrent->m_flNextPrimaryAttack = pfrom->m_flNextPrimaryAttack; pCurrent->m_flNextSecondaryAttack = pfrom->m_flNextSecondaryAttack; pCurrent->m_flTimeWeaponIdle = pfrom->m_flTimeWeaponIdle; pCurrent->pev->fuser1 = pfrom->fuser1; pCurrent->m_flStartThrow = pfrom->fuser2; pCurrent->m_flReleaseThrow = pfrom->fuser3; pCurrent->m_chargeReady = pfrom->iuser1; pCurrent->m_fInAttack = pfrom->iuser2; pCurrent->m_fireState = pfrom->iuser3; pCurrent->m_iSecondaryAmmoType = (int)from->client.vuser3[ 2 ]; pCurrent->m_iPrimaryAmmoType = (int)from->client.vuser4[ 0 ]; player.m_rgAmmo[ pCurrent->m_iPrimaryAmmoType ] = (int)from->client.vuser4[ 1 ]; player.m_rgAmmo[ pCurrent->m_iSecondaryAmmoType ] = (int)from->client.vuser4[ 2 ]; } // For random weapon events, use this seed to seed random # generator player.random_seed = random_seed; // Get old buttons from previous state. player.m_afButtonLast = from->playerstate.oldbuttons; // Which buttsons chave changed buttonsChanged = (player.m_afButtonLast ^ cmd->buttons); // These buttons have changed this frame // Debounced button codes for pressed/released // The changed ones still down are "pressed" player.m_afButtonPressed = buttonsChanged & cmd->buttons; // The ones not down are "released" player.m_afButtonReleased = buttonsChanged & (~cmd->buttons); // Set player variables that weapons code might check/alter player.pev->button = cmd->buttons; player.pev->velocity = from->client.velocity; player.pev->flags = from->client.flags; player.pev->deadflag = from->client.deadflag; player.pev->waterlevel = from->client.waterlevel; player.pev->maxspeed = from->client.maxspeed; player.pev->fov = from->client.fov; player.pev->weaponanim = from->client.weaponanim; player.pev->viewmodel = from->client.viewmodel; player.m_flNextAttack = from->client.m_flNextAttack; player.m_flNextAmmoBurn = from->client.fuser2; player.m_flAmmoStartCharge = from->client.fuser3; //Stores all our ammo info, so the client side weapons can use them. player.ammo_9mm = (int)from->client.vuser1[0]; player.ammo_357 = (int)from->client.vuser1[1]; player.ammo_argrens = (int)from->client.vuser1[2]; player.ammo_bolts = (int)from->client.ammo_nails; //is an int anyways... player.ammo_buckshot = (int)from->client.ammo_shells; player.ammo_uranium = (int)from->client.ammo_cells; player.ammo_hornets = (int)from->client.vuser2[0]; player.ammo_rockets = (int)from->client.ammo_rockets; // Point to current weapon object if ( from->client.m_iId ) { player.m_pActiveItem = g_pWpns[ from->client.m_iId ]; } if ( player.m_pActiveItem->m_iId == WEAPON_RPG ) { ( ( CRpg * )player.m_pActiveItem)->m_fSpotActive = (int)from->client.vuser2[ 1 ]; ( ( CRpg * )player.m_pActiveItem)->m_cActiveRockets = (int)from->client.vuser2[ 2 ]; } // Don't go firing anything if we have died or are spectating // Or if we don't have a weapon model deployed if ( ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) && !CL_IsDead() && player.pev->viewmodel && !g_iUser1 ) { if ( player.m_flNextAttack <= 0 ) { pWeapon->ItemPostFrame(); } } // Assume that we are not going to switch weapons to->client.m_iId = from->client.m_iId; // Now see if we issued a changeweapon command ( and we're not dead ) if ( cmd->weaponselect && ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) ) { // Switched to a different weapon? if ( from->weapondata[ cmd->weaponselect ].m_iId == cmd->weaponselect ) { CBasePlayerWeapon *pNew = g_pWpns[ cmd->weaponselect ]; if ( pNew && ( pNew != pWeapon ) ) { // Put away old weapon if (player.m_pActiveItem) player.m_pActiveItem->Holster( ); player.m_pLastItem = player.m_pActiveItem; player.m_pActiveItem = pNew; // Deploy new weapon if (player.m_pActiveItem) { player.m_pActiveItem->Deploy( ); } // Update weapon id so we can predict things correctly. to->client.m_iId = cmd->weaponselect; } } } // Copy in results of prediction code to->client.viewmodel = player.pev->viewmodel; to->client.fov = player.pev->fov; to->client.weaponanim = player.pev->weaponanim; to->client.m_flNextAttack = player.m_flNextAttack; to->client.fuser2 = player.m_flNextAmmoBurn; to->client.fuser3 = player.m_flAmmoStartCharge; to->client.maxspeed = player.pev->maxspeed; //HL Weapons to->client.vuser1[0] = player.ammo_9mm; to->client.vuser1[1] = player.ammo_357; to->client.vuser1[2] = player.ammo_argrens; to->client.ammo_nails = player.ammo_bolts; to->client.ammo_shells = player.ammo_buckshot; to->client.ammo_cells = player.ammo_uranium; to->client.vuser2[0] = player.ammo_hornets; to->client.ammo_rockets = player.ammo_rockets; if ( player.m_pActiveItem->m_iId == WEAPON_RPG ) { from->client.vuser2[ 1 ] = ( ( CRpg * )player.m_pActiveItem)->m_fSpotActive; from->client.vuser2[ 2 ] = ( ( CRpg * )player.m_pActiveItem)->m_cActiveRockets; } // Make sure that weapon animation matches what the game .dll is telling us // over the wire ( fixes some animation glitches ) if ( g_runfuncs && ( HUD_GetWeaponAnim() != to->client.weaponanim ) ) { int body = 2; //Pop the model to body 0. if ( pWeapon == &g_Tripmine ) body = 0; //Show laser sight/scope combo if ( pWeapon == &g_Python && bIsMultiplayer() ) body = 1; // Force a fixed anim down to viewmodel HUD_SendWeaponAnim( to->client.weaponanim, body, 1 ); } for ( i = 0; i < 32; i++ ) { pCurrent = g_pWpns[ i ]; pto = &to->weapondata[ i ]; if ( !pCurrent ) { memset( pto, 0, sizeof( weapon_data_t ) ); continue; } pto->m_fInReload = pCurrent->m_fInReload; pto->m_fInSpecialReload = pCurrent->m_fInSpecialReload; // pto->m_flPumpTime = pCurrent->m_flPumpTime; pto->m_iClip = pCurrent->m_iClip; pto->m_flNextPrimaryAttack = pCurrent->m_flNextPrimaryAttack; pto->m_flNextSecondaryAttack = pCurrent->m_flNextSecondaryAttack; pto->m_flTimeWeaponIdle = pCurrent->m_flTimeWeaponIdle; pto->fuser1 = pCurrent->pev->fuser1; pto->fuser2 = pCurrent->m_flStartThrow; pto->fuser3 = pCurrent->m_flReleaseThrow; pto->iuser1 = pCurrent->m_chargeReady; pto->iuser2 = pCurrent->m_fInAttack; pto->iuser3 = pCurrent->m_fireState; // Decrement weapon counters, server does this at same time ( during post think, after doing everything else ) pto->m_flNextReload -= cmd->msec / 1000.0; pto->m_fNextAimBonus -= cmd->msec / 1000.0; pto->m_flNextPrimaryAttack -= cmd->msec / 1000.0; pto->m_flNextSecondaryAttack -= cmd->msec / 1000.0; pto->m_flTimeWeaponIdle -= cmd->msec / 1000.0; pto->fuser1 -= cmd->msec / 1000.0; to->client.vuser3[2] = pCurrent->m_iSecondaryAmmoType; to->client.vuser4[0] = pCurrent->m_iPrimaryAmmoType; to->client.vuser4[1] = player.m_rgAmmo[ pCurrent->m_iPrimaryAmmoType ]; to->client.vuser4[2] = player.m_rgAmmo[ pCurrent->m_iSecondaryAmmoType ]; /* if ( pto->m_flPumpTime != -9999 ) { pto->m_flPumpTime -= cmd->msec / 1000.0; if ( pto->m_flPumpTime < -0.001 ) pto->m_flPumpTime = -0.001; }*/ if ( pto->m_fNextAimBonus < -1.0 ) { pto->m_fNextAimBonus = -1.0; } if ( pto->m_flNextPrimaryAttack < -1.0 ) { pto->m_flNextPrimaryAttack = -1.0; } if ( pto->m_flNextSecondaryAttack < -0.001 ) { pto->m_flNextSecondaryAttack = -0.001; } if ( pto->m_flTimeWeaponIdle < -0.001 ) { pto->m_flTimeWeaponIdle = -0.001; } if ( pto->m_flNextReload < -0.001 ) { pto->m_flNextReload = -0.001; } if ( pto->fuser1 < -0.001 ) { pto->fuser1 = -0.001; } } // m_flNextAttack is now part of the weapons, but is part of the player instead to->client.m_flNextAttack -= cmd->msec / 1000.0; if ( to->client.m_flNextAttack < -0.001 ) { to->client.m_flNextAttack = -0.001; } to->client.fuser2 -= cmd->msec / 1000.0; if ( to->client.fuser2 < -0.001 ) { to->client.fuser2 = -0.001; } to->client.fuser3 -= cmd->msec / 1000.0; if ( to->client.fuser3 < -0.001 ) { to->client.fuser3 = -0.001; } // Store off the last position from the predicted state. HUD_SetLastOrg(); // Wipe it so we can't use it after this frame g_finalstate = NULL; }
============ */ int CL_ButtonBits( int bResetState ) { int bits = 0; if ( in_attack.state & 3 ) { bits |= IN_ATTACK; } if (in_duck.state & 3) { bits |= IN_DUCK; } if (in_jump.state & 3) { bits |= IN_JUMP; } if ( in_forward.state & 3 ) { bits |= IN_FORWARD; } if (in_back.state & 3) { bits |= IN_BACK; } if (in_use.state & 3) { bits |= IN_USE; } if (in_cancel) { bits |= IN_CANCEL; } if ( in_left.state & 3 ) { bits |= IN_LEFT; } if (in_right.state & 3) { bits |= IN_RIGHT; } if ( in_moveleft.state & 3 ) { bits |= IN_MOVELEFT; } if (in_moveright.state & 3) { bits |= IN_MOVERIGHT; } if (in_attack2.state & 3) { bits |= IN_ATTACK2; } if (in_reload.state & 3) { bits |= IN_RELOAD; } if (in_alt1.state & 3) { bits |= IN_ALT1; } if ( in_score.state & 3 ) { bits |= IN_SCORE; } // Dead or in intermission? Shore scoreboard, too if ( CL_IsDead() || gHUD.m_iIntermission ) { bits |= IN_SCORE; } if ( bResetState ) { in_attack.state &= ~2; in_duck.state &= ~2; in_jump.state &= ~2; in_forward.state &= ~2; in_back.state &= ~2; in_use.state &= ~2; in_left.state &= ~2; in_right.state &= ~2; in_moveleft.state &= ~2; in_moveright.state &= ~2; in_attack2.state &= ~2; in_reload.state &= ~2; in_alt1.state &= ~2; in_score.state &= ~2; }
/* ================ CL_CreateMove Send the intended movement message to the server if active == 1 then we are 1) not playing back demos ( where our commands are ignored ) and 2 ) we have finished signing on to server ================ */ void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int active ) { float spd; vec3_t viewangles; static vec3_t oldangles; if ( active ) { //memset( viewangles, 0, sizeof( vec3_t ) ); //viewangles[ 0 ] = viewangles[ 1 ] = viewangles[ 2 ] = 0.0; gEngfuncs.GetViewAngles( (float *)viewangles ); CL_AdjustAngles ( frametime, viewangles ); memset (cmd, 0, sizeof(*cmd)); gEngfuncs.SetViewAngles( (float *)viewangles ); if ( in_strafe.state & 1 ) { cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right); cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left); } cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright); cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft); cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up); cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down); if ( !(in_klook.state & 1 ) ) { if(gHUD.m_MOTD.m_bShow) { gHUD.m_MOTD.scroll -= CL_KeyState (&in_forward); gHUD.m_MOTD.scroll += CL_KeyState (&in_back); } else { cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward); cmd->forwardmove -= cl_backspeed->value * CL_KeyState (&in_back); } } // adjust for speed key if ( in_speed.state & 1 ) { cmd->forwardmove *= cl_movespeedkey->value; cmd->sidemove *= cl_movespeedkey->value; cmd->upmove *= cl_movespeedkey->value; } // clip to maxspeed spd = gEngfuncs.GetClientMaxspeed(); if ( spd != 0.0 ) { // scale the 3 speeds so that the total velocity is not > cl.maxspeed float fmov = sqrt( (cmd->forwardmove*cmd->forwardmove) + (cmd->sidemove*cmd->sidemove) + (cmd->upmove*cmd->upmove) ); if ( fmov > spd ) { float fratio = spd / fmov; cmd->forwardmove *= fratio; cmd->sidemove *= fratio; cmd->upmove *= fratio; } } // Allow mice and other controllers to add their inputs IN_Move ( frametime, cmd ); } cmd->impulse = in_impulse; in_impulse = 0; cmd->weaponselect = g_weaponselect; g_weaponselect = 0; // // set button and flag bits // cmd->buttons = CL_ButtonBits( 1 ); // Using joystick? if ( in_joystick->value ) { if ( cmd->forwardmove > 0 ) { cmd->buttons |= IN_FORWARD; } else if ( cmd->forwardmove < 0 ) { cmd->buttons |= IN_BACK; } } gEngfuncs.GetViewAngles( (float *)viewangles ); // Set current view angles. if ( CL_IsDead() ) { VectorCopy( oldangles, cmd->viewangles ); } else { VectorCopy( viewangles, cmd->viewangles ); VectorCopy( viewangles, oldangles ); } }
/* ===================== HUD_WeaponsPostThink Run Weapon firing code on client ===================== */ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cmd, double time, unsigned int random_seed ) { int i; int buttonsChanged; CBasePlayerWeapon *pWeapon = NULL; CBasePlayerWeapon *pCurrent; weapon_data_t nulldata, *pfrom, *pto; static int lasthealth; memset( &nulldata, 0, sizeof( nulldata ) ); HUD_InitClientWeapons(); // Get current clock gpGlobals->time = time; // Fill in data based on selected weapon // FIXME, make this a method in each weapon? where you pass in an entity_state_t *? switch ( from->client.m_iId ) { case WEAPON_DISC: pWeapon = &g_Disc; break; } // We are not predicting the current weapon, just bow out here. if ( !pWeapon ) return; for ( i = 0; i < 32; i++ ) { pCurrent = g_pWpns[ i ]; if ( !pCurrent ) { continue; } pfrom = &from->weapondata[ i ]; pCurrent->m_fInReload = pfrom->m_fInReload; pCurrent->m_iClip = pfrom->m_iClip; pCurrent->m_flNextPrimaryAttack = pfrom->m_flNextPrimaryAttack; pCurrent->m_flNextSecondaryAttack = pfrom->m_flNextSecondaryAttack; pCurrent->m_flTimeWeaponIdle = pfrom->m_flTimeWeaponIdle; // Ricochet uses m_iClip to transmit current/primary ammo to client if ( pWeapon == pCurrent ) { player.m_rgAmmo[pCurrent->m_iPrimaryAmmoType] = pfrom->m_iClip; } } // For random weapon events, use this seed to seed random # generator player.random_seed = random_seed; // Get old buttons from previous state. player.m_afButtonLast = from->playerstate.oldbuttons; // Which buttsons chave changed buttonsChanged = (player.m_afButtonLast ^ cmd->buttons); // These buttons have changed this frame // Debounced button codes for pressed/released // The changed ones still down are "pressed" player.m_afButtonPressed = buttonsChanged & cmd->buttons; // The ones not down are "released" player.m_afButtonReleased = buttonsChanged & (~cmd->buttons); // Set player variables that weapons code might check/alter player.pev->button = cmd->buttons; player.pev->velocity = from->client.velocity; player.pev->flags = from->client.flags; player.pev->deadflag = from->client.deadflag; player.pev->waterlevel = from->client.waterlevel; player.pev->maxspeed = from->client.maxspeed; player.pev->fov = from->client.fov; player.pev->weaponanim = from->client.weaponanim; player.pev->viewmodel = from->client.viewmodel; player.m_flNextAttack = from->client.m_flNextAttack; player.m_flBackupTime = from->client.fuser1; player.m_Activity = (Activity)(int)from->client.fuser2; player.m_flThrowTime = from->client.fuser3; player.m_vecOldVelocity = from->client.vuser1; player.pev->sequence = from->playerstate.sequence; player.pev->gaitsequence = from->playerstate.gaitsequence; player.pev->angles = from->playerstate.angles; // Point to current weapon object if ( from->client.m_iId ) { player.m_pActiveItem = g_pWpns[ from->client.m_iId ]; } // Store pointer to our destination entity_state_t so we can get our origin, etc. from it // for setting up events on the client g_finalstate = to; // Don't go firing anything if we have died. // Or if we don't have a weapon model deployed if ( ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) && !CL_IsDead() && player.pev->viewmodel ) { if ( player.m_flNextAttack <= 0 ) { pWeapon->ItemPostFrame(); } } // If we are running events/etc. go ahead and see if we // managed to die between last frame and this one // If so, run the appropriate player killed or spawn function if ( g_runfuncs ) { if ( to->client.health <= 0 && lasthealth > 0 ) { player.Killed( NULL, 0 ); } else if ( to->client.health > 0 && lasthealth <= 0 ) { player.Spawn(); } lasthealth = to->client.health; } // Fix up animations, etc. player.PostThink(); // Assume that we are not going to switch weapons to->client.m_iId = from->client.m_iId; // Now see if we issued a changeweapon command ( and we're not dead ) if ( cmd->weaponselect && ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) ) { // Switched to a different weapon? if ( from->weapondata[ cmd->weaponselect ].m_iId == cmd->weaponselect ) { CBasePlayerWeapon *pNew = g_pWpns[ cmd->weaponselect ]; if ( pNew && ( pNew != pWeapon ) ) { // Put away old weapon if (player.m_pActiveItem) player.m_pActiveItem->Holster( ); player.m_pLastItem = player.m_pActiveItem; player.m_pActiveItem = pNew; // Deploy new weapon if (player.m_pActiveItem) { player.m_pActiveItem->Deploy( ); } // Update weapon id so we can predict things correctly. to->client.m_iId = cmd->weaponselect; } } } // Copy in results of predcition code to->client.viewmodel = player.pev->viewmodel; to->client.fov = player.pev->fov; to->client.weaponanim = player.pev->weaponanim; to->client.m_flNextAttack = player.m_flNextAttack; to->client.maxspeed = player.pev->maxspeed; to->client.fuser1 = player.m_flBackupTime; to->client.fuser2 = (float)(int)player.m_Activity; to->client.fuser3 = player.m_flThrowTime; to->client.vuser1 = player.m_vecOldVelocity; to->playerstate.sequence = player.pev->sequence; to->playerstate.gaitsequence = player.pev->gaitsequence; // Make sure that weapon animation matches what the game .dll is telling us // over the wire ( fixes some animation glitches ) if ( g_runfuncs && ( HUD_GetWeaponAnim() != to->client.weaponanim ) ) { int body = 2; // Force a fixed anim down to viewmodel HUD_SendWeaponAnim( to->client.weaponanim, body, 1 ); } for ( i = 0; i < 32; i++ ) { pCurrent = g_pWpns[ i ]; pto = &to->weapondata[ i ]; if ( !pCurrent ) { memset( pto, 0, sizeof( weapon_data_t ) ); continue; } pto->m_fInReload = pCurrent->m_fInReload; pto->m_iClip = pCurrent->m_iClip; pto->m_flNextPrimaryAttack = pCurrent->m_flNextPrimaryAttack; pto->m_flNextSecondaryAttack = pCurrent->m_flNextSecondaryAttack; pto->m_flTimeWeaponIdle = pCurrent->m_flTimeWeaponIdle; // Decrement weapon counters, server does this at same time ( during post think, after doing everything else ) pto->m_flNextReload -= cmd->msec / 1000.0; pto->m_fNextAimBonus -= cmd->msec / 1000.0; pto->m_flNextPrimaryAttack -= cmd->msec / 1000.0; pto->m_flNextSecondaryAttack -= cmd->msec / 1000.0; pto->m_flTimeWeaponIdle -= cmd->msec / 1000.0; if ( pto->m_flPumpTime != -9999 ) { pto->m_flPumpTime -= cmd->msec / 1000.0; if ( pto->m_flPumpTime < -0.001 ) pto->m_flPumpTime = -0.001; } if ( pto->m_fNextAimBonus < -1.0 ) { pto->m_fNextAimBonus = -1.0; } if ( pto->m_flNextPrimaryAttack < -1.0 ) { pto->m_flNextPrimaryAttack = -1.0; } if ( pto->m_flNextSecondaryAttack < -0.001 ) { pto->m_flNextSecondaryAttack = -0.001; } if ( pto->m_flTimeWeaponIdle < -0.001 ) { pto->m_flTimeWeaponIdle = -0.001; } if ( pto->m_flNextReload < -0.001 ) { pto->m_flNextReload = -0.001; } } // m_flNextAttack is now part of the weapons, but is part of the player instead to->client.m_flNextAttack -= cmd->msec / 1000.0; if ( to->client.m_flNextAttack < -0.001 ) { to->client.m_flNextAttack = -0.001; } to->client.fuser1 -= cmd->msec / 1000.0; if ( to->client.fuser1 < -0.001 ) { to->client.fuser1 = -0.001; } to->client.fuser3 -= cmd->msec / 1000.0; if ( to->client.fuser3 < -0.001 ) { to->client.fuser3 = -0.001; } // Wipe it so we can't use it after this frame g_finalstate = NULL; }
/* ================ CL_CreateMove Send the intended movement message to the server if active == 1 then we are 1) not playing back demos ( where our commands are ignored ) and 2 ) we have finished signing on to server ================ */ void CL_CreateMove( float frametime, usercmd_t *cmd, int active ) { float spd; Vector viewangles; static Vector oldangles; if( active ) { gEngfuncs.GetViewAngles( viewangles ); CL_AdjustAngles( frametime, viewangles ); memset( cmd, 0, sizeof( *cmd )); float rgfl[3]; viewangles.CopyToArray( rgfl ); gEngfuncs.SetViewAngles( rgfl ); if( in_strafe.state & BUTTON_DOWN ) { cmd->sidemove += cl_sidespeed->value * CL_KeyState( &in_right ); cmd->sidemove -= cl_sidespeed->value * CL_KeyState( &in_left ); } cmd->sidemove += cl_sidespeed->value * CL_KeyState( &in_moveright ); cmd->sidemove -= cl_sidespeed->value * CL_KeyState( &in_moveleft ); cmd->upmove += cl_upspeed->value * CL_KeyState( &in_up ); cmd->upmove -= cl_upspeed->value * CL_KeyState( &in_down ); if(!( in_klook.state & BUTTON_DOWN )) { cmd->forwardmove += cl_forwardspeed->value * CL_KeyState( &in_forward ); cmd->forwardmove -= cl_backspeed->value * CL_KeyState( &in_back ); } // adjust for speed key if( in_speed.state & BUTTON_DOWN ) { cmd->forwardmove *= cl_movespeedkey->value; cmd->sidemove *= cl_movespeedkey->value; cmd->upmove *= cl_movespeedkey->value; } // clip to maxspeed spd = gEngfuncs.GetClientMaxspeed(); if( spd != 0.0f ) { // scale the 3 speeds so that the total velocity is not > cl.maxspeed float fmov = sqrt(( cmd->forwardmove * cmd->forwardmove) + (cmd->sidemove * cmd->sidemove) + (cmd->upmove * cmd->upmove)); if( fmov > spd ) { float fratio = spd / fmov; cmd->forwardmove *= fratio; cmd->sidemove *= fratio; cmd->upmove *= fratio; } } // allow mice and other controllers to add their inputs if( !CL_IsDead( )) IN_Move( frametime, cmd ); } cmd->impulse = in_impulse; in_impulse = 0; cmd->weaponselect = g_weaponselect; g_weaponselect = 0; // set button and flag bits cmd->buttons = CL_ButtonBits( 1 ); gEngfuncs.GetViewAngles( viewangles ); // Set current view angles. if( CL_IsDead( )) { cmd->viewangles = oldangles; } else { cmd->viewangles = viewangles; oldangles = viewangles; } }
/* ===================== HUD_WeaponsPostThink Run Weapon firing code on client ===================== */ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cmd, double time, unsigned int random_seed ) { int i; int buttonsChanged; CBasePlayerWeapon *pWeapon = NULL; CBasePlayerWeapon *pCurrent; weapon_data_t nulldata, *pfrom, *pto; static int lasthealth; memset( &nulldata, 0, sizeof( nulldata ) ); HUD_InitClientWeapons(); // Get current clock gpGlobals->time = time; // Fill in data based on selected weapon // FIXME, make this a method in each weapon? where you pass in an entity_state_t *? switch ( from->client.m_iId ) { case WEAPON_GLOCK: pWeapon = &g_QuakeGun; break; } // Store pointer to our destination entity_state_t so we can get our origin, etc. from it // for setting up events on the client g_finalstate = to; // If we are running events/etc. go ahead and see if we // managed to die between last frame and this one // If so, run the appropriate player killed or spawn function if ( g_runfuncs ) { if ( to->client.health <= 0 && lasthealth > 0 ) { player.Killed( NULL, 0 ); } else if ( to->client.health > 0 && lasthealth <= 0 ) { player.Spawn(); } lasthealth = to->client.health; } // We are not predicting the current weapon, just bow out here. if ( !pWeapon ) return; gpGlobals->deathmatch = from->client.iuser4; for ( i = 0; i < 32; i++ ) { pCurrent = g_pWpns[ i ]; if ( !pCurrent ) { continue; } pfrom = &from->weapondata[ i ]; pCurrent->m_fInReload = pfrom->m_fInReload; pCurrent->m_iClip = pfrom->m_iClip; pCurrent->m_flNextPrimaryAttack = pfrom->m_flNextPrimaryAttack; pCurrent->m_flNextSecondaryAttack = pfrom->m_flNextSecondaryAttack; pCurrent->m_flTimeWeaponIdle = pfrom->m_flTimeWeaponIdle; } // For random weapon events, use this seed to seed random # generator player.random_seed = random_seed; // Get old buttons from previous state. player.m_afButtonLast = from->playerstate.oldbuttons; // Which buttsons chave changed buttonsChanged = (player.m_afButtonLast ^ cmd->buttons); // These buttons have changed this frame // Debounced button codes for pressed/released // The changed ones still down are "pressed" player.m_afButtonPressed = buttonsChanged & cmd->buttons; // The ones not down are "released" player.m_afButtonReleased = buttonsChanged & (~cmd->buttons); // Set player variables that weapons code might check/alter player.pev->button = cmd->buttons; player.pev->velocity = from->client.velocity; player.pev->flags = from->client.flags; player.pev->deadflag = from->client.deadflag; g_iWaterLevel = player.pev->waterlevel = from->client.waterlevel; player.pev->maxspeed = from->client.maxspeed; player.pev->fov = from->client.fov; player.pev->weaponanim = from->client.weaponanim; player.pev->viewmodel = from->client.viewmodel; player.m_flNextAttack = from->client.m_flNextAttack; player.m_iQuakeWeapon = (int)from->client.fuser1; iCarriedWeapons = player.m_iQuakeItems = from->client.iuser3; player.m_iAmmoShells = from->client.ammo_shells; player.m_iAmmoCells = from->client.ammo_cells; player.m_iAmmoRockets = from->client.ammo_rockets; player.m_iAmmoNails = from->client.ammo_nails; player.m_iNailOffset = (int)from->client.fuser2 != 0.0 ? 4.0 : -4.0; // REally useful for debugging prediction /* if ( player.m_iQuakeWeapon > 0 ) { gEngfuncs.Con_NPrintf( 9, "got qw %i", player.m_iQuakeWeapon ); char items[33]; for ( int i = 0; i < 32; i++ ) { if ( player.m_iQuakeItems & (1<<i) ) { items[i] = '1'; } else { items[i] = '0'; } } items[32] = 0; gEngfuncs.Con_NPrintf( 10, "got qi %s", items ); gEngfuncs.Con_NPrintf( 11, "shells %i", player.m_iAmmoShells ); gEngfuncs.Con_NPrintf( 12, "cells %i", player.m_iAmmoCells ); gEngfuncs.Con_NPrintf( 13, "rockets %i", player.m_iAmmoRockets ); gEngfuncs.Con_NPrintf( 14, "nails %i", player.m_iAmmoNails ); gEngfuncs.Con_NPrintf( 15, "viewmodel %i", player.pev->viewmodel ); gEngfuncs.Con_NPrintf( 16, "dm == %i", gpGlobals->deathmatch ); }*/ // Point to current weapon object if ( from->client.m_iId ) { player.m_pActiveItem = g_pWpns[ from->client.m_iId ]; } // Set ammo, but don't change anim player.W_SetCurrentAmmo( 0 ); // Don't go firing anything if we have died. // Or if we don't have a weapon model deployed if ( ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) && !CL_IsDead() ) // && player.pev->viewmodel ) { if ( player.m_flNextAttack <= 0 ) { pWeapon->ItemPostFrame(); } } // Assume that we are not going to switch weapons to->client.m_iId = from->client.m_iId; // Now see if we issued a changeweapon command ( and we're not dead ) if ( cmd->weaponselect && ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) ) { // Switched to a different weapon? if ( Quake_NumForWeaponItem( player.m_iQuakeWeapon ) != cmd->weaponselect ) { player.W_ChangeWeapon( cmd->weaponselect ); } } if ( player.m_iQuakeWeapon != IT_LIGHTNING && pBeam != NULL ) { pBeam->die = 0.0; pBeam = NULL; } // Copy in results of predcition code to->client.viewmodel = player.pev->viewmodel; to->client.fov = player.pev->fov; to->client.weaponanim = player.pev->weaponanim; to->client.m_flNextAttack = player.m_flNextAttack; to->client.maxspeed = player.pev->maxspeed; to->client.iuser3 = player.m_iQuakeItems; to->client.fuser1 = (float)player.m_iQuakeWeapon; to->client.fuser2 = (float)player.m_iNailOffset > 0.0 ? 1.0 : 0.0; to->client.ammo_shells = player.m_iAmmoShells; to->client.ammo_cells = player.m_iAmmoCells; to->client.ammo_rockets = player.m_iAmmoRockets; to->client.ammo_nails = player.m_iAmmoNails; // Make sure that weapon animation matches what the game .dll is telling us // over the wire ( fixes some animation glitches ) if ( g_runfuncs && ( HUD_GetWeaponAnim() != to->client.weaponanim ) ) { int body = 2; // Force a fixed anim down to viewmodel HUD_SendWeaponAnim( to->client.weaponanim, body, 1 ); } for ( i = 0; i < 32; i++ ) { pCurrent = g_pWpns[ i ]; pto = &to->weapondata[ i ]; if ( !pCurrent ) { memset( pto, 0, sizeof( weapon_data_t ) ); continue; } pto->m_fInReload = pCurrent->m_fInReload; pto->m_iClip = pCurrent->m_iClip; pto->m_flNextPrimaryAttack = pCurrent->m_flNextPrimaryAttack; pto->m_flNextSecondaryAttack = pCurrent->m_flNextSecondaryAttack; pto->m_flTimeWeaponIdle = pCurrent->m_flTimeWeaponIdle; // Decrement weapon counters, server does this at same time ( during post think, after doing everything else ) pto->m_flNextReload -= cmd->msec / 1000.0; pto->m_fNextAimBonus -= cmd->msec / 1000.0; pto->m_flNextPrimaryAttack -= cmd->msec / 1000.0; pto->m_flNextSecondaryAttack -= cmd->msec / 1000.0; pto->m_flTimeWeaponIdle -= cmd->msec / 1000.0; if ( pto->m_flPumpTime != -9999 ) { pto->m_flPumpTime -= cmd->msec / 1000.0; if ( pto->m_flPumpTime < -0.001 ) pto->m_flPumpTime = -0.001; } if ( pto->m_fNextAimBonus < -1.0 ) { pto->m_fNextAimBonus = -1.0; } if ( pto->m_flNextPrimaryAttack < -1.0 ) { pto->m_flNextPrimaryAttack = -1.0; } if ( pto->m_flNextSecondaryAttack < -0.001 ) { pto->m_flNextSecondaryAttack = -0.001; } if ( pto->m_flTimeWeaponIdle < -0.001 ) { pto->m_flTimeWeaponIdle = -0.001; } if ( pto->m_flNextReload < -0.001 ) { pto->m_flNextReload = -0.001; } } // m_flNextAttack is now part of the weapons, but is part of the player instead to->client.m_flNextAttack -= cmd->msec / 1000.0; if ( to->client.m_flNextAttack < -0.001 ) { to->client.m_flNextAttack = -0.001; } // Store off the last position from the predicted state. HUD_SetLastOrg(); // Wipe it so we can't use it after this frame g_finalstate = NULL; }
/* ===================== HUD_WeaponsPostThink Run Weapon firing code on client ===================== */ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cmd, double time, unsigned int random_seed ) { int i; int buttonsChanged; CBasePlayerWeapon *pWeapon = NULL; static int lasthealth; int flags; HUD_InitClientWeapons(); // Get current clock gpGlobals->time = time; // Fill in data based on selected weapon switch ( from->client.m_iId ) { case WEAPON_P228: pWeapon = &g_P228; break; case WEAPON_SCOUT: pWeapon = &g_SCOUT; break; case WEAPON_HEGRENADE: pWeapon = &g_HEGrenade; break; case WEAPON_XM1014: pWeapon = &g_XM1014; break; case WEAPON_C4: pWeapon = &g_C4; break; case WEAPON_MAC10: pWeapon = &g_MAC10; break; case WEAPON_AUG: pWeapon = &g_AUG; break; case WEAPON_SMOKEGRENADE: pWeapon = &g_SmokeGrenade; break; case WEAPON_ELITE: pWeapon = &g_ELITE; break; case WEAPON_FIVESEVEN: pWeapon = &g_FiveSeven; break; case WEAPON_UMP45: pWeapon = &g_UMP45; break; case WEAPON_SG550: pWeapon = &g_SG550; break; case WEAPON_GALIL: pWeapon = &g_Galil; break; case WEAPON_FAMAS: pWeapon = &g_Famas; break; case WEAPON_USP: pWeapon = &g_USP; break; case WEAPON_GLOCK18: pWeapon = &g_GLOCK18; break; case WEAPON_AWP: pWeapon = &g_AWP; break; case WEAPON_MP5N: pWeapon = &g_MP5N; break; case WEAPON_M249: pWeapon = &g_M249; break; case WEAPON_M3: pWeapon = &g_M3; break; case WEAPON_M4A1: pWeapon = &g_M4A1; break; case WEAPON_TMP: pWeapon = &g_TMP; break; case WEAPON_G3SG1: pWeapon = &g_G3SG1; break; case WEAPON_FLASHBANG: pWeapon = &g_Flashbang; break; case WEAPON_DEAGLE: pWeapon = &g_DEAGLE; break; case WEAPON_SG552: pWeapon = &g_SG552; break; case WEAPON_AK47: pWeapon = &g_AK47; break; case WEAPON_KNIFE: pWeapon = &g_Knife; break; case WEAPON_P90: pWeapon = &g_P90; break; /*case WEAPON_NONE: break; case WEAPON_GLOCK: default: gEngfuncs.Con_Printf("VALVEWHY: Unknown Weapon %i is active.\n", from->client.m_iId ); break;*/ } // Store pointer to our destination entity_state_t so we can get our origin, etc. from it // for setting up events on the client g_finalstate = to; // If we are running events/etc. go ahead and see if we // managed to die between last frame and this one // If so, run the appropriate player killed or spawn function if ( g_runfuncs ) { if ( to->client.health <= 0 && lasthealth > 0 ) { player.Killed( NULL, 0 ); } else if ( to->client.health > 0 && lasthealth <= 0 ) { player.Spawn(); } lasthealth = to->client.health; } // We are not predicting the current weapon, just bow out here. if ( !pWeapon ) return; for ( i = 0; i < MAX_WEAPONS; i++ ) { CBasePlayerWeapon *pCurrent = g_pWpns[ i ]; if ( !pCurrent ) { continue; } weapon_data_t *pfrom = from->weapondata + i; pCurrent->m_fInReload = pfrom->m_fInReload; pCurrent->m_fInSpecialReload = pfrom->m_fInSpecialReload; pCurrent->m_iClip = pfrom->m_iClip; pCurrent->m_flNextPrimaryAttack = pfrom->m_flNextPrimaryAttack; pCurrent->m_flNextSecondaryAttack = pfrom->m_flNextSecondaryAttack; pCurrent->m_flTimeWeaponIdle = pfrom->m_flTimeWeaponIdle; pCurrent->m_flStartThrow = pfrom->fuser2; pCurrent->m_flReleaseThrow = pfrom->fuser3; pCurrent->m_iSwing = pfrom->iuser1; pCurrent->m_iWeaponState = pfrom->m_iWeaponState; pCurrent->m_flLastFire = pfrom->m_fAimedDamage; pCurrent->m_iShotsFired = pfrom->m_fInZoom; } if( from->client.vuser4.x < 0 || from->client.vuser4.x > MAX_AMMO_TYPES ) { pWeapon->m_iPrimaryAmmoType = 0; } else { pWeapon->m_iPrimaryAmmoType = (int)from->client.vuser4.x; player.m_rgAmmo[ pWeapon->m_iPrimaryAmmoType ] = (int)from->client.vuser4.y; } g_iWeaponFlags = pWeapon->m_iWeaponState; // For random weapon events, use this seed to seed random # generator player.random_seed = random_seed; // Get old buttons from previous state. player.m_afButtonLast = from->playerstate.oldbuttons; // Which buttsons chave changed buttonsChanged = (player.m_afButtonLast ^ cmd->buttons); // These buttons have changed this frame // Debounced button codes for pressed/released // The changed ones still down are "pressed" player.m_afButtonPressed = buttonsChanged & cmd->buttons; // The ones not down are "released" player.m_afButtonReleased = buttonsChanged & (~cmd->buttons); // Set player variables that weapons code might check/alter player.pev->button = cmd->buttons; player.pev->velocity = from->client.velocity; g_iPlayerFlags = player.pev->flags = from->client.flags; player.pev->deadflag = from->client.deadflag; player.pev->waterlevel = from->client.waterlevel; player.pev->maxspeed = from->client.maxspeed; player.pev->punchangle = from->client.punchangle; player.pev->fov = from->client.fov; player.pev->weaponanim = from->client.weaponanim; player.pev->viewmodel = from->client.viewmodel; player.m_flNextAttack = from->client.m_flNextAttack; g_vPlayerVelocity = from->client.velocity; g_flPlayerSpeed = from->client.velocity.Length(); //Stores all our ammo info, so the client side weapons can use them. player.ammo_9mm = (int)from->client.ammo_nails; player.ammo_556nato = (int)from->client.ammo_cells; player.ammo_buckshot = (int)from->client.ammo_shells; player.ammo_556natobox = (int)from->client.ammo_rockets; player.ammo_762nato = (int)from->client.vuser2.x; player.ammo_45acp = (int)from->client.vuser2.y; player.ammo_50ae = (int)from->client.vuser2.z; player.ammo_338mag = (int)from->client.vuser3.x; player.ammo_57mm = (int)from->client.vuser3.y; player.ammo_357sig = (int)from->client.vuser3.z; cl_entity_t *pplayer = gEngfuncs.GetLocalPlayer(); if( pplayer ) { player.pev->origin = from->client.origin; player.pev->angles = pplayer->angles; player.pev->v_angle = v_angles; } flags = from->client.iuser3; g_bHoldingKnife = pWeapon->m_iId == WEAPON_KNIFE; player.m_bCanShoot = (flags & PLAYER_CAN_SHOOT) != 0; g_iFreezeTimeOver = !(flags & PLAYER_FREEZE_TIME_OVER); g_bInBombZone = (flags & PLAYER_IN_BOMB_ZONE) != 0; g_bHoldingShield = (flags & PLAYER_HOLDING_SHIELD) != 0; // Point to current weapon object if ( from->client.m_iId ) { player.m_pActiveItem = pWeapon; } // Don't go firing anything if we have died. // Or if we don't have a weapon model deployed if ( ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) && !CL_IsDead() && player.pev->viewmodel && !g_iUser1 ) { if( g_bHoldingKnife && pWeapon->m_iClientWeaponState && player.pev->button & IN_FORWARD ) player.m_flNextAttack = 0; else if( player.m_flNextAttack <= 0 ) { pWeapon->ItemPostFrame(); } } // Assume that we are not going to switch weapons to->client.m_iId = from->client.m_iId; // Now see if we issued a changeweapon command ( and we're not dead ) if ( cmd->weaponselect && ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) ) { // Switched to a different weapon? if ( from->weapondata[ cmd->weaponselect ].m_iId == cmd->weaponselect ) { CBasePlayerWeapon *pNew = g_pWpns[ cmd->weaponselect ]; if ( pNew && ( pNew != pWeapon ) ) { // Put away old weapon if (player.m_pActiveItem) player.m_pActiveItem->Holster( ); player.m_pLastItem = player.m_pActiveItem; player.m_pActiveItem = pNew; // Deploy new weapon if (player.m_pActiveItem) { player.m_pActiveItem->Deploy( ); } // Update weapon id so we can predict things correctly. to->client.m_iId = cmd->weaponselect; } } } // Copy in results of prediction code to->client.viewmodel = player.pev->viewmodel; to->client.fov = player.pev->fov; to->client.weaponanim = player.pev->weaponanim; to->client.m_flNextAttack = player.m_flNextAttack; to->client.maxspeed = player.pev->maxspeed; to->client.punchangle = player.pev->punchangle; to->client.ammo_nails = player.ammo_9mm; to->client.ammo_cells = player.ammo_556nato; to->client.ammo_shells = player.ammo_buckshot; to->client.ammo_rockets = player.ammo_556natobox; to->client.vuser2.x = player.ammo_762nato; to->client.vuser2.y = player.ammo_45acp; to->client.vuser2.z = player.ammo_50ae; to->client.vuser3.x = player.ammo_338mag; to->client.vuser3.y = player.ammo_57mm; to->client.vuser3.z = player.ammo_357sig; to->client.iuser3 = flags; // Make sure that weapon animation matches what the game .dll is telling us // over the wire ( fixes some animation glitches ) if ( g_runfuncs && ( HUD_GetWeaponAnim() != to->client.weaponanim ) ) // Force a fixed anim down to viewmodel HUD_SendWeaponAnim( to->client.weaponanim, to->client.m_iId, 2, 1 ); if (pWeapon->m_iPrimaryAmmoType < MAX_AMMO_TYPES) { to->client.vuser4.x = pWeapon->m_iPrimaryAmmoType; to->client.vuser4.y = player.m_rgAmmo[ pWeapon->m_iPrimaryAmmoType ]; } else { to->client.vuser4.x = -1.0; to->client.vuser4.y = 0; } for ( i = 0; i < MAX_WEAPONS; i++ ) { CBasePlayerWeapon *pCurrent = g_pWpns[ i ]; weapon_data_t *pto = to->weapondata + i; if ( !pCurrent ) { memset( pto, 0, sizeof( weapon_data_t ) ); continue; } pto->m_fInReload = pCurrent->m_fInReload; pto->m_fInSpecialReload = pCurrent->m_fInSpecialReload; pto->m_iClip = pCurrent->m_iClip; pto->m_flNextPrimaryAttack = pCurrent->m_flNextPrimaryAttack; pto->m_flNextSecondaryAttack = pCurrent->m_flNextSecondaryAttack; pto->m_flTimeWeaponIdle = pCurrent->m_flTimeWeaponIdle; pto->m_flNextReload = pCurrent->m_flNextReload; pto->fuser2 = pCurrent->m_flStartThrow; pto->fuser3 = pCurrent->m_flReleaseThrow; pto->iuser1 = pCurrent->m_iSwing; pto->m_iWeaponState = pCurrent->m_iWeaponState; pto->m_fInZoom = pCurrent->m_iShotsFired; pto->m_fAimedDamage = pCurrent->m_flLastFire; // Decrement weapon counters, server does this at same time ( during post think, after doing everything else ) pto->m_flNextReload -= cmd->msec / 1000.0f; pto->m_fNextAimBonus -= cmd->msec / 1000.0f; pto->m_flNextPrimaryAttack -= cmd->msec / 1000.0f; pto->m_flNextSecondaryAttack -= cmd->msec / 1000.0f; pto->m_flTimeWeaponIdle -= cmd->msec / 1000.0f; if( pto->m_flPumpTime != -9999.0f ) { pto->m_flPumpTime -= cmd->msec / 1000.0f; if( pto->m_flPumpTime < -1.0f ) pto->m_flPumpTime = 1.0f; } if ( pto->m_fNextAimBonus < -1.0 ) { pto->m_fNextAimBonus = -1.0; } if ( pto->m_flNextPrimaryAttack < -1.0 ) { pto->m_flNextPrimaryAttack = -1.0; } if ( pto->m_flNextSecondaryAttack < -0.001 ) { pto->m_flNextSecondaryAttack = -0.001; } if ( pto->m_flTimeWeaponIdle < -0.001 ) { pto->m_flTimeWeaponIdle = -0.001; } if ( pto->m_flNextReload < -0.001 ) { pto->m_flNextReload = -0.001; } /*if ( pto->fuser1 < -0.001 ) { pto->fuser1 = -0.001; }*/ } // m_flNextAttack is now part of the weapons, but is part of the player instead to->client.m_flNextAttack -= cmd->msec / 1000.0f; if ( to->client.m_flNextAttack < -0.001 ) { to->client.m_flNextAttack = -0.001; } // Wipe it so we can't use it after this frame g_finalstate = NULL; }
/* ===================== HUD_WeaponsPostThink Run Weapon firing code on client ===================== */ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cmd, double time, unsigned int random_seed ) { int i; int buttonsChanged; CBasePlayerWeapon* pCurrent = NULL; weapon_data_t nulldata, *pfrom, *pto; static int lasthealth; memset( &nulldata, 0, sizeof( nulldata ) ); HUD_InitClientWeapons(); // Get current clock gpGlobals->time = time; // Fill in data based on selected weapon // FIXME, make this a method in each weapon? where you pass in an entity_state_t *? // Store pointer to our destination entity_state_t so we can get our origin, etc. from it CBasePlayerWeapon* pWeapon = HUD_GetWeaponForID(from->client.m_iId); // for setting up events on the client g_finalstate = to; // If we are running events/etc. go ahead and see if we // managed to die between last frame and this one // If so, run the appropriate player killed or spawn function if ( g_runfuncs ) { if ( to->client.health <= 0 && lasthealth > 0 ) { player.Killed( NULL, 0 ); } else if ( to->client.health > 0 && lasthealth <= 0 ) { player.Spawn(); } lasthealth = to->client.health; } // We are not predicting the current weapon, just bow out here. if ( !pWeapon ) return; for ( i = 0; i < 32; i++ ) { pCurrent = g_pWpns[ i ]; if ( !pCurrent ) { continue; } pfrom = &from->weapondata[ i ]; pCurrent->m_fInReload = pfrom->m_fInReload; pCurrent->m_fInSpecialReload = pfrom->m_fInSpecialReload; // pCurrent->m_flPumpTime = pfrom->m_flPumpTime; pCurrent->m_iClip = pfrom->m_iClip; pCurrent->m_flNextPrimaryAttack = pfrom->m_flNextPrimaryAttack; pCurrent->m_flNextSecondaryAttack = pfrom->m_flNextSecondaryAttack; pCurrent->m_flTimeWeaponIdle = pfrom->m_flTimeWeaponIdle; if(pWeapon && (pWeapon->m_iId == pfrom->m_iId)) { // Predict clip gHUD.m_Ammo.SetCurrentClip(pfrom->m_iClip); AvHBasePlayerWeapon* theWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pWeapon); if(theWeapon) { gHUD.SetCurrentWeaponData(pWeapon->m_iId, theWeapon->GetEnabledState()); } //gHUD.SetClientDebugCSP(pfrom, from->client.m_flNextAttack); } // Tell HUD what energy level is needed to use weapon, so alien HUD can indicate this float theEnergyLevel = 0.0f; AvHMUGetEnergyCost((AvHWeaponID)(pWeapon->m_iId), theEnergyLevel); gHUD.SetCurrentUseableEnergyLevel(theEnergyLevel); // New SDK stuff...needed? // pCurrent->pev->fuser1 = pfrom->fuser1; pCurrent->m_flStartThrow = pfrom->fuser2; pCurrent->m_flReleaseThrow = pfrom->fuser3; // pCurrent->m_chargeReady = pfrom->iuser1; // pCurrent->m_fInAttack = pfrom->iuser2; pCurrent->pev->iuser3 = pfrom->iuser3; // pCurrent->m_iSecondaryAmmoType = (int)from->client.vuser3[2]; pCurrent->m_iPrimaryAmmoType = (int)from->client.vuser4[0]; // player.m_rgAmmo[ pCurrent->m_iPrimaryAmmoType ] = (int)from->client.vuser4[1]; // player.m_rgAmmo[ pCurrent->m_iSecondaryAmmoType ] = (int)from->client.vuser4[2]; } // For random weapon events, use this seed to seed random # generator player.random_seed = random_seed; // Get old buttons from previous state. player.m_afButtonLast = from->playerstate.oldbuttons; // Which buttsons chave changed buttonsChanged = (player.m_afButtonLast ^ cmd->buttons); // These buttons have changed this frame // Debounced button codes for pressed/released // The changed ones still down are "pressed" player.m_afButtonPressed = buttonsChanged & cmd->buttons; // The ones not down are "released" player.m_afButtonReleased = buttonsChanged & (~cmd->buttons); // Set player variables that weapons code might check/alter player.pev->button = cmd->buttons; player.pev->velocity = from->client.velocity; player.pev->flags = from->client.flags; player.pev->deadflag = from->client.deadflag; player.pev->waterlevel = from->client.waterlevel; player.pev->maxspeed = from->client.maxspeed; player.pev->fov = from->client.fov; player.pev->weaponanim = from->client.weaponanim; player.pev->viewmodel = from->client.viewmodel; player.m_flNextAttack = from->client.m_flNextAttack; //player.m_flNextAmmoBurn = from->client.fuser2; //player.m_flAmmoStartCharge = from->client.fuser3; // Removed this because NS uses vuser1 and vuser2 (and the HL weapons aren't used) ////Stores all our ammo info, so the client side weapons can use them. //player.ammo_9mm = (int)from->client.vuser1[0]; //player.ammo_357 = (int)from->client.vuser1[1]; //player.ammo_argrens = (int)from->client.vuser1[2]; //player.ammo_bolts = (int)from->client.ammo_nails; //is an int anyways... //player.ammo_buckshot = (int)from->client.ammo_shells; //player.ammo_uranium = (int)from->client.ammo_cells; //player.ammo_hornets = (int)from->client.vuser2[0]; //player.ammo_rockets = (int)from->client.ammo_rockets; // Point to current weapon object if ( from->client.m_iId ) { player.m_pActiveItem = g_pWpns[ from->client.m_iId ]; } if ( player.m_pActiveItem->m_iId == WEAPON_RPG ) { ( ( CRpg * )player.m_pActiveItem)->m_fSpotActive = (int)from->client.vuser2[ 1 ]; ( ( CRpg * )player.m_pActiveItem)->m_cActiveRockets = (int)from->client.vuser2[ 2 ]; } // Don't go firing anything if we have died. // Or if we don't have a weapon model deployed if ( ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) && !CL_IsDead() && player.pev->viewmodel && !g_iUser1 ) { if ( player.m_flNextAttack <= 0 ) { pWeapon->ItemPostFrame(); } // if ( g_runfuncs ) // { // pWeapon->PrintState(); // } } // Assume that we are not going to switch weapons to->client.m_iId = from->client.m_iId; // Now see if we issued a changeweapon command ( and we're not dead ) if ( cmd->weaponselect && ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) ) { // Switched to a different weapon? if ( from->weapondata[ cmd->weaponselect ].m_iId == cmd->weaponselect ) { ASSERT(cmd->weaponselect >= 0); ASSERT(cmd->weaponselect < 32); CBasePlayerWeapon *pNew = g_pWpns[ cmd->weaponselect ]; if ( pNew && ( pNew != pWeapon ) && player.m_pActiveItem && player.m_pActiveItem->CanHolster()) { // Put away old weapon if (player.m_pActiveItem) player.m_pActiveItem->Holster( ); player.m_pLastItem = player.m_pActiveItem; player.m_pActiveItem = pNew; // Deploy new weapon if (player.m_pActiveItem) { player.m_pActiveItem->Deploy( ); } // Update weapon id so we can predict things correctly. to->client.m_iId = cmd->weaponselect; } } } // Copy in results of prediction code to->client.viewmodel = player.pev->viewmodel; to->client.fov = player.pev->fov; to->client.weaponanim = player.pev->weaponanim; to->client.m_flNextAttack = player.m_flNextAttack; //to->client.fuser2 = player.m_flNextAmmoBurn; //to->client.fuser3 = player.m_flAmmoStartCharge; to->client.maxspeed = player.pev->maxspeed; // Removed this because NS uses vuser1 and vuser2 (and the HL weapons aren't used) // //HL Weapons // to->client.vuser1[0] = player.ammo_9mm; // to->client.vuser1[1] = player.ammo_357; // to->client.vuser1[2] = player.ammo_argrens; // // to->client.ammo_nails = player.ammo_bolts; // to->client.ammo_shells = player.ammo_buckshot; // to->client.ammo_cells = player.ammo_uranium; // to->client.vuser2[0] = player.ammo_hornets; // to->client.ammo_rockets = player.ammo_rockets; if ( player.m_pActiveItem->m_iId == WEAPON_RPG ) { from->client.vuser2[ 1 ] = ( ( CRpg * )player.m_pActiveItem)->m_fSpotActive; from->client.vuser2[ 2 ] = ( ( CRpg * )player.m_pActiveItem)->m_cActiveRockets; } // Make sure that weapon animation matches what the game .dll is telling us // over the wire ( fixes some animation glitches ) if ( g_runfuncs && ( HUD_GetWeaponAnim() != to->client.weaponanim ) ) { int body = 2; //Pop the model to body 0. //if ( pWeapon == &g_Tripmine ) // body = 0; // Force a fixed anim down to viewmodel HUD_SendWeaponAnim( to->client.weaponanim, body, 1 ); } for ( i = 0; i < 32; i++ ) { pCurrent = g_pWpns[ i ]; pto = &to->weapondata[ i ]; if ( !pCurrent ) { memset( pto, 0, sizeof( weapon_data_t ) ); continue; } pto->m_fInReload = pCurrent->m_fInReload; pto->m_fInSpecialReload = pCurrent->m_fInSpecialReload; // pto->m_flPumpTime = pCurrent->m_flPumpTime; pto->m_iClip = pCurrent->m_iClip; pto->m_flNextPrimaryAttack = pCurrent->m_flNextPrimaryAttack; pto->m_flNextSecondaryAttack = pCurrent->m_flNextSecondaryAttack; pto->m_flTimeWeaponIdle = pCurrent->m_flTimeWeaponIdle; // pto->fuser1 = pCurrent->pev->fuser1; // pto->fuser2 = pCurrent->m_flStartThrow; // pto->fuser3 = pCurrent->m_flReleaseThrow; // pto->iuser1 = pCurrent->m_chargeReady; // pto->iuser2 = pCurrent->m_fInAttack; pto->iuser3 = pCurrent->pev->iuser3; // Decrement weapon counters, server does this at same time ( during post think, after doing everything else ) pto->m_flNextReload -= cmd->msec / 1000.0; pto->m_fNextAimBonus -= cmd->msec / 1000.0; pto->m_flNextPrimaryAttack -= cmd->msec / 1000.0; pto->m_flNextSecondaryAttack -= cmd->msec / 1000.0; pto->m_flTimeWeaponIdle -= cmd->msec / 1000.0; pto->fuser1 -= cmd->msec / 1000.0; to->client.vuser3[2] = pCurrent->m_iSecondaryAmmoType; to->client.vuser4 = pCurrent->pev->vuser4; // to->client.vuser4[0] = pCurrent->m_iPrimaryAmmoType; // to->client.vuser4[1] = player.m_rgAmmo[ pCurrent->m_iPrimaryAmmoType ]; // to->client.vuser4[2] = player.m_rgAmmo[ pCurrent->m_iSecondaryAmmoType ]; /* if ( pto->m_flPumpTime != -9999 ) { pto->m_flPumpTime -= cmd->msec / 1000.0; if ( pto->m_flPumpTime < -0.001 ) pto->m_flPumpTime = -0.001; }*/ if ( pto->m_fNextAimBonus < -1.0 ) { pto->m_fNextAimBonus = -1.0; } if ( pto->m_flNextPrimaryAttack < -1.0 ) { pto->m_flNextPrimaryAttack = -1.0; } if ( pto->m_flNextSecondaryAttack < -0.001 ) { pto->m_flNextSecondaryAttack = -0.001; } if ( pto->m_flTimeWeaponIdle < -0.001 ) { pto->m_flTimeWeaponIdle = -0.001; } if ( pto->m_flNextReload < -0.001 ) { pto->m_flNextReload = -0.001; } if ( pto->fuser1 < -0.001 ) { pto->fuser1 = -0.001; } } // m_flNextAttack is now part of the weapons, but is part of the player instead to->client.m_flNextAttack -= cmd->msec / 1000.0; if ( to->client.m_flNextAttack < -0.001 ) { to->client.m_flNextAttack = -0.001; } to->client.fuser2 -= cmd->msec / 1000.0; if ( to->client.fuser2 < -0.001 ) { to->client.fuser2 = -0.001; } to->client.fuser3 -= cmd->msec / 1000.0; if ( to->client.fuser3 < -0.001 ) { to->client.fuser3 = -0.001; } // Store off the last position from the predicted state. HUD_SetLastOrg(); // Wipe it so we can't use it after this frame g_finalstate = NULL; }