/* ===================== 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; }
//----------------------------------------------------------------------------- // Purpose: Overloaded to handle the zoom functionality. //----------------------------------------------------------------------------- void CWeaponSniperRifle::ItemPostFrame( void ) { CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); if (pPlayer == NULL) { return; } if ((m_bInReload) && (m_flNextPrimaryAttack <= gpGlobals->curtime)) { FinishReload(); m_bInReload = false; } if (pPlayer->m_nButtons & IN_ATTACK2) { if (m_fNextZoom <= gpGlobals->curtime) { Zoom(); pPlayer->m_nButtons &= ~IN_ATTACK2; } } else if ((pPlayer->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime)) { if ( (m_iClip1 == 0 && UsesClipsForAmmo1()) || ( !UsesClipsForAmmo1() && !pPlayer->GetAmmoCount(m_iPrimaryAmmoType) ) ) { m_bFireOnEmpty = true; } // Fire underwater? if (pPlayer->GetWaterLevel() == 3 && m_bFiresUnderwater == false) { WeaponSound(EMPTY); m_flNextPrimaryAttack = gpGlobals->curtime + 0.2; return; } else { // If the firing button was just pressed, reset the firing time if ( pPlayer && pPlayer->m_afButtonPressed & IN_ATTACK ) { m_flNextPrimaryAttack = gpGlobals->curtime; } PrimaryAttack(); } } // ----------------------- // Reload pressed / Clip Empty // ----------------------- if ( pPlayer->m_nButtons & IN_RELOAD && UsesClipsForAmmo1() && !m_bInReload ) { // reload when reload is pressed, or if no buttons are down and weapon is empty. Reload(); } // ----------------------- // No buttons down // ----------------------- if (!((pPlayer->m_nButtons & IN_ATTACK) || (pPlayer->m_nButtons & IN_ATTACK2) || (pPlayer->m_nButtons & IN_RELOAD))) { // no fire buttons down m_bFireOnEmpty = false; if ( !HasAnyAmmo() && m_flNextPrimaryAttack < gpGlobals->curtime ) { // weapon isn't useable, switch. if ( !(GetWeaponFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && pPlayer->SwitchToNextBestWeapon( this ) ) { m_flNextPrimaryAttack = gpGlobals->curtime + 0.3; return; } } else { // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing if ( m_iClip1 == 0 && !(GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < gpGlobals->curtime ) { Reload(); return; } } WeaponIdle( ); return; } }
//// HOST_SAY // String comes in as // say blah blah blah // or as // blah blah blah // void Host_Say( edict_t *pEntity, int teamonly ) { CBasePlayer *client; int j; char *p; char text[128]; char szTemp[256]; const char *cpSay = "say"; const char *cpSayTeam = "say_team"; const char *pcmd = CMD_ARGV(0); // We can get a raw string now, without the "say " prepended if ( CMD_ARGC() == 0 ) return; if ( !stricmp( pcmd, cpSay) || !stricmp( pcmd, cpSayTeam ) ) { if ( CMD_ARGC() >= 2 ) { p = (char *)CMD_ARGS(); } else { // say with a blank message, nothing to do return; } } else // Raw text, need to prepend argv[0] { if ( CMD_ARGC() >= 2 ) { sprintf( szTemp, "%s %s", ( char * )pcmd, (char *)CMD_ARGS() ); } else { // Just a one word command, use the first word...sigh sprintf( szTemp, "%s", ( char * )pcmd ); } p = szTemp; } // remove quotes if present if (*p == '"') { p++; p[strlen(p)-1] = 0; } // make sure the text has content for ( char *pc = p; pc != NULL && *pc != 0; pc++ ) { if ( isprint( *pc ) && !isspace( *pc ) ) { pc = NULL; // we've found an alphanumeric character, so text is valid break; } } if ( pc != NULL ) return; // no character found, so say nothing // turn on color set 2 (color on, no sound) if ( teamonly ) sprintf( text, "%c(TEAM) %s: ", 2, STRING( pEntity->v.netname ) ); else sprintf( text, "%c%s: ", 2, STRING( pEntity->v.netname ) ); j = sizeof(text) - 2 - strlen(text); // -2 for /n and null terminator if ( (int)strlen(p) > j ) p[j] = 0; strcat( text, p ); strcat( text, "\n" ); // loop through all players // Start with the first player. // This may return the world in single player if the client types something between levels or during spawn // so check it, or it will infinite loop client = NULL; while ( ((client = (CBasePlayer*)UTIL_FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) ) { if ( !client->pev ) continue; if ( client->edict() == pEntity ) continue; if ( !(client->IsNetClient()) ) // Not a client ? (should never be true) continue; if ( teamonly && g_pGameRules->PlayerRelationship(client, CBaseEntity::Instance(pEntity)) != GR_TEAMMATE ) continue; MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, client->pev ); WRITE_BYTE( ENTINDEX(pEntity) ); WRITE_STRING( text ); MESSAGE_END(); } // print to the sending client MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, &pEntity->v ); WRITE_BYTE( ENTINDEX(pEntity) ); WRITE_STRING( text ); MESSAGE_END(); // echo to server console g_engfuncs.pfnServerPrint( text ); }
//----------------------------------------------------------------------------- // Purpose: Think method //----------------------------------------------------------------------------- void CTFFlameEntity::FlameThink( void ) { // if we've expired, remove ourselves if ( gpGlobals->curtime >= m_flTimeRemove ) { UTIL_Remove( this ); return; } // Do collision detection. We do custom collision detection because we can do it more cheaply than the // standard collision detection (don't need to check against world unless we might have hit an enemy) and // flame entity collision detection w/o this was a bottleneck on the X360 server if ( GetAbsOrigin() != m_vecPrevPos ) { CTFPlayer *pAttacker = dynamic_cast<CTFPlayer *>( (CBaseEntity *) m_hAttacker ); if ( !pAttacker ) return; CUtlVector<CTFTeam *> pTeamList; CTFTeam *pTeam = pAttacker->GetTFTeam(); if ( pTeam ) pTeam->GetOpposingTFTeamList(&pTeamList); else return; //CTFTeam *pTeam = pAttacker->GetOpposingTFTeam(); //if ( !pTeam ) // return; bool bHitWorld = false; for (int i = 0; i < pTeamList.Size(); i++) { if (pTeamList[i]) { // check collision against all enemy players for (int iPlayer = 0; iPlayer < pTeamList[i]->GetNumPlayers(); iPlayer++) { CBasePlayer *pPlayer = pTeamList[i]->GetPlayer(iPlayer); // Is this player connected, alive, and an enemy? if (pPlayer && pPlayer->IsConnected() && pPlayer->IsAlive() && pPlayer!=pAttacker) { CheckCollision(pPlayer, &bHitWorld); if (bHitWorld) return; } } // check collision against all enemy objects for (int iObject = 0; iObject < pTeamList[i]->GetNumObjects(); iObject++) { CBaseObject *pObject = pTeamList[i]->GetObject(iObject); if (pObject) { CheckCollision(pObject, &bHitWorld); if (bHitWorld) return; } } } } } // Calculate how long the flame has been alive for float flFlameElapsedTime = tf_flamethrower_flametime.GetFloat() - ( m_flTimeRemove - gpGlobals->curtime ); // Calculate how much of the attacker's velocity to blend in to the flame's velocity. The flame gets the attacker's velocity // added right when the flame is fired, but that velocity addition fades quickly to zero. float flAttackerVelocityBlend = RemapValClamped( flFlameElapsedTime, tf_flamethrower_velocityfadestart.GetFloat(), tf_flamethrower_velocityfadeend.GetFloat(), 1.0, 0 ); // Reduce our base velocity by the air drag constant m_vecBaseVelocity *= tf_flamethrower_drag.GetFloat(); // Add our float upward velocity Vector vecVelocity = m_vecBaseVelocity + Vector( 0, 0, tf_flamethrower_float.GetFloat() ) + ( flAttackerVelocityBlend * m_vecAttackerVelocity ); // Update our velocity SetAbsVelocity( vecVelocity ); // Render debug visualization if convar on if ( tf_debug_flamethrower.GetInt() ) { if ( m_hEntitiesBurnt.Count() > 0 ) { int val = ( (int) ( gpGlobals->curtime * 10 ) ) % 255; NDebugOverlay::EntityBounds(this, val, 255, val, 0 ,0 ); } else { NDebugOverlay::EntityBounds(this, 0, 100, 255, 0 ,0) ; } } SetNextThink( gpGlobals->curtime ); m_vecPrevPos = GetAbsOrigin(); }
void ClientKill( edict_t *pEdict, const Vector &vecForce, bool bExplode = false ) { CBasePlayer *pPlayer = static_cast<CBasePlayer*>( GetContainingEntity( pEdict ) ); pPlayer->CommitSuicide( vecForce, bExplode ); }
//------------------------------------------------------------------------------ // Purpose : Draws a large crosshair at flCrossDistance from the debug player // with tick marks // Input : // Output : //------------------------------------------------------------------------------ void NDebugOverlay::DrawPositioningOverlay( float flCrossDistance ) { CBasePlayer* pPlayer = UTIL_PlayerByIndex(CBaseEntity::m_nDebugPlayer); if (!pPlayer) { return; } Vector pRight; pPlayer->EyeVectors( NULL, &pRight, NULL ); #ifdef _WIN32 Vector topPos = NWCEdit::AirNodePlacementPosition(); #else Vector pForward; pPlayer->EyeVectors( &pForward ); Vector floorVec = pForward; floorVec.z = 0; VectorNormalize( floorVec ); VectorNormalize( pForward ); float cosAngle = DotProduct(floorVec,pForward); float lookDist = g_pAINetworkManager->GetEditOps()->m_flAirEditDistance/cosAngle; Vector topPos = pPlayer->EyePosition()+pForward * lookDist; #endif Vector bottomPos = topPos; bottomPos.z = GetLongFloorZ(bottomPos); // Make sure we can see the target pos trace_t tr; Vector endPos; UTIL_TraceLine(pPlayer->EyePosition(), topPos, MASK_NPCSOLID_BRUSHONLY, pPlayer, COLLISION_GROUP_NONE, &tr); if (tr.fraction == 1.0) { Vector rightTrace = topPos + pRight*400; float traceLen = (topPos - rightTrace).Length(); UTIL_TraceLine(topPos, rightTrace, MASK_NPCSOLID_BRUSHONLY, pPlayer, COLLISION_GROUP_NONE, &tr); endPos = topPos+(pRight*traceLen*tr.fraction); NDebugOverlay::DrawTickMarkedLine(topPos, endPos, 24.0, 5, 255,0,0,false,0); Vector leftTrace = topPos - pRight*400; traceLen = (topPos - leftTrace).Length(); UTIL_TraceLine(topPos, leftTrace, MASK_NPCSOLID_BRUSHONLY, pPlayer, COLLISION_GROUP_NONE, &tr); endPos = topPos-(pRight*traceLen*tr.fraction); NDebugOverlay::DrawTickMarkedLine(topPos, endPos, 24.0, 5, 255,0,0,false,0); Vector upTrace = topPos + Vector(0,0,1)*400; traceLen = (topPos - upTrace).Length(); UTIL_TraceLine(topPos, upTrace, MASK_NPCSOLID_BRUSHONLY, pPlayer, COLLISION_GROUP_NONE, &tr); endPos = topPos+(Vector(0,0,1)*traceLen*tr.fraction); NDebugOverlay::DrawTickMarkedLine(bottomPos, endPos, 24.0, 5, 255,0,0,false,0); // Draw white cross at center Cross3D(topPos, Vector(-2,-2,-2), Vector(2,2,2), 255,255,255, true, 0); } else { // Draw warning cross at center Cross3D(topPos, Vector(-2,-2,-2), Vector(2,2,2), 255,100,100, true, 0 ); } /* Don't show distance for now. char text[25]; Q_snprintf(text,sizeof(text),"%3.0f",flCrossDistance/12.0); Vector textPos = topPos - pRight*16 + Vector(0,0,10); NDebugOverlay::Text( textPos, text, true, 0 ); */ }
void CWeaponEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) { CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); if ( !pPlayer ) { return; } //CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 450, 0.1 ); WeaponSound( SINGLE ); Vector vecDest = vecOrigSrc + (vecDir * MAX_TRACE_LENGTH); trace_t tr; UTIL_TraceLine( vecOrigSrc, vecDest, MASK_SHOT, pPlayer, COLLISION_GROUP_NONE, &tr ); if ( tr.allsolid ) return; CBaseEntity *pEntity = tr.m_pEnt; if ( pEntity == NULL ) return; if ( g_pGameRules->IsMultiplayer() ) { if ( m_hSprite ) { if ( pEntity->m_takedamage != DAMAGE_NO ) { m_hSprite->TurnOn(); } else { m_hSprite->TurnOff(); } } } if ( m_flDmgTime < gpGlobals->curtime ) { // wide mode does damage to the ent, and radius damage if ( pEntity->m_takedamage != DAMAGE_NO ) { ClearMultiDamage(); CTakeDamageInfo info(this, pPlayer, sk_plr_dmg_egon_wide.GetFloat() * g_pGameRules->GetDamageMultiplier(), DMG_ENERGYBEAM | DMG_ALWAYSGIB | DMG_CRUSH); CalculateMeleeDamageForce( &info, vecDir, tr.endpos ); pEntity->DispatchTraceAttack( info, vecDir, &tr ); ApplyMultiDamage(); } if ( g_pGameRules->IsMultiplayer() ) { // radius damage a little more potent in multiplayer. #ifndef CLIENT_DLL RadiusDamage(CTakeDamageInfo(this, pPlayer, sk_plr_dmg_egon_wide.GetFloat() * g_pGameRules->GetDamageMultiplier() / 4, DMG_ENERGYBEAM | DMG_BLAST | DMG_ALWAYSGIB | DMG_CRUSH), tr.endpos, 128, CLASS_NONE, NULL); #endif } if ( !pPlayer->IsAlive() ) return; if ( g_pGameRules->IsMultiplayer() ) { //multiplayer uses 5 ammo/second if ( gpGlobals->curtime >= m_flAmmoUseTime ) { UseAmmo( 1 ); m_flAmmoUseTime = gpGlobals->curtime + 0.2; } } else { // Wide mode uses 10 charges per second in single player if ( gpGlobals->curtime >= m_flAmmoUseTime ) { UseAmmo( 1 ); m_flAmmoUseTime = gpGlobals->curtime + 0.1; } } m_flDmgTime = gpGlobals->curtime + EGON_DISCHARGE_INTERVAL; if ( m_flShakeTime < gpGlobals->curtime ) { #ifndef CLIENT_DLL UTIL_ScreenShake( tr.endpos, 5.0, 150.0, 0.75, 250.0, SHAKE_START ); #endif m_flShakeTime = gpGlobals->curtime + 1.5; } } Vector vecUp, vecRight; QAngle angDir; VectorAngles( vecDir, angDir ); AngleVectors( angDir, NULL, &vecRight, &vecUp ); Vector tmpSrc = vecOrigSrc + (vecUp * -8) + (vecRight * 3); UpdateEffect( tmpSrc, tr.endpos ); }
void CPlantedC4::C4Think() { if (!IsInWorld()) { UTIL_Remove( this ); return; } //Bomb is dead, don't think anymore if( !m_bBombTicking ) { SetThink( NULL ); return; } SetNextThink( gpGlobals->curtime + 0.12 ); #ifndef CLIENT_DLL // let the bots hear the bomb beeping // BOTPORT: Emit beep events at same time as client effects IGameEvent * event = gameeventmanager->CreateEvent( "bomb_beep" ); if( event ) { event->SetInt( "entindex", entindex() ); gameeventmanager->FireEvent( event ); } #endif // IF the timer has expired ! blow this bomb up! if (m_flC4Blow <= gpGlobals->curtime) { // give the defuser credit for defusing the bomb CBasePlayer *pBombOwner = dynamic_cast< CBasePlayer* >( GetOwnerEntity() ); if ( pBombOwner ) { pBombOwner->IncrementFragCount( 3 ); } CSGameRules()->m_bBombDropped = false; trace_t tr; Vector vecSpot = GetAbsOrigin(); vecSpot[2] += 8; UTIL_TraceLine( vecSpot, vecSpot + Vector ( 0, 0, -40 ), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); Explode( &tr, DMG_BLAST ); CSGameRules()->m_bBombPlanted = false; IGameEvent * event = gameeventmanager->CreateEvent( "bomb_exploded" ); if( event ) { event->SetInt( "userid", pBombOwner?pBombOwner->GetUserID():-1 ); event->SetInt( "site", m_iBombSiteIndex ); event->SetInt( "priority", 9 ); gameeventmanager->FireEvent( event ); } } //if the defusing process has started if ((m_bStartDefuse == true) && (m_pBombDefuser != NULL)) { //if the defusing process has not ended yet if ( m_flDefuseCountDown > gpGlobals->curtime) { int iOnGround = FBitSet( m_pBombDefuser->GetFlags(), FL_ONGROUND ); //if the bomb defuser has stopped defusing the bomb if( m_flNextDefuse < gpGlobals->curtime || !iOnGround ) { if ( !iOnGround && m_pBombDefuser->IsAlive() ) ClientPrint( m_pBombDefuser, HUD_PRINTCENTER, "#C4_Defuse_Must_Be_On_Ground"); // release the player from being frozen m_pBombDefuser->ResetMaxSpeed(); m_pBombDefuser->m_bIsDefusing = false; #ifndef CLIENT_DLL // tell the bots someone has aborted defusing IGameEvent * event = gameeventmanager->CreateEvent( "bomb_abortdefuse" ); if( event ) { event->SetInt("userid", m_pBombDefuser->GetUserID() ); event->SetInt( "priority", 6 ); gameeventmanager->FireEvent( event ); } #endif //cancel the progress bar m_pBombDefuser->SetProgressBarTime( 0 ); m_pBombDefuser = NULL; m_bStartDefuse = false; m_flDefuseCountDown = 0; m_flDefuseLength = 0; //force it to show completely defused } return; } //if the defuse process has ended, kill the c4 else if ( !m_pBombDefuser->IsDead() ) { IGameEvent * event = gameeventmanager->CreateEvent( "bomb_defused" ); if( event ) { event->SetInt("userid", m_pBombDefuser->GetUserID() ); event->SetInt("site", m_iBombSiteIndex ); event->SetInt( "priority", 9 ); gameeventmanager->FireEvent( event ); } Vector soundPosition = m_pBombDefuser->GetAbsOrigin() + Vector( 0, 0, 5 ); CPASAttenuationFilter filter( soundPosition ); EmitSound( filter, entindex(), "c4.disarmfinish" ); // The bomb has just been disarmed.. Check to see if the round should end now m_bBombTicking = false; // release the player from being frozen m_pBombDefuser->ResetMaxSpeed(); m_pBombDefuser->m_bIsDefusing = false; CSGameRules()->m_bBombDefused = true; CSGameRules()->CheckWinConditions(); // give the defuser credit for defusing the bomb m_pBombDefuser->IncrementFragCount( 3 ); CSGameRules()->m_bBombDropped = false; CSGameRules()->m_bBombPlanted = false; // Clear their progress bar. m_pBombDefuser->SetProgressBarTime( 0 ); m_pBombDefuser = NULL; m_bStartDefuse = false; m_flDefuseLength = 10; return; } #ifndef CLIENT_DLL // tell the bots someone has aborted defusing IGameEvent * event = gameeventmanager->CreateEvent( "bomb_abortdefuse" ); if( event ) { event->SetInt("userid", m_pBombDefuser->GetUserID() ); event->SetInt( "priority", 6 ); gameeventmanager->FireEvent( event ); } #endif //if it gets here then the previouse defuser has taken off or been killed // release the player from being frozen m_pBombDefuser->ResetMaxSpeed(); m_pBombDefuser->m_bIsDefusing = false; m_bStartDefuse = false; m_pBombDefuser = NULL; } }
void CGameRules::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore ) { const int MASK_RADIUS_DAMAGE = MASK_SHOT&(~CONTENTS_HITBOX); CBaseEntity *pEntity = NULL; trace_t tr; float flAdjustedDamage, falloff; Vector vecSpot; Vector vecSrc = vecSrcIn; if ( flRadius ) falloff = info.GetDamage() / flRadius; else falloff = 1.0; int bInWater = (UTIL_PointContents ( vecSrc ) & MASK_WATER) ? true : false; #ifdef HL2_DLL if( bInWater ) { // Only muffle the explosion if deeper than 2 feet in water. if( !(UTIL_PointContents(vecSrc + Vector(0, 0, 24)) & MASK_WATER) ) { bInWater = false; } } #endif // HL2_DLL vecSrc.z += 1;// in case grenade is lying on the ground float flHalfRadiusSqr = Square( flRadius / 2.0f ); // iterate on all entities in the vicinity. for ( CEntitySphereQuery sphere( vecSrc, flRadius ); (pEntity = sphere.GetCurrentEntity()) != NULL; sphere.NextEntity() ) { // This value is used to scale damage when the explosion is blocked by some other object. float flBlockedDamagePercent = 0.0f; if ( pEntity == pEntityIgnore ) continue; if ( pEntity->m_takedamage == DAMAGE_NO ) continue; // UNDONE: this should check a damage mask, not an ignore if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) {// houndeyes don't hurt other houndeyes with their attack continue; } // blast's don't tavel into or out of water if (bInWater && pEntity->GetWaterLevel() == 0) continue; if (!bInWater && pEntity->GetWaterLevel() == 3) continue; // Check that the explosion can 'see' this entity. vecSpot = pEntity->BodyTarget( vecSrc, false ); UTIL_TraceLine( vecSrc, vecSpot, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); if( old_radius_damage.GetBool() ) { if ( tr.fraction != 1.0 && tr.m_pEnt != pEntity ) continue; } else { if ( tr.fraction != 1.0 ) { if ( IsExplosionTraceBlocked(&tr) ) { if( ShouldUseRobustRadiusDamage( pEntity ) ) { if( vecSpot.DistToSqr( vecSrc ) > flHalfRadiusSqr ) { // Only use robust model on a target within one-half of the explosion's radius. continue; } Vector vecToTarget = vecSpot - tr.endpos; VectorNormalize( vecToTarget ); // We're going to deflect the blast along the surface that // interrupted a trace from explosion to this target. Vector vecUp, vecDeflect; CrossProduct( vecToTarget, tr.plane.normal, vecUp ); CrossProduct( tr.plane.normal, vecUp, vecDeflect ); VectorNormalize( vecDeflect ); // Trace along the surface that intercepted the blast... UTIL_TraceLine( tr.endpos, tr.endpos + vecDeflect * ROBUST_RADIUS_PROBE_DIST, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); //NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 255, 0, false, 10 ); // ...to see if there's a nearby edge that the explosion would 'spill over' if the blast were fully simulated. UTIL_TraceLine( tr.endpos, vecSpot, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); //NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 0, 0, false, 10 ); if( tr.fraction != 1.0 && tr.DidHitWorld() ) { // Still can't reach the target. continue; } // else fall through } else { continue; } } // UNDONE: Probably shouldn't let children block parents either? Or maybe those guys should set their owner if they want this behavior? // HL2 - Dissolve damage is not reduced by interposing non-world objects if( tr.m_pEnt && tr.m_pEnt != pEntity && tr.m_pEnt->GetOwnerEntity() != pEntity ) { // Some entity was hit by the trace, meaning the explosion does not have clear // line of sight to the entity that it's trying to hurt. If the world is also // blocking, we do no damage. CBaseEntity *pBlockingEntity = tr.m_pEnt; //Msg( "%s may be blocked by %s...", pEntity->GetClassname(), pBlockingEntity->GetClassname() ); UTIL_TraceLine( vecSrc, vecSpot, CONTENTS_SOLID, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); if( tr.fraction != 1.0 ) { continue; } // Now, if the interposing object is physics, block some explosion force based on its mass. if( pBlockingEntity->VPhysicsGetObject() ) { const float MASS_ABSORB_ALL_DAMAGE = 350.0f; float flMass = pBlockingEntity->VPhysicsGetObject()->GetMass(); float scale = flMass / MASS_ABSORB_ALL_DAMAGE; // Absorbed all the damage. if( scale >= 1.0f ) { continue; } ASSERT( scale > 0.0f ); flBlockedDamagePercent = scale; //Msg(" Object (%s) weighing %fkg blocked %f percent of explosion damage\n", pBlockingEntity->GetClassname(), flMass, scale * 100.0f); } else { // Some object that's not the world and not physics. Generically block 25% damage flBlockedDamagePercent = 0.25f; } } } } // decrease damage for an ent that's farther from the bomb. flAdjustedDamage = ( vecSrc - tr.endpos ).Length() * falloff; flAdjustedDamage = info.GetDamage() - flAdjustedDamage; if ( flAdjustedDamage <= 0 ) { continue; } // the explosion can 'see' this entity, so hurt them! if (tr.startsolid) { // if we're stuck inside them, fixup the position and distance tr.endpos = vecSrc; tr.fraction = 0.0; } CTakeDamageInfo adjustedInfo = info; //Msg("%s: Blocked damage: %f percent (in:%f out:%f)\n", pEntity->GetClassname(), flBlockedDamagePercent * 100, flAdjustedDamage, flAdjustedDamage - (flAdjustedDamage * flBlockedDamagePercent) ); adjustedInfo.SetDamage( flAdjustedDamage - (flAdjustedDamage * flBlockedDamagePercent) ); // Now make a consideration for skill level! if( info.GetAttacker() && info.GetAttacker()->IsPlayer() && pEntity->IsNPC() ) { // An explosion set off by the player is harming an NPC. Adjust damage accordingly. adjustedInfo.AdjustPlayerDamageInflictedForSkillLevel(); } Vector dir = vecSpot - vecSrc; VectorNormalize( dir ); // If we don't have a damage force, manufacture one if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin ) { if ( !( adjustedInfo.GetDamageType() & DMG_PREVENT_PHYSICS_FORCE ) ) { CalculateExplosiveDamageForce( &adjustedInfo, dir, vecSrc ); } } else { // Assume the force passed in is the maximum force. Decay it based on falloff. float flForce = adjustedInfo.GetDamageForce().Length() * falloff; adjustedInfo.SetDamageForce( dir * flForce ); adjustedInfo.SetDamagePosition( vecSrc ); } if ( tr.fraction != 1.0 && pEntity == tr.m_pEnt ) { ClearMultiDamage( ); pEntity->DispatchTraceAttack( adjustedInfo, dir, &tr ); ApplyMultiDamage(); } else { pEntity->TakeDamage( adjustedInfo ); } // Now hit all triggers along the way that respond to damage... pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, tr.endpos, dir ); #if defined( GAME_DLL ) if ( info.GetAttacker() && info.GetAttacker()->IsPlayer() && ToBaseCombatCharacter( tr.m_pEnt ) ) { // This is a total hack!!! bool bIsPrimary = true; CBasePlayer *player = ToBasePlayer( info.GetAttacker() ); CBaseCombatWeapon *pWeapon = player->GetActiveWeapon(); if ( pWeapon && FClassnameIs( pWeapon, "weapon_smg1" ) ) { bIsPrimary = false; } gamestats->Event_WeaponHit( player, bIsPrimary, (pWeapon != NULL) ? player->GetActiveWeapon()->GetClassname() : "NULL", info ); } #endif } }
//------------------------------------------------------------------------------ // Purpose : Starts the swing of the weapon and determines the animation // Input : bIsSecondary - is this a secondary attack? //------------------------------------------------------------------------------ void CBaseHL2MPBludgeonWeapon::Swing( int bIsSecondary ) { trace_t traceHit; // Try a ray CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); if ( !pOwner ) return; Vector swingStart = pOwner->Weapon_ShootPosition( ); Vector forward; pOwner->EyeVectors( &forward, NULL, NULL ); Vector swingEnd = swingStart + forward * GetRange(); UTIL_TraceLine( swingStart, swingEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit ); Activity nHitActivity = ACT_VM_HITCENTER; #ifndef CLIENT_DLL // Like bullets, bludgeon traces have to trace against triggers. CTakeDamageInfo triggerInfo( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB ); TraceAttackToTriggers( triggerInfo, traceHit.startpos, traceHit.endpos, vec3_origin ); #endif if ( traceHit.fraction == 1.0 ) { float bludgeonHullRadius = 1.732f * BLUDGEON_HULL_DIM; // hull is +/- 16, so use cuberoot of 2 to determine how big the hull is from center to the corner point // Back off by hull "radius" swingEnd -= forward * bludgeonHullRadius; UTIL_TraceHull( swingStart, swingEnd, g_bludgeonMins, g_bludgeonMaxs, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit ); if ( traceHit.fraction < 1.0 && traceHit.m_pEnt ) { Vector vecToTarget = traceHit.m_pEnt->GetAbsOrigin() - swingStart; VectorNormalize( vecToTarget ); float dot = vecToTarget.Dot( forward ); // YWB: Make sure they are sort of facing the guy at least... if ( dot < 0.70721f ) { // Force amiss traceHit.fraction = 1.0f; } else { nHitActivity = ChooseIntersectionPointAndActivity( traceHit, g_bludgeonMins, g_bludgeonMaxs, pOwner ); } } } WeaponSound( SINGLE ); // ------------------------- // Miss // ------------------------- if ( traceHit.fraction == 1.0f ) { nHitActivity = bIsSecondary ? ACT_VM_MISSCENTER2 : ACT_VM_MISSCENTER; // We want to test the first swing again Vector testEnd = swingStart + forward * GetRange(); // See if we happened to hit water ImpactWater( swingStart, testEnd ); } else { Hit( traceHit, nHitActivity ); } // Send the anim SendWeaponAnim( nHitActivity ); pOwner->SetAnimation( PLAYER_ATTACK1 ); ToHL2MPPlayer(pOwner)->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_PRIMARY ); //Setup our next attack times m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate(); m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration(); }
void CASW_Simple_Alien::MeleeAttack( float distance, float damage, QAngle &viewPunch, Vector &shove ) { Vector vecForceDir; // Always hurt bullseyes for now if ( ( GetEnemy() != NULL ) && ( GetEnemy()->Classify() == CLASS_BULLSEYE ) ) { vecForceDir = (GetEnemy()->GetAbsOrigin() - GetAbsOrigin()); CTakeDamageInfo info( this, this, damage, DMG_SLASH ); CalculateMeleeDamageForce( &info, vecForceDir, GetEnemy()->GetAbsOrigin() ); GetEnemy()->TakeDamage( info ); return; } CBaseEntity *pHurt = CheckTraceHullAttack( distance, -Vector(16,16,32), Vector(16,16,32), damage, DMG_SLASH, 5.0f ); if ( pHurt ) { vecForceDir = ( pHurt->WorldSpaceCenter() - WorldSpaceCenter() ); CBasePlayer *pPlayer = ToBasePlayer( pHurt ); if ( pPlayer != NULL ) { //Kick the player angles pPlayer->ViewPunch( viewPunch ); Vector dir = pHurt->GetAbsOrigin() - GetAbsOrigin(); VectorNormalize(dir); QAngle angles; VectorAngles( dir, angles ); Vector forward, right; AngleVectors( angles, &forward, &right, NULL ); //Push the target back pHurt->ApplyAbsVelocityImpulse( - right * shove[1] - forward * shove[0] ); } // Play a random attack hit sound AttackSound(); // bleed em if ( UTIL_ShouldShowBlood(pHurt->BloodColor()) ) { // Hit an NPC. Bleed them! Vector vecBloodPos; Vector forward, right, up; AngleVectors( GetAbsAngles(), &forward, &right, &up ); //if( GetAttachment( "leftclaw", vecBloodPos ) ) { //Vector diff = vecBloodPos - GetAbsOrigin(); //if (diff.z < 0) //vecBloodPos.z = GetAbsOrigin().z - (diff.z * 2); vecBloodPos = GetAbsOrigin() + forward * 60 - right * 14 + up * 50; SpawnBlood( vecBloodPos, g_vecAttackDir, pHurt->BloodColor(), MIN( damage, 30 ) ); } //if( GetAttachment( "rightclaw", vecBloodPos ) ) { vecBloodPos = GetAbsOrigin() + forward * 60 + right * 14 + up * 50; SpawnBlood( vecBloodPos, g_vecAttackDir, pHurt->BloodColor(), MIN( damage, 30 ) ); } } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeapon357::PrimaryAttack( void ) { // Only the player fires this way so we can cast CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); if ( !pPlayer ) { return; } if ( m_iClip1 <= 0 ) { if ( !m_bFireOnEmpty ) { Reload(); } else { WeaponSound( EMPTY ); m_flNextPrimaryAttack = 0.15; } return; } WeaponSound( SINGLE ); pPlayer->DoMuzzleFlash(); SendWeaponAnim( ACT_VM_PRIMARYATTACK ); pPlayer->SetAnimation( PLAYER_ATTACK1 ); m_flNextPrimaryAttack = gpGlobals->curtime + 0.75; m_flNextSecondaryAttack = gpGlobals->curtime + 0.75; m_iClip1--; Vector vecSrc = pPlayer->Weapon_ShootPosition(); Vector vecAiming = pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); FireBulletsInfo_t info( 1, vecSrc, vecAiming, vec3_origin, MAX_TRACE_LENGTH, m_iPrimaryAmmoType ); info.m_pAttacker = pPlayer; // Fire the bullets, and force the first shot to be perfectly accuracy pPlayer->FireBullets( info ); //Disorient the player QAngle angles = pPlayer->GetLocalAngles(); angles.x += random->RandomInt( -1, 1 ); angles.y += random->RandomInt( -1, 1 ); angles.z = 0; #ifndef CLIENT_DLL pPlayer->SnapEyeAngles( angles ); #endif pPlayer->ViewPunch( QAngle( -8, random->RandomFloat( -2, 2 ), 0 ) ); if ( !m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) { // HEV suit - indicate out of ammo condition pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); } }
//----------------------------------------------------------------------------- // Purpose: See if I can make my leaping attack!! // // //----------------------------------------------------------------------------- int CFastZombie::RangeAttack1Conditions( float flDot, float flDist ) { #define FASTZOMBIE_MINLEAP 128 #define FASTZOMBIE_MAXLEAP 508 // see me if you have questions about this (sjb - telegraphing) if (GetEnemy() == NULL) { return( COND_NONE ); } if( !(GetFlags() & FL_ONGROUND) ) { return COND_NONE; } if( gpGlobals->curtime < m_flNextAttack ) { return( COND_NONE ); } if (flDot < 0.8) { //return COND_NOT_FACING_ATTACK; return COND_NONE; } // make sure the enemy isn't on a roof and I'm in the streets (Ravenholm) float flZDist; flZDist = GetEnemy()->GetLocalOrigin().z - GetLocalOrigin().z; if( flZDist > 128 ) { return COND_TOO_FAR_TO_ATTACK; } if( flDist > FASTZOMBIE_MAXLEAP ) { return COND_TOO_FAR_TO_ATTACK; } if( flDist < FASTZOMBIE_MINLEAP ) { //return COND_TOO_CLOSE_TO_ATTACK; return COND_NONE; } if ( !IsMoving() ) { // I Have to be running!!! return COND_NONE; } // Don't jump at the player unless he's facing me. // This allows the player to get away if he turns and sprints CBasePlayer *pPlayer = static_cast<CBasePlayer*>( GetEnemy() ); if( pPlayer ) { // If the enemy is a player, don't attack from behind! if( !pPlayer->FInViewCone( this ) ) { return COND_NONE; } } // Drumroll please! // The final check! Is the path from my position to halfway between me // and the player clear? trace_t tr; Vector vecDirToEnemy; vecDirToEnemy = GetEnemy()->WorldSpaceCenter() - WorldSpaceCenter(); Vector vecHullMin( -16, -16, -16 ); Vector vecHullMax( 16, 16, 16 ); // only check half the distance. (the first part of the jump) vecDirToEnemy = vecDirToEnemy * 0.5; AI_TraceHull( WorldSpaceCenter(), WorldSpaceCenter() + vecDirToEnemy, vecHullMin, vecHullMax, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); if( tr.fraction != 1.0 ) { // There's some sort of obstacle pretty much right in front of me. return COND_NONE; } return COND_CAN_RANGE_ATTACK1; }
//========================================================= // CWeaponBox - Touch: try to add my contents to the toucher // if the toucher is a player. //========================================================= void CWeaponBox::Touch(CBaseEntity *pOther) { if(!(pev->flags & FL_ONGROUND)) { return; } if(!pOther->IsPlayer()) { // only players may touch a weaponbox. return; } if(!pOther->IsAlive()) { // no dead guys. return; } CBasePlayer *pPlayer = (CBasePlayer *)pOther; int i; // dole out ammo for(i = 0; i < MAX_AMMO_SLOTS; i++) { if(!FStringNull(m_rgiszAmmo[i])) { // there's some ammo of this type. pPlayer->GiveAmmo(m_rgAmmo[i], (char *)STRING(m_rgiszAmmo[i]), MaxAmmoCarry(m_rgiszAmmo[i])); //ALERT ( at_console, "Gave %d rounds of %s\n", m_rgAmmo[i], STRING(m_rgiszAmmo[i]) ); // now empty the ammo from the weaponbox since we just gave it to the player m_rgiszAmmo[i] = iStringNull; m_rgAmmo[i] = 0; } } // go through my weapons and try to give the usable ones to the player. // it's important the the player be given ammo first, so the weapons code doesn't refuse // to deploy a better weapon that the player may pick up because he has no ammo for it. for(i = 0; i < MAX_ITEM_TYPES; i++) { if(m_rgpPlayerItems[i]) { CBasePlayerItem *pItem; // have at least one weapon in this slot while(m_rgpPlayerItems[i]) { //ALERT ( at_console, "trying to give %s\n", STRING( m_rgpPlayerItems[ i ]->pev->classname ) ); pItem = m_rgpPlayerItems[i]; m_rgpPlayerItems[i] = m_rgpPlayerItems[i]->m_pNext; // unlink this weapon from the box if(pPlayer->AddPlayerItem(pItem)) { pItem->AttachToPlayer(pPlayer); } } } } EMIT_SOUND(pOther->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM); SetTouch(NULL); UTIL_Remove(this); }
void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, float flTargetTime ) { Vector org; Vector minsPreScaled; Vector maxsPreScaled; QAngle ang; VPROF_BUDGET( "BacktrackPlayer", "CLagCompensationManager" ); int pl_index = pPlayer->entindex() - 1; // get track history of this player CUtlFixedLinkedList< LagRecord > *track = &m_PlayerTrack[ pl_index ]; // check if we have at leat one entry if ( track->Count() <= 0 ) return; int curr = track->Head(); LagRecord *prevRecord = NULL; LagRecord *record = NULL; Vector prevOrg = pPlayer->GetLocalOrigin(); // Walk context looking for any invalidating event while( track->IsValidIndex(curr) ) { // remember last record prevRecord = record; // get next record record = &track->Element( curr ); if ( !(record->m_fFlags & LC_ALIVE) ) { // player most be alive, lost track return; } Vector delta = record->m_vecOrigin - prevOrg; if ( delta.Length2DSqr() > m_flTeleportDistanceSqr ) { // lost track, too much difference return; } // did we find a context smaller than target time ? if ( record->m_flSimulationTime <= flTargetTime ) break; // hurra, stop prevOrg = record->m_vecOrigin; // go one step back curr = track->Next( curr ); } Assert( record ); if ( !record ) { if ( sv_unlag_debug.GetBool() ) { DevMsg( "No valid positions in history for BacktrackPlayer client ( %s )\n", pPlayer->GetPlayerName() ); } return; // that should never happen } float frac = 0.0f; if ( prevRecord && (record->m_flSimulationTime < flTargetTime) && (record->m_flSimulationTime < prevRecord->m_flSimulationTime) ) { // we didn't find the exact time but have a valid previous record // so interpolate between these two records; Assert( prevRecord->m_flSimulationTime > record->m_flSimulationTime ); Assert( flTargetTime < prevRecord->m_flSimulationTime ); // calc fraction between both records frac = ( flTargetTime - record->m_flSimulationTime ) / ( prevRecord->m_flSimulationTime - record->m_flSimulationTime ); Assert( frac > 0 && frac < 1 ); // should never extrapolate ang = Lerp( frac, record->m_vecAngles, prevRecord->m_vecAngles ); org = Lerp( frac, record->m_vecOrigin, prevRecord->m_vecOrigin ); minsPreScaled = Lerp( frac, record->m_vecMinsPreScaled, prevRecord->m_vecMinsPreScaled ); maxsPreScaled = Lerp( frac, record->m_vecMaxsPreScaled, prevRecord->m_vecMaxsPreScaled ); } else { // we found the exact record or no other record to interpolate with // just copy these values since they are the best we have org = record->m_vecOrigin; ang = record->m_vecAngles; minsPreScaled = record->m_vecMinsPreScaled; maxsPreScaled = record->m_vecMaxsPreScaled; } // See if this is still a valid position for us to teleport to if ( sv_unlag_fixstuck.GetBool() ) { // Try to move to the wanted position from our current position. trace_t tr; UTIL_TraceEntity( pPlayer, org, org, MASK_PLAYERSOLID, &tr ); if ( tr.startsolid || tr.allsolid ) { if ( sv_unlag_debug.GetBool() ) DevMsg( "WARNING: BackupPlayer trying to back player into a bad position - client %s\n", pPlayer->GetPlayerName() ); CBasePlayer *pHitPlayer = dynamic_cast<CBasePlayer *>( tr.m_pEnt ); // don't lag compensate the current player if ( pHitPlayer && ( pHitPlayer != m_pCurrentPlayer ) ) { // If we haven't backtracked this player, do it now // this deliberately ignores WantsLagCompensationOnEntity. if ( !m_RestorePlayer.Get( pHitPlayer->entindex() - 1 ) ) { // prevent recursion - save a copy of m_RestorePlayer, // pretend that this player is off-limits int pl_index = pPlayer->entindex() - 1; // Temp turn this flag on m_RestorePlayer.Set( pl_index ); BacktrackPlayer( pHitPlayer, flTargetTime ); // Remove the temp flag m_RestorePlayer.Clear( pl_index ); } } #ifdef SecobMod__Enable_Fixed_Multiplayer_AI else { CAI_BaseNPC *pHitEntity = dynamic_cast<CAI_BaseNPC *>( tr.m_pEnt ); if ( pHitEntity ) { CAI_BaseNPC *pNPC = NULL; CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs(); int nAIs = g_AI_Manager.NumAIs(); for ( int i = 0; i < nAIs; i++ ) // we'll have to find this entity's index though :( { pNPC = ppAIs[i]; if ( pNPC == pHitEntity ) break; } // If we haven't backtracked this player, do it now // this deliberately ignores WantsLagCompensationOnEntity. if ( pNPC && !m_RestoreEntity.Get( pNPC->GetAIIndex() ) ) { // prevent recursion - save a copy of m_RestoreEntity, // pretend that this player is off-limits // Temp turn this flag on m_RestoreEntity.Set( pNPC->GetAIIndex() ); BacktrackEntity( pHitEntity, flTargetTime ); // Remove the temp flag m_RestoreEntity.Clear( pNPC->GetAIIndex() ); } } } #endif //SecobMod__Enable_Fixed_Multiplayer_AI // now trace us back as far as we can go UTIL_TraceEntity( pPlayer, pPlayer->GetLocalOrigin(), org, MASK_PLAYERSOLID, &tr ); if ( tr.startsolid || tr.allsolid ) { // Our starting position is bogus if ( sv_unlag_debug.GetBool() ) DevMsg( "Backtrack failed completely, bad starting position\n" ); } else { // We can get to a valid place, but not all the way to the target Vector vPos; VectorLerp( pPlayer->GetLocalOrigin(), org, tr.fraction * g_flFractionScale, vPos ); // This is as close as we're going to get org = vPos; if ( sv_unlag_debug.GetBool() ) DevMsg( "Backtrack got most of the way\n" ); } } } // See if this represents a change for the player int flags = 0; LagRecord *restore = &m_RestoreData[ pl_index ]; LagRecord *change = &m_ChangeData[ pl_index ]; QAngle angdiff = pPlayer->GetLocalAngles() - ang; Vector orgdiff = pPlayer->GetLocalOrigin() - org; // Always remember the pristine simulation time in case we need to restore it. restore->m_flSimulationTime = pPlayer->GetSimulationTime(); if ( angdiff.LengthSqr() > LAG_COMPENSATION_EPS_SQR ) { flags |= LC_ANGLES_CHANGED; restore->m_vecAngles = pPlayer->GetLocalAngles(); pPlayer->SetLocalAngles( ang ); change->m_vecAngles = ang; } // Use absolute equality here if ( minsPreScaled != pPlayer->CollisionProp()->OBBMinsPreScaled() || maxsPreScaled != pPlayer->CollisionProp()->OBBMaxsPreScaled() ) { flags |= LC_SIZE_CHANGED; restore->m_vecMinsPreScaled = pPlayer->CollisionProp()->OBBMinsPreScaled(); restore->m_vecMaxsPreScaled = pPlayer->CollisionProp()->OBBMaxsPreScaled(); pPlayer->SetSize( minsPreScaled, maxsPreScaled ); change->m_vecMinsPreScaled = minsPreScaled; change->m_vecMaxsPreScaled = maxsPreScaled; } // Note, do origin at end since it causes a relink into the k/d tree if ( orgdiff.LengthSqr() > LAG_COMPENSATION_EPS_SQR ) { flags |= LC_ORIGIN_CHANGED; restore->m_vecOrigin = pPlayer->GetLocalOrigin(); pPlayer->SetLocalOrigin( org ); change->m_vecOrigin = org; } // Sorry for the loss of the optimization for the case of people // standing still, but you breathe even on the server. // This is quicker than actually comparing all bazillion floats. flags |= LC_ANIMATION_CHANGED; restore->m_masterSequence = pPlayer->GetSequence(); restore->m_masterCycle = pPlayer->GetCycle(); bool interpolationAllowed = false; if( prevRecord && (record->m_masterSequence == prevRecord->m_masterSequence) ) { // If the master state changes, all layers will be invalid too, so don't interp (ya know, interp barely ever happens anyway) interpolationAllowed = true; } //////////////////////// // First do the master settings bool interpolatedMasters = false; if( frac > 0.0f && interpolationAllowed ) { interpolatedMasters = true; pPlayer->SetSequence( Lerp( frac, record->m_masterSequence, prevRecord->m_masterSequence ) ); pPlayer->SetCycle( Lerp( frac, record->m_masterCycle, prevRecord->m_masterCycle ) ); if( record->m_masterCycle > prevRecord->m_masterCycle ) { // the older record is higher in frame than the newer, it must have wrapped around from 1 back to 0 // add one to the newer so it is lerping from .9 to 1.1 instead of .9 to .1, for example. float newCycle = Lerp( frac, record->m_masterCycle, prevRecord->m_masterCycle + 1 ); pPlayer->SetCycle(newCycle < 1 ? newCycle : newCycle - 1 );// and make sure .9 to 1.2 does not end up 1.05 } else { pPlayer->SetCycle( Lerp( frac, record->m_masterCycle, prevRecord->m_masterCycle ) ); } } if( !interpolatedMasters ) { pPlayer->SetSequence(record->m_masterSequence); pPlayer->SetCycle(record->m_masterCycle); } //////////////////////// // Now do all the layers int layerCount = pPlayer->GetNumAnimOverlays(); for( int layerIndex = 0; layerIndex < layerCount; ++layerIndex ) { CAnimationLayer *currentLayer = pPlayer->GetAnimOverlay(layerIndex); if( currentLayer ) { restore->m_layerRecords[layerIndex].m_cycle = currentLayer->m_flCycle; restore->m_layerRecords[layerIndex].m_order = currentLayer->m_nOrder; restore->m_layerRecords[layerIndex].m_sequence = currentLayer->m_nSequence; restore->m_layerRecords[layerIndex].m_weight = currentLayer->m_flWeight; bool interpolated = false; if( (frac > 0.0f) && interpolationAllowed ) { LayerRecord &recordsLayerRecord = record->m_layerRecords[layerIndex]; LayerRecord &prevRecordsLayerRecord = prevRecord->m_layerRecords[layerIndex]; if( (recordsLayerRecord.m_order == prevRecordsLayerRecord.m_order) && (recordsLayerRecord.m_sequence == prevRecordsLayerRecord.m_sequence) ) { // We can't interpolate across a sequence or order change interpolated = true; if( recordsLayerRecord.m_cycle > prevRecordsLayerRecord.m_cycle ) { // the older record is higher in frame than the newer, it must have wrapped around from 1 back to 0 // add one to the newer so it is lerping from .9 to 1.1 instead of .9 to .1, for example. float newCycle = Lerp( frac, recordsLayerRecord.m_cycle, prevRecordsLayerRecord.m_cycle + 1 ); currentLayer->m_flCycle = newCycle < 1 ? newCycle : newCycle - 1;// and make sure .9 to 1.2 does not end up 1.05 } else { currentLayer->m_flCycle = Lerp( frac, recordsLayerRecord.m_cycle, prevRecordsLayerRecord.m_cycle ); } currentLayer->m_nOrder = recordsLayerRecord.m_order; currentLayer->m_nSequence = recordsLayerRecord.m_sequence; currentLayer->m_flWeight = Lerp( frac, recordsLayerRecord.m_weight, prevRecordsLayerRecord.m_weight ); } } if( !interpolated ) { //Either no interp, or interp failed. Just use record. currentLayer->m_flCycle = record->m_layerRecords[layerIndex].m_cycle; currentLayer->m_nOrder = record->m_layerRecords[layerIndex].m_order; currentLayer->m_nSequence = record->m_layerRecords[layerIndex].m_sequence; currentLayer->m_flWeight = record->m_layerRecords[layerIndex].m_weight; } } } if ( !flags ) return; // we didn't change anything if ( sv_lagflushbonecache.GetBool() ) pPlayer->InvalidateBoneCache(); /*char text[256]; Q_snprintf( text, sizeof(text), "time %.2f", flTargetTime ); pPlayer->DrawServerHitboxes( 10 ); NDebugOverlay::Text( org, text, false, 10 ); NDebugOverlay::EntityBounds( pPlayer, 255, 0, 0, 32, 10 ); */ m_RestorePlayer.Set( pl_index ); //remember that we changed this player m_bNeedToRestore = true; // we changed at least one player restore->m_fFlags = flags; // we need to restore these flags change->m_fFlags = flags; // we have changed these flags if( sv_showlagcompensation.GetInt() == 1 ) { pPlayer->DrawServerHitboxes(4, true); } }
//----------------------------------------------------------------------------- // Purpose: // // //----------------------------------------------------------------------------- void CHL2MPMachineGun::PrimaryAttack( void ) { // Only the player fires this way so we can cast CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); if (!pPlayer) return; // Abort here to handle burst and auto fire modes if ( (UsesClipsForAmmo1() && m_iClip1 == 0) || ( !UsesClipsForAmmo1() && !pPlayer->GetAmmoCount(m_iPrimaryAmmoType) ) ) return; m_nShotsFired++; // MUST call sound before removing a round from the clip of a CHLMachineGun // FIXME: only called once, will miss multiple sound events per frame if needed // FIXME: m_flNextPrimaryAttack is always in the past, it's not clear what'll happen with sounds WeaponSound(SINGLE, m_flNextPrimaryAttack); // Msg("%.3f\n", m_flNextPrimaryAttack.Get() ); pPlayer->DoMuzzleFlash(); // To make the firing framerate independent, we may have to fire more than one bullet here on low-framerate systems, // especially if the weapon we're firing has a really fast rate of fire. int iBulletsToFire = 0; float fireRate = GetFireRate(); while ( m_flNextPrimaryAttack <= gpGlobals->curtime ) { m_flNextPrimaryAttack = m_flNextPrimaryAttack + fireRate; iBulletsToFire++; } // Make sure we don't fire more than the amount in the clip, if this weapon uses clips if ( UsesClipsForAmmo1() ) { if ( iBulletsToFire > m_iClip1 ) iBulletsToFire = m_iClip1; m_iClip1 -= iBulletsToFire; } CHL2MP_Player *pHL2MPPlayer = ToHL2MPPlayer( pPlayer ); // Fire the bullets FireBulletsInfo_t info; info.m_iShots = iBulletsToFire; info.m_vecSrc = pHL2MPPlayer->Weapon_ShootPosition( ); info.m_vecDirShooting = pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); info.m_vecSpread = pHL2MPPlayer->GetAttackSpread( this ); info.m_flDistance = MAX_TRACE_LENGTH; info.m_iAmmoType = m_iPrimaryAmmoType; info.m_iTracerFreq = 2; FireBullets( info ); //Factor in the view kick AddViewKick(); if (!m_iClip1 && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0) { // HEV suit - indicate out of ammo condition pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); } SendWeaponAnim( GetPrimaryAttackActivity() ); pPlayer->SetAnimation( PLAYER_ATTACK1 ); }
//--------------------------------------------------------- // Returns distance to the nearest BaseCombatCharacter. //--------------------------------------------------------- float CBounceBomb::FindNearestNPC() { float flNearest = (BOUNCEBOMB_WARN_RADIUS * BOUNCEBOMB_WARN_RADIUS) + 1.0; // Assume this search won't find anyone. SetNearestNPC( NULL ); CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs(); int nAIs = g_AI_Manager.NumAIs(); for ( int i = 0; i < nAIs; i++ ) { CAI_BaseNPC *pNPC = ppAIs[ i ]; if( pNPC->IsAlive() ) { // ignore hidden objects if ( pNPC->IsEffectActive( EF_NODRAW ) ) continue; // Don't bother with NPC's that are below me. if( pNPC->EyePosition().z < GetAbsOrigin().z ) continue; // Disregard things that want to be disregarded if( pNPC->Classify() == CLASS_NONE ) continue; // Disregard bullseyes if( pNPC->Classify() == CLASS_BULLSEYE ) continue; // Disregard turrets if( pNPC->m_iClassname == gm_iszFloorTurretClassname || pNPC->m_iClassname == gm_iszGroundTurretClassname ) continue; float flDist = (GetAbsOrigin() - pNPC->GetAbsOrigin()).LengthSqr(); if( flDist < flNearest ) { // Now do a visibility test. if( FVisible( pNPC, MASK_SOLID_BRUSHONLY ) ) { flNearest = flDist; SetNearestNPC( pNPC ); } } } } // finally, check the player. CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); if( pPlayer && !(pPlayer->GetFlags() & FL_NOTARGET) ) { float flDist = (pPlayer->GetAbsOrigin() - GetAbsOrigin() ).LengthSqr(); if( flDist < flNearest && FVisible( pPlayer, MASK_SOLID_BRUSHONLY ) ) { flNearest = flDist; SetNearestNPC( pPlayer ); } } if( m_hNearestNPC.Get() ) { // If sprite is active, update its color to reflect who is nearest. if( IsFriend( m_hNearestNPC ) ) { if( m_bFoeNearest ) { // Changing state to where a friend is nearest. if( IsFriend( m_hNearestNPC ) ) { // Friend UpdateLight( true, 0, 255, 0, 190 ); m_bFoeNearest = false; } } } else // it's a foe { if( !m_bFoeNearest ) { // Changing state to where a foe is nearest. UpdateLight( true, 255, 0, 0, 190 ); m_bFoeNearest = true; } } } return sqrt( flNearest ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponSMG1::SecondaryAttack( void ) { // Only the player fires this way so we can cast CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); if ( pPlayer == NULL ) return; //Must have ammo if ( ( pPlayer->GetAmmoCount( m_iSecondaryAmmoType ) <= 0 ) || ( pPlayer->GetWaterLevel() == 3 ) ) { SendWeaponAnim( ACT_VM_DRYFIRE ); BaseClass::WeaponSound( EMPTY ); m_flNextSecondaryAttack = gpGlobals->curtime + 0.5f; return; } if( m_bInReload ) m_bInReload = false; // MUST call sound before removing a round from the clip of a CMachineGun BaseClass::WeaponSound( WPN_DOUBLE ); pPlayer->RumbleEffect( RUMBLE_357, 0, RUMBLE_FLAGS_NONE ); Vector vecSrc = pPlayer->Weapon_ShootPosition(); Vector vecThrow; // Don't autoaim on grenade tosses AngleVectors( pPlayer->EyeAngles() + pPlayer->GetPunchAngle(), &vecThrow ); VectorScale( vecThrow, 1000.0f, vecThrow ); //Create the grenade QAngle angles; VectorAngles( vecThrow, angles ); CGrenadeAR2 *pGrenade = (CGrenadeAR2*)Create( "grenade_ar2", vecSrc, angles, pPlayer ); pGrenade->SetAbsVelocity( vecThrow ); pGrenade->SetLocalAngularVelocity( RandomAngle( -400, 400 ) ); pGrenade->SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE ); pGrenade->SetThrower( GetOwner() ); pGrenade->SetDamage( sk_plr_dmg_smg1_grenade.GetFloat() ); SendWeaponAnim( ACT_VM_SECONDARYATTACK ); CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 1000, 0.2, GetOwner(), SOUNDENT_CHANNEL_WEAPON ); // player "shoot" animation pPlayer->SetAnimation( PLAYER_ATTACK1 ); // Decrease ammo if (!(pPlayer->GetBlaFlags() & FL_BLA_INFAMMO)) pPlayer->RemoveAmmo( 1, m_iSecondaryAmmoType ); // Can shoot again immediately m_flNextPrimaryAttack = gpGlobals->curtime + 0.5f; // Can blow up after a short delay (so have time to release mouse button) m_flNextSecondaryAttack = gpGlobals->curtime + 1.0f; // Register a muzzleflash for the AI. pPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 0.5 ); m_iSecondaryAttacks++; gamestats->Event_WeaponFired( pPlayer, false, GetClassname() ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponEgon::PrimaryAttack( void ) { CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); if ( !pPlayer ) { return; } // don't fire underwater if ( pPlayer->GetWaterLevel() == 3 ) { if ( m_fireState != FIRE_OFF || m_hBeam ) { EndAttack(); } else { WeaponSound( EMPTY ); } m_flNextPrimaryAttack = gpGlobals->curtime + 0.5; m_flNextSecondaryAttack = gpGlobals->curtime + 0.5; return; } Vector vecAiming = pPlayer->GetAutoaimVector( 0 ); Vector vecSrc = pPlayer->Weapon_ShootPosition( ); switch( m_fireState ) { case FIRE_OFF: { if ( !HasAmmo() ) { m_flNextPrimaryAttack = gpGlobals->curtime + 0.25; m_flNextSecondaryAttack = gpGlobals->curtime + 0.25; WeaponSound( EMPTY ); return; } m_flAmmoUseTime = gpGlobals->curtime;// start using ammo ASAP. EmitSound( "Weapon_Gluon.Start" ); SendWeaponAnim( ACT_VM_PRIMARYATTACK ); m_flShakeTime = 0; m_flStartFireTime = gpGlobals->curtime; SetWeaponIdleTime( gpGlobals->curtime + 0.1 ); m_flDmgTime = gpGlobals->curtime + EGON_PULSE_INTERVAL; m_fireState = FIRE_STARTUP; } break; case FIRE_STARTUP: { Fire( vecSrc, vecAiming ); if ( gpGlobals->curtime >= ( m_flStartFireTime + 2.0 ) ) { EmitSound( "Weapon_Gluon.Run" ); m_fireState = FIRE_CHARGE; } if ( !HasAmmo() ) { EndAttack(); m_flNextPrimaryAttack = gpGlobals->curtime + 1.0; m_flNextSecondaryAttack = gpGlobals->curtime + 1.0; } } case FIRE_CHARGE: { Fire( vecSrc, vecAiming ); if ( !HasAmmo() ) { EndAttack(); m_flNextPrimaryAttack = gpGlobals->curtime + 1.0; m_flNextSecondaryAttack = gpGlobals->curtime + 1.0; } } break; } }
//----------------------------------------------------------------------------- // Purpose: // Output : float //----------------------------------------------------------------------------- float CBaseHL2MPCombatWeapon::CalcViewmodelBob( void ) { static float bobtime; static float lastbobtime; float cycle; CBasePlayer *player = ToBasePlayer( GetOwner() ); //Assert( player ); //NOTENOTE: For now, let this cycle continue when in the air, because it snaps badly without it if ( ( !gpGlobals->frametime ) || ( player == NULL ) ) { //NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!) return 0.0f;// just use old value } //Find the speed of the player float speed = player->GetLocalVelocity().Length2D(); //FIXME: This maximum speed value must come from the server. // MaxSpeed() is not sufficient for dealing with sprinting - jdw speed = clamp( speed, -320, 320 ); float bob_offset = RemapVal( speed, 0, 320, 0.0f, 1.0f ); bobtime += ( gpGlobals->curtime - lastbobtime ) * bob_offset; lastbobtime = gpGlobals->curtime; //Calculate the vertical bob cycle = bobtime - (int)(bobtime/HL2_BOB_CYCLE_MAX)*HL2_BOB_CYCLE_MAX; cycle /= HL2_BOB_CYCLE_MAX; if ( cycle < HL2_BOB_UP ) { cycle = M_PI * cycle / HL2_BOB_UP; } else { cycle = M_PI + M_PI*(cycle-HL2_BOB_UP)/(1.0 - HL2_BOB_UP); } g_verticalBob = speed*0.005f; g_verticalBob = g_verticalBob*0.3 + g_verticalBob*0.7*sin(cycle); g_verticalBob = clamp( g_verticalBob, -7.0f, 4.0f ); //Calculate the lateral bob cycle = bobtime - (int)(bobtime/HL2_BOB_CYCLE_MAX*2)*HL2_BOB_CYCLE_MAX*2; cycle /= HL2_BOB_CYCLE_MAX*2; if ( cycle < HL2_BOB_UP ) { cycle = M_PI * cycle / HL2_BOB_UP; } else { cycle = M_PI + M_PI*(cycle-HL2_BOB_UP)/(1.0 - HL2_BOB_UP); } g_lateralBob = speed*0.005f; g_lateralBob = g_lateralBob*0.3 + g_lateralBob*0.7*sin(cycle); g_lateralBob = clamp( g_lateralBob, -7.0f, 4.0f ); //NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!) return 0.0f; }
//----------------------------------------------------------------------------- // Purpose: Override so shotgun can do mulitple reloads in a row //----------------------------------------------------------------------------- void CWeaponShotgun::ItemPostFrame( void ) { CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); if (!pOwner) { return; } if ( m_bNeedPump && ( pOwner->m_nButtons & IN_RELOAD ) ) { m_bDelayedReload = true; } if (m_bInReload) { // If I'm primary firing and have one round stop reloading and fire if ((pOwner->m_nButtons & IN_ATTACK ) && (m_iClip1 >=1) && !m_bNeedPump ) { m_bInReload = false; m_bNeedPump = false; m_bDelayedFire1 = true; } // If I'm secondary firing and have two rounds stop reloading and fire else if ((pOwner->m_nButtons & IN_ATTACK2 ) && (m_iClip1 >=2) && !m_bNeedPump ) { m_bInReload = false; m_bNeedPump = false; m_bDelayedFire2 = true; } else if (m_flNextPrimaryAttack <= gpGlobals->curtime) { // If out of ammo end reload if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <=0) { FinishReload(); return; } // If clip not full reload again if (m_iClip1 < GetMaxClip1()) { Reload(); return; } // Clip full, stop reloading else { FinishReload(); return; } } } else { // Make shotgun shell invisible SetBodygroup(1,1); } if ((m_bNeedPump) && (m_flNextPrimaryAttack <= gpGlobals->curtime)) { Pump(); return; } // Shotgun uses same timing and ammo for secondary attack if ((m_bDelayedFire2 || pOwner->m_nButtons & IN_ATTACK2)&&(m_flNextPrimaryAttack <= gpGlobals->curtime)) { m_bDelayedFire2 = false; if ( (m_iClip1 <= 1 && UsesClipsForAmmo1())) { // If only one shell is left, do a single shot instead if ( m_iClip1 == 1 ) { PrimaryAttack(); } else if (!pOwner->GetAmmoCount(m_iPrimaryAmmoType)) { DryFire(); } else { StartReload(); } } // Fire underwater? else if (GetOwner()->GetWaterLevel() == 3 && m_bFiresUnderwater == false) { WeaponSound(EMPTY); m_flNextPrimaryAttack = gpGlobals->curtime + 0.2; return; } else { // If the firing button was just pressed, reset the firing time if ( pOwner->m_afButtonPressed & IN_ATTACK ) { m_flNextPrimaryAttack = gpGlobals->curtime; } SecondaryAttack(); } } else if ( (m_bDelayedFire1 || pOwner->m_nButtons & IN_ATTACK) && m_flNextPrimaryAttack <= gpGlobals->curtime) { m_bDelayedFire1 = false; if ( (m_iClip1 <= 0 && UsesClipsForAmmo1()) || ( !UsesClipsForAmmo1() && !pOwner->GetAmmoCount(m_iPrimaryAmmoType) ) ) { if (!pOwner->GetAmmoCount(m_iPrimaryAmmoType)) { DryFire(); } else { StartReload(); } } // Fire underwater? else if (pOwner->GetWaterLevel() == 3 && m_bFiresUnderwater == false) { WeaponSound(EMPTY); m_flNextPrimaryAttack = gpGlobals->curtime + 0.2; return; } else { // If the firing button was just pressed, reset the firing time CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); if ( pPlayer && pPlayer->m_afButtonPressed & IN_ATTACK ) { m_flNextPrimaryAttack = gpGlobals->curtime; } PrimaryAttack(); } } if ( pOwner->m_nButtons & IN_RELOAD && UsesClipsForAmmo1() && !m_bInReload ) { // reload when reload is pressed, or if no buttons are down and weapon is empty. StartReload(); } else { // no fire buttons down m_bFireOnEmpty = false; if ( !HasAnyAmmo() && m_flNextPrimaryAttack < gpGlobals->curtime ) { // weapon isn't useable, switch. if ( !(GetWeaponFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && pOwner->SwitchToNextBestWeapon( this ) ) { m_flNextPrimaryAttack = gpGlobals->curtime + 0.3; return; } } else { // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing if ( m_iClip1 <= 0 && !(GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < gpGlobals->curtime ) { if (StartReload()) { // if we've successfully started to reload, we're done return; } } } WeaponIdle( ); return; } }
int CAI_LeadBehavior::SelectSchedule() { if (HasGoal()) { if (HasCondition(COND_LEAD_SUCCESS)) { return SCHED_LEAD_SUCCEED; } // Player's here, but does he have the weapon we want him to have? if (m_weaponname != NULL_STRING) { CBasePlayer *pFollower = AI_GetSinglePlayer(); if (pFollower && !pFollower->Weapon_OwnsThisType(STRING(m_weaponname))) { // If the safety timeout has run out, just give the player the weapon if (!m_flWeaponSafetyTimeOut || (m_flWeaponSafetyTimeOut > gpGlobals->curtime)) return SCHED_LEAD_PLAYERNEEDSWEAPON; string_t iszItem = AllocPooledString("weapon_bugbait"); pFollower->GiveNamedItem(STRING(iszItem)); } } // If we have a waitpoint, we want to wait at it for the player. if (HasWaitPoint() && !PlayerIsAheadOfMe(true)) { bool bKeepWaiting = true; // If we have no wait distance, trigger as soon as the player comes in view if (!m_waitdistance) { if (HasCondition(COND_SEE_PLAYER)) { // We've spotted the player, so stop waiting bKeepWaiting = false; } } else { // We have to collect data about the person we're leading around. CBaseEntity *pFollower = AI_GetSinglePlayer(); if (pFollower) { float flFollowerDist = (WorldSpaceCenter() - pFollower->WorldSpaceCenter()).Length(); if (flFollowerDist < m_waitdistance) { bKeepWaiting = false; } } } // Player still not here? if (bKeepWaiting) return SCHED_LEAD_WAITFORPLAYER; // We're finished waiting m_waitpoint = vec3_origin; Speak(TLK_LEAD_WAITOVER); // Don't speak the start line, because we've said m_hasspokenstart = true; return SCHED_WAIT_FOR_SPEAK_FINISH; } // If we haven't spoken our start speech, do that first if (!m_hasspokenstart) { if (HasCondition(COND_LEAD_HAVE_FOLLOWER_LOS) && HasCondition(COND_LEAD_FOLLOWER_VERY_CLOSE)) return SCHED_LEAD_SPEAK_START; // We haven't spoken to him, and we still need to. Go get him. return SCHED_LEAD_RETRIEVE; } if (HasCondition(COND_LEAD_FOLLOWER_LOST)) { if (m_args.iRetrievePlayer) { // If not, we want to go get the player. DevMsg(GetOuter(), "Follower lost. Spoke COMING_BACK.\n"); Speak(TLK_LEAD_COMINGBACK); m_MoveMonitor.ClearMark(); // If we spoke something, wait for it to finish if (m_args.iComingBackWaitForSpeak && IsSpeaking()) return SCHED_LEAD_SPEAK_THEN_RETRIEVE_PLAYER; return SCHED_LEAD_RETRIEVE; } else { // Just stay right here and wait. return SCHED_LEAD_WAITFORPLAYERIDLE; } } if (HasCondition(COND_LEAD_FOLLOWER_LAGGING)) { DevMsg(GetOuter(), "Follower lagging. Spoke CATCHUP.\n"); Speak(TLK_LEAD_CATCHUP); return SCHED_LEAD_PAUSE; } else { // If we're at the goal, wait for the player to get here if ((WorldSpaceCenter() - m_goal).LengthSqr() < (64 * 64)) return SCHED_LEAD_AWAIT_SUCCESS; // If we were retrieving the player, speak the resume if (IsCurSchedule(SCHED_LEAD_RETRIEVE, false) || IsCurSchedule(SCHED_LEAD_WAITFORPLAYERIDLE, false)) { Speak(TLK_LEAD_RETRIEVE); // If we spoke something, wait for it to finish, if the mapmakers wants us to if (m_args.iRetrieveWaitForSpeak && IsSpeaking()) return SCHED_LEAD_SPEAK_THEN_LEAD_PLAYER; } DevMsg(GetOuter(), "Leading Follower.\n"); return SCHED_LEAD_PLAYER; } } return BaseClass::SelectSchedule(); }
//// HOST_SAY // String comes in as // say blah blah blah // or as // blah blah blah // void Host_Say( edict_t *pEdict, const CCommand &args, MessageMode_t messageMode ) { CBasePlayer *client; int j; char *p; char szTemp[256]; char text[256]; const char *cpSay = "say"; const char *cpSayTeam = "say_team"; const char *cpSaySpec = "say_spec"; const char *pcmd = args[0]; bool bSenderDead = false; // We can get a raw string now, without the "say " prepended if ( args.ArgC() == 0 ) return; if ( !stricmp( pcmd, cpSay) || !stricmp( pcmd, cpSayTeam ) || !stricmp( pcmd, cpSaySpec ) ) { if ( args.ArgC() >= 2 ) { p = (char *)args.ArgS(); } else { // say with a blank message, nothing to do return; } } else // Raw text, need to prepend argv[0] { if ( args.ArgC() >= 2 ) { Q_snprintf( szTemp,sizeof(szTemp), "%s %s", ( char * )pcmd, (char *)args.ArgS() ); } else { // Just a one word command, use the first word...sigh Q_snprintf( szTemp,sizeof(szTemp), "%s", ( char * )pcmd ); } p = szTemp; } CBasePlayer *pPlayer = NULL; if ( pEdict ) { pPlayer = ((CBasePlayer *)CBaseEntity::Instance( pEdict )); Assert( pPlayer ); // make sure the text has valid content p = CheckChatText( pPlayer, p ); } if ( !p ) return; if ( pEdict ) { if ( !pPlayer->CanSpeak(messageMode) ) return; // See if the player wants to modify of check the text pPlayer->CheckChatText( p, 127 ); // though the buffer szTemp that p points to is 256, // chat text is capped to 127 in CheckChatText above Assert( strlen( pPlayer->GetPlayerName() ) > 0 ); bSenderDead = ( pPlayer->m_lifeState != LIFE_ALIVE ); } else { bSenderDead = false; } const char *pszFormat = NULL; const char *pszPrefix = NULL; char pszLocation[8]; if ( g_pGameRules ) { pszFormat = g_pGameRules->GetChatFormat( messageMode, pPlayer ); pszPrefix = g_pGameRules->GetChatPrefix( messageMode, pPlayer ); if (pPlayer && pPlayer->GetTeam() && pPlayer->GetTeam()->GetCaptain() == pPlayer) Q_snprintf(pszLocation, sizeof(pszLocation), "(%s)", g_pGameRules->GetChatLocation( messageMode, pPlayer )); else Q_snprintf(pszLocation, sizeof(pszLocation), "%s", g_pGameRules->GetChatLocation( messageMode, pPlayer )); } const char *pszPlayerName = pPlayer ? pPlayer->GetPlayerName() : "Stadium Announcer"; // loop through all players // Start with the first player. // This may return the world in single player if the client types something between levels or during spawn // so check it, or it will infinite loop client = NULL; for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { client = ToBaseMultiplayerPlayer( UTIL_PlayerByIndex( i ) ); if ( !client || !client->edict() ) continue; if ( client->edict() == pEdict ) continue; if ( !(client->IsNetClient()) ) // Not a client ? (should never be true) continue; if ( messageMode != MM_SAY && !g_pGameRules->PlayerCanHearChat( client, pPlayer, messageMode ) ) continue; if ( pPlayer && !client->CanHearAndReadChatFrom( pPlayer ) ) continue; if ( pPlayer && GetVoiceGameMgr() && GetVoiceGameMgr()->IsPlayerIgnoringPlayer( pPlayer->entindex(), i ) ) continue; CSingleUserRecipientFilter user( client ); user.MakeReliable(); UTIL_SayText2Filter( user, pPlayer, true, pszFormat, pszPlayerName, p, pszLocation, pszPrefix ); } if ( pPlayer ) { // print to the sending client CSingleUserRecipientFilter user( pPlayer ); user.MakeReliable(); UTIL_SayText2Filter( user, pPlayer, true, pszFormat, pszPlayerName, p, pszLocation, pszPrefix ); } // echo to server console // Adrian: Only do this if we're running a dedicated server since we already print to console on the client. if ( engine->IsDedicatedServer() ) { Q_snprintf( text, sizeof(text), "%s: ", pszPlayerName ); j = sizeof(text) - 2 - strlen(text); // -2 for /n and null terminator if ( (int)strlen(p) > j ) p[j] = 0; Q_strncat( text, p, sizeof( text ), COPY_ALL_CHARACTERS ); Q_strncat( text, "\n", sizeof( text ), COPY_ALL_CHARACTERS ); Msg( "%s", text ); } Assert( p ); int userid = 0; const char *networkID = "Console"; const char *playerName = "Console"; const char *playerTeam = "Console"; if ( pPlayer ) { userid = pPlayer->GetUserID(); networkID = pPlayer->GetNetworkIDString(); playerName = pPlayer->GetPlayerName(); CTeam *team = pPlayer->GetTeam(); if ( team ) { playerTeam = team->GetKitName(); } } if ( messageMode == MM_SAY_TEAM ) UTIL_LogPrintf( "\"%s<%i><%s><%s>\" say_team \"%s\"\n", playerName, userid, networkID, playerTeam, p ); else if ( messageMode == MM_SAY_SPEC ) UTIL_LogPrintf( "\"%s<%i><%s><%s>\" say_spec \"%s\"\n", playerName, userid, networkID, playerTeam, p ); else UTIL_LogPrintf( "\"%s<%i><%s><%s>\" say \"%s\"\n", playerName, userid, networkID, playerTeam, p ); IGameEvent * event = gameeventmanager->CreateEvent( "player_say" ); if ( event ) // will be null if there are no listeners! { event->SetInt("userid", userid ); event->SetString("text", p ); event->SetInt("priority", 1 ); // HLTV event priority, not transmitted gameeventmanager->FireEvent( event ); } }
//------------------------------------------------------------------------------ // Purpose: Samples the player's inputs and fires outputs based on what buttons // are currently held down. //------------------------------------------------------------------------------ void CGameUI::Think( void ) { CBasePlayer *pPlayer = m_player; // If player is gone, stop thinking if (pPlayer == NULL) { SetNextThink( TICK_NEVER_THINK ); return; } // ------------------------------------------------ // Check that toucher is facing the UI within // the field of view tolerance. If not disconnect // ------------------------------------------------ if (m_flFieldOfView > -1) { Vector vPlayerFacing; pPlayer->EyeVectors( &vPlayerFacing ); Vector vPlayerToUI = GetAbsOrigin() - pPlayer->WorldSpaceCenter(); VectorNormalize(vPlayerToUI); float flDotPr = DotProduct(vPlayerFacing,vPlayerToUI); if (flDotPr < m_flFieldOfView) { Deactivate( pPlayer ); return; } } pPlayer->AddFlag( FL_ONTRAIN ); SetNextThink( gpGlobals->curtime ); // BUGBUG: m_afButtonPressed is broken - check the player.cpp code!!! // // Deactivate if they jump or press +use. // FIXME: prevent the use from going through in player.cpp if ((( pPlayer->m_afButtonPressed & IN_USE ) && ( m_spawnflags & SF_GAMEUI_USE_DEACTIVATES )) || (( pPlayer->m_afButtonPressed & IN_JUMP ) && ( m_spawnflags & SF_GAMEUI_JUMP_DEACTIVATES ))) { Deactivate( pPlayer ); return; } if ( pPlayer->m_afButtonPressed & IN_MOVERIGHT ) { m_pressedMoveRight.FireOutput( pPlayer, this, 0 ); } if ( pPlayer->m_afButtonPressed & IN_MOVELEFT ) { m_pressedMoveLeft.FireOutput( pPlayer, this, 0 ); } if ( pPlayer->m_afButtonPressed & IN_FORWARD ) { m_pressedForward.FireOutput( pPlayer, this, 0 ); } if ( pPlayer->m_afButtonPressed & IN_BACK ) { m_pressedBack.FireOutput( pPlayer, this, 0 ); } if ( pPlayer->m_afButtonPressed & IN_ATTACK ) { m_pressedAttack.FireOutput( pPlayer, this, 0 ); } if ( pPlayer->m_afButtonPressed & IN_ATTACK2 ) { m_pressedAttack2.FireOutput( pPlayer, this, 0 ); } float x = 0, y = 0, attack = 0, attack2 = 0; if ( pPlayer->m_nButtons & IN_MOVERIGHT ) { x = 1; } else if ( pPlayer->m_nButtons & IN_MOVELEFT ) { x = -1; } if ( pPlayer->m_nButtons & IN_FORWARD ) { y = 1; } else if ( pPlayer->m_nButtons & IN_BACK ) { y = -1; } if ( pPlayer->m_nButtons & IN_ATTACK ) { attack = 1; } if ( pPlayer->m_nButtons & IN_ATTACK2 ) { attack2 = 1; } // // Fire the analog outputs if they changed. // if ( m_bForceUpdate || ( m_xaxis.Get() != x ) ) { m_xaxis.Set( x, pPlayer, this ); } if ( m_bForceUpdate || ( m_yaxis.Get() != y ) ) { m_yaxis.Set( y, pPlayer, this ); } if ( m_bForceUpdate || ( m_attackaxis.Get() != attack ) ) { m_attackaxis.Set( attack, pPlayer, this ); } if ( m_bForceUpdate || ( m_attack2axis.Get() != attack2 ) ) { m_attack2axis.Set( attack2, pPlayer, this ); } m_bForceUpdate = false; }
// Invoked when injured by something // NOTE: We dont want to directly call Attack() here, or the bots will have super-human reaction times when injured BOOL CCSBot::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) { CBaseEntity *pAttacker = GetClassPtr<CCSEntity>((CBaseEntity *)pevInflictor); // if we were attacked by a teammate, rebuke if (pAttacker->IsPlayer()) { CBasePlayer *pPlayer = static_cast<CBasePlayer *>(pAttacker); if (BotRelationship(pPlayer) == BOT_TEAMMATE && !pPlayer->IsBot()) { GetChatter()->FriendlyFire(); } if (IsEnemy(pPlayer)) { // Track previous attacker so we don't try to panic multiple times for a shotgun blast CBasePlayer *lastAttacker = m_attacker; float lastAttackedTimestamp = m_attackedTimestamp; // keep track of our last attacker m_attacker = pPlayer; m_attackedTimestamp = gpGlobals->time; // no longer safe AdjustSafeTime(); if (!IsSurprised() && (m_attacker != lastAttacker || m_attackedTimestamp != lastAttackedTimestamp)) { // being hurt by an enemy we can't see causes panic if (!IsVisible(pPlayer, CHECK_FOV)) { bool bPanic = false; // if not attacking anything, look around to try to find attacker if (!IsAttacking()) { bPanic = true; } else { // we are attacking if (!IsEnemyVisible()) { // can't see our current enemy, panic to acquire new attacker bPanic = true; } } if (!bPanic) { float invSkill = 1.0f - GetProfile()->GetSkill(); float panicChance = invSkill * invSkill * 50.0f; if (panicChance > RANDOM_FLOAT(0, 100)) { bPanic = true; } } if (bPanic) { // can't see our current enemy, panic to acquire new attacker Panic(m_attacker); } } } } } // extend return CBasePlayer::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); }
void CLagCompensationManager::FinishLagCompensation( CBasePlayer *player ) { VPROF_BUDGET_FLAGS( "FinishLagCompensation", VPROF_BUDGETGROUP_OTHER_NETWORKING, BUDGETFLAG_CLIENT|BUDGETFLAG_SERVER ); m_pCurrentPlayer = NULL; if ( !m_bNeedToRestore ) return; // no player was changed at all // Iterate all active players for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { int pl_index = i - 1; if ( !m_RestorePlayer.Get( pl_index ) ) { // player wasn't changed by lag compensation continue; } CBasePlayer *pPlayer = UTIL_PlayerByIndex( i ); if ( !pPlayer ) { continue; } LagRecord *restore = &m_RestoreData[ pl_index ]; LagRecord *change = &m_ChangeData[ pl_index ]; bool restoreSimulationTime = false; if ( restore->m_fFlags & LC_SIZE_CHANGED ) { restoreSimulationTime = true; // see if simulation made any changes, if no, then do the restore, otherwise, // leave new values in if ( pPlayer->CollisionProp()->OBBMinsPreScaled() == change->m_vecMinsPreScaled && pPlayer->CollisionProp()->OBBMaxsPreScaled() == change->m_vecMaxsPreScaled ) { // Restore it pPlayer->SetSize( restore->m_vecMinsPreScaled, restore->m_vecMaxsPreScaled ); } #ifdef STAGING_ONLY else { Warning( "Should we really not restore the size?\n" ); } #endif } if ( restore->m_fFlags & LC_ANGLES_CHANGED ) { restoreSimulationTime = true; if ( pPlayer->GetLocalAngles() == change->m_vecAngles ) { pPlayer->SetLocalAngles( restore->m_vecAngles ); } } if ( restore->m_fFlags & LC_ORIGIN_CHANGED ) { restoreSimulationTime = true; // Okay, let's see if we can do something reasonable with the change Vector delta = pPlayer->GetLocalOrigin() - change->m_vecOrigin; // If it moved really far, just leave the player in the new spot!!! if ( delta.Length2DSqr() < m_flTeleportDistanceSqr ) { RestorePlayerTo( pPlayer, restore->m_vecOrigin + delta ); } } if( restore->m_fFlags & LC_ANIMATION_CHANGED ) { restoreSimulationTime = true; pPlayer->SetSequence(restore->m_masterSequence); pPlayer->SetCycle(restore->m_masterCycle); int layerCount = pPlayer->GetNumAnimOverlays(); for( int layerIndex = 0; layerIndex < layerCount; ++layerIndex ) { CAnimationLayer *currentLayer = pPlayer->GetAnimOverlay(layerIndex); if( currentLayer ) { currentLayer->m_flCycle = restore->m_layerRecords[layerIndex].m_cycle; currentLayer->m_nOrder = restore->m_layerRecords[layerIndex].m_order; currentLayer->m_nSequence = restore->m_layerRecords[layerIndex].m_sequence; currentLayer->m_flWeight = restore->m_layerRecords[layerIndex].m_weight; } } } if ( restoreSimulationTime ) { pPlayer->SetSimulationTime( restore->m_flSimulationTime ); #ifdef SecobMod__Enable_Fixed_Multiplayer_AI } } // also iterate all monsters CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs(); int nAIs = g_AI_Manager.NumAIs(); for ( int i = 0; i < nAIs; i++ ) { CAI_BaseNPC *pNPC = ppAIs[i]; if ( !m_RestoreEntity.Get( i ) ) { // entity wasn't changed by lag compensation continue; } LagRecord *restore = &m_EntityRestoreData[ i ]; LagRecord *change = &m_EntityChangeData[ i ]; bool restoreSimulationTime = false; if ( restore->m_fFlags & LC_SIZE_CHANGED ) { restoreSimulationTime = true; // see if simulation made any changes, if no, then do the restore, otherwise, // leave new values in if ( pNPC->WorldAlignMins() == change->m_vecMinsPreScaled && pNPC->WorldAlignMaxs() == change->m_vecMaxsPreScaled ) { // Restore it pNPC->SetSize( restore->m_vecMinsPreScaled, restore->m_vecMaxsPreScaled ); } } if ( restore->m_fFlags & LC_ANGLES_CHANGED ) { restoreSimulationTime = true; if ( pNPC->GetLocalAngles() == change->m_vecAngles ) { pNPC->SetLocalAngles( restore->m_vecAngles ); } } if ( restore->m_fFlags & LC_ORIGIN_CHANGED ) { restoreSimulationTime = true; // Okay, let's see if we can do something reasonable with the change Vector delta = pNPC->GetLocalOrigin() - change->m_vecOrigin; // If it moved really far, just leave the player in the new spot!!! if ( delta.LengthSqr() < LAG_COMPENSATION_EPS_SQR ) { RestoreEntityTo( pNPC, restore->m_vecOrigin + delta ); } } if( restore->m_fFlags & LC_ANIMATION_CHANGED ) { restoreSimulationTime = true; pNPC->SetSequence(restore->m_masterSequence); pNPC->SetCycle(restore->m_masterCycle); int layerCount = pNPC->GetNumAnimOverlays(); for( int layerIndex = 0; layerIndex < layerCount; ++layerIndex ) { CAnimationLayer *currentLayer = pNPC->GetAnimOverlay(layerIndex); if( currentLayer ) { currentLayer->m_flCycle = restore->m_layerRecords[layerIndex].m_cycle; currentLayer->m_nOrder = restore->m_layerRecords[layerIndex].m_order; currentLayer->m_nSequence = restore->m_layerRecords[layerIndex].m_sequence; currentLayer->m_flWeight = restore->m_layerRecords[layerIndex].m_weight; } } } if ( restoreSimulationTime ) { pNPC->SetSimulationTime( restore->m_flSimulationTime ); #endif //SecobMod__Enable_Fixed_Multiplayer_AI } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHL2MPClientScoreBoardDialog::UpdatePlayerInfo() { m_iSectionId = 0; // 0'th row is a header int selectedRow = -1; int i; CBasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( !pPlayer || !g_PR ) return; // walk all the players and make sure they're in the scoreboard for ( i = 1; i <= gpGlobals->maxClients; i++ ) { bool shouldShow = g_PR->IsConnected( i ); if ( shouldShow ) { // add the player to the list KeyValues *playerData = new KeyValues("data"); GetPlayerScoreInfo( i, playerData ); int itemID = FindItemIDForPlayerIndex( i ); int sectionID = GetSectionFromTeamNumber( g_PR->GetTeam( i ) ); if (itemID == -1) { // add a new row itemID = m_pPlayerList->AddItem( sectionID, playerData ); } else { // modify the current row m_pPlayerList->ModifyItem( itemID, sectionID, playerData ); } if ( i == pPlayer->entindex() ) { selectedRow = itemID; // this is the local player, hilight this row } // set the row color based on the players team m_pPlayerList->SetItemFgColor( itemID, g_PR->GetTeamColor( g_PR->GetTeam( i ) ) ); playerData->deleteThis(); } else { // remove the player int itemID = FindItemIDForPlayerIndex( i ); if (itemID != -1) { m_pPlayerList->RemoveItem(itemID); } } } if ( selectedRow != -1 ) { m_pPlayerList->SetSelectedItem(selectedRow); } }
//----------------------------------------------------------------------------- // Purpose: Called once per frame after all entities have had a chance to think //----------------------------------------------------------------------------- void CLagCompensationManager::FrameUpdatePostEntityThink() { #ifdef SecobMod__Enable_Fixed_Multiplayer_AI if ( m_bNeedsAIUpdate ) UpdateAIIndexes(); // only bother if we haven't had one yet else // setting this true here ensures that the update happens at the start of the next frame m_bNeedsAIUpdate = true; #endif //SecobMod__Enable_Fixed_Multiplayer_AI if ( (gpGlobals->maxClients <= 1) || !sv_unlag.GetBool() ) { ClearHistory(); return; } m_flTeleportDistanceSqr = sv_lagcompensation_teleport_dist.GetFloat() * sv_lagcompensation_teleport_dist.GetFloat(); VPROF_BUDGET( "FrameUpdatePostEntityThink", "CLagCompensationManager" ); // remove all records before that time: int flDeadtime = gpGlobals->curtime - sv_maxunlag.GetFloat(); // Iterate all active players for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBasePlayer *pPlayer = UTIL_PlayerByIndex( i ); CUtlFixedLinkedList< LagRecord > *track = &m_PlayerTrack[i-1]; if ( !pPlayer ) { if ( track->Count() > 0 ) { track->RemoveAll(); } continue; } Assert( track->Count() < 1000 ); // insanity check // remove tail records that are too old int tailIndex = track->Tail(); while ( track->IsValidIndex( tailIndex ) ) { LagRecord &tail = track->Element( tailIndex ); // if tail is within limits, stop if ( tail.m_flSimulationTime >= flDeadtime ) break; // remove tail, get new tail track->Remove( tailIndex ); tailIndex = track->Tail(); } // check if head has same simulation time if ( track->Count() > 0 ) { LagRecord &head = track->Element( track->Head() ); // check if player changed simulation time since last time updated if ( head.m_flSimulationTime >= pPlayer->GetSimulationTime() ) continue; // don't add new entry for same or older time } // add new record to player track LagRecord &record = track->Element( track->AddToHead() ); record.m_fFlags = 0; if ( pPlayer->IsAlive() ) { record.m_fFlags |= LC_ALIVE; } record.m_flSimulationTime = pPlayer->GetSimulationTime(); record.m_vecAngles = pPlayer->GetLocalAngles(); record.m_vecOrigin = pPlayer->GetLocalOrigin(); record.m_vecMinsPreScaled = pPlayer->CollisionProp()->OBBMinsPreScaled(); record.m_vecMaxsPreScaled = pPlayer->CollisionProp()->OBBMaxsPreScaled(); int layerCount = pPlayer->GetNumAnimOverlays(); for( int layerIndex = 0; layerIndex < layerCount; ++layerIndex ) { CAnimationLayer *currentLayer = pPlayer->GetAnimOverlay(layerIndex); if( currentLayer ) { record.m_layerRecords[layerIndex].m_cycle = currentLayer->m_flCycle; record.m_layerRecords[layerIndex].m_order = currentLayer->m_nOrder; record.m_layerRecords[layerIndex].m_sequence = currentLayer->m_nSequence; record.m_layerRecords[layerIndex].m_weight = currentLayer->m_flWeight; } } record.m_masterSequence = pPlayer->GetSequence(); record.m_masterCycle = pPlayer->GetCycle(); } #ifdef SecobMod__Enable_Fixed_Multiplayer_AI // Iterate all active NPCs CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs(); int nAIs = g_AI_Manager.NumAIs(); for ( int i = 0; i < nAIs; i++ ) { CAI_BaseNPC *pNPC = ppAIs[i]; CUtlFixedLinkedList< LagRecord > *track = &m_EntityTrack[i]; if ( !pNPC ) { track->RemoveAll(); continue; } Assert( track->Count() < 1000 ); // insanity check // remove tail records that are too old int tailIndex = track->Tail(); while ( track->IsValidIndex( tailIndex ) ) { LagRecord &tail = track->Element( tailIndex ); // if tail is within limits, stop if ( tail.m_flSimulationTime >= flDeadtime ) break; // remove tail, get new tail track->Remove( tailIndex ); tailIndex = track->Tail(); } // check if head has same simulation time if ( track->Count() > 0 ) { LagRecord &head = track->Element( track->Head() ); // check if entity changed simulation time since last time updated if ( &head && head.m_flSimulationTime >= pNPC->GetSimulationTime() ) continue; // don't add new entry for same or older time // Simulation Time is set when an entity moves or rotates ... // this error occurs when whatever entity it is that breaks it moves or rotates then, presumably? } // add new record to track LagRecord &record = track->Element( track->AddToHead() ); record.m_fFlags = 0; if ( pNPC->IsAlive() ) { record.m_fFlags |= LC_ALIVE; } record.m_flSimulationTime = pNPC->GetSimulationTime(); record.m_vecAngles = pNPC->GetLocalAngles(); record.m_vecOrigin = pNPC->GetLocalOrigin(); record.m_vecMaxsPreScaled = pNPC->WorldAlignMaxs(); record.m_vecMinsPreScaled = pNPC->WorldAlignMins(); int layerCount = pNPC->GetNumAnimOverlays(); for( int layerIndex = 0; layerIndex < layerCount; ++layerIndex ) { CAnimationLayer *currentLayer = pNPC->GetAnimOverlay(layerIndex); if( currentLayer ) { record.m_layerRecords[layerIndex].m_cycle = currentLayer->m_flCycle; record.m_layerRecords[layerIndex].m_order = currentLayer->m_nOrder; record.m_layerRecords[layerIndex].m_sequence = currentLayer->m_nSequence; record.m_layerRecords[layerIndex].m_weight = currentLayer->m_flWeight; } } record.m_masterSequence = pNPC->GetSequence(); record.m_masterCycle = pNPC->GetCycle(); } #endif //SecobMod__Enable_Fixed_Multiplayer_AI //Clear the current player. m_pCurrentPlayer = NULL; }
//----------------------------------------------------------------------------- // Purpose: Check the weapon LOS for an owner at an arbitrary position // If bSetConditions is true, LOS related conditions will also be set //----------------------------------------------------------------------------- bool CBaseCombatWeapon::WeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions ) { // -------------------- // Check for occlusion // -------------------- CAI_BaseNPC* npcOwner = m_hOwner.Get()->MyNPCPointer(); // Find its relative shoot position Vector vecRelativeShootPosition; VectorSubtract( npcOwner->Weapon_ShootPosition(), npcOwner->GetAbsOrigin(), vecRelativeShootPosition ); Vector barrelPos = ownerPos + vecRelativeShootPosition; // Use the custom LOS trace filter CWeaponLOSFilter traceFilter( m_hOwner.Get(), npcOwner->GetEnemy(), COLLISION_GROUP_BREAKABLE_GLASS ); trace_t tr; UTIL_TraceLine( barrelPos, targetPos, MASK_SHOT, &traceFilter, &tr ); // See if we completed the trace without interruption if ( tr.fraction == 1.0 ) { if ( ai_debug_shoot_positions.GetBool() ) { NDebugOverlay::Line( barrelPos, targetPos, 0, 255, 0, false, 1.0 ); } return true; } CBaseEntity *pHitEnt = tr.m_pEnt; CBasePlayer *pEnemyPlayer = ToBasePlayer( npcOwner->GetEnemy() ); // is player in a vehicle? if so, verify vehicle is target and return if so (so npc shoots at vehicle) if ( pEnemyPlayer && pEnemyPlayer->IsInAVehicle() ) { // Ok, player in vehicle, check if vehicle is target we're looking at, fire if it is // Also, check to see if the owner of the entity is the vehicle, in which case it's valid too. // This catches vehicles that use bone followers. CBaseEntity *pVehicle = pEnemyPlayer->GetVehicle()->GetVehicleEnt(); if ( pHitEnt == pVehicle || pHitEnt->GetOwnerEntity() == pVehicle ) return true; } // Hitting our enemy is a success case if ( pHitEnt == npcOwner->GetEnemy() ) { if ( ai_debug_shoot_positions.GetBool() ) { NDebugOverlay::Line( barrelPos, targetPos, 0, 255, 0, false, 1.0 ); } return true; } // If a vehicle is blocking the view, grab its driver and use that as the combat character CBaseCombatCharacter *pBCC; IServerVehicle *pVehicle = pHitEnt->GetServerVehicle(); if ( pVehicle ) { pBCC = pVehicle->GetPassenger( ); } else { pBCC = ToBaseCombatCharacter( pHitEnt ); } if ( pBCC ) { if ( npcOwner->IRelationType( pBCC ) == D_HT ) return true; if ( bSetConditions ) { npcOwner->SetCondition( COND_WEAPON_BLOCKED_BY_FRIEND ); } } else if ( bSetConditions ) { npcOwner->SetCondition( COND_WEAPON_SIGHT_OCCLUDED ); npcOwner->SetEnemyOccluder( pHitEnt ); if( ai_debug_shoot_positions.GetBool() ) { NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 0, 0, false, 1.0 ); } } return false; }
void ItemPostFrame() { CBasePlayer *pPlayer = dynamic_cast<CBasePlayer*>(GetOwner()); if( !pPlayer ) return; if ( pPlayer->m_afButtonReleased & IN_ATTACK ) { CancelPrimaryAttack(); } trace_t tr; Vector eyePos, eyeForward; pPlayer->EyePositionAndVectors( &eyePos, &eyeForward, NULL, NULL ); CTraceFilterSkipTwoEntities traceFilter( pPlayer, this, COLLISION_GROUP_NONE ); UTIL_TraceLine( eyePos, eyePos + eyeForward * MAX_TRACE_LENGTH, MASK_SHOT, &traceFilter, &tr ); if( !m_hBeam ) { if ( gpGlobals->curtime >= m_flBeamTime ) { #ifndef CLIENT_DLL m_hBeam = CREATE_ENTITY( CBeam, "env_beam" ); if ( m_hBeam ) { m_hBeam->BeamInit( "sprites/lgtning.vmt", 6.5f ); m_hBeam->PointEntInit( tr.endpos, pPlayer->GetViewModel(0) ); m_hBeam->SetScrollRate( -10.f ); m_hBeam->SetNoise( 1 ); m_hBeam->SetEndAttachment( LookupAttachment("muzzle") ); m_hBeam->Spawn(); } #endif SendWeaponAnim( ACT_VM_PRIMARYATTACK ); } if ( m_flBeamTime == FLT_MAX ) BaseClass::ItemPostFrame(); } else { if ( gpGlobals->curtime >= m_flDamageTime ) { GetOwner()->RemoveAmmo( 1, GetPrimaryAmmoType() ); #ifndef CLIENT_DLL if( tr.fraction != 1.0 && tr.m_pEnt ) { ClearMultiDamage(); Vector dir = tr.endpos - m_hBeam->GetAbsEndPos(); VectorNormalize( dir ); const float flDamage = BEAM_DAMAGE; CTakeDamageInfo info( m_hBeam, GetOwner(), flDamage, DMG_SHOCK ); CalculateMeleeDamageForce( &info, dir, tr.endpos ); tr.m_pEnt->DispatchTraceAttack( info, dir, &tr ); ApplyMultiDamage(); RadiusDamage( CTakeDamageInfo( m_hBeam, GetOwner(), flDamage * 0.25f, DMG_SHOCK ), tr.endpos, 16.0f, CLASS_NONE, NULL ); } #endif if ( !HasPrimaryAmmo() ) CancelPrimaryAttack(); m_flDamageTime = gpGlobals->curtime + DAMAGE_TICK; } m_hBeam->SetStartPos( tr.endpos ); } }