//----------------------------------------------------------------------------- // Deal with dynamic lighting //----------------------------------------------------------------------------- void C_WeaponCombat_ChargeablePlasma::ClientThink( ) { BaseClass::ClientThink(); C_BaseTFPlayer *pPlayer = (C_BaseTFPlayer *)GetOwner(); if ( !pPlayer || (pPlayer->GetHealth() <= 0)) { SetNextClientThink( CLIENT_THINK_NEVER ); return; } if (!m_bCharging) return; // Determine the ball size... m_flPower = (gpGlobals->curtime - m_flChargeStartTime) / BALL_GROW_TIME; m_flPower = clamp( m_flPower, 0, 1 ); // FIXME: dl->origin should be based on the attachment point dlight_t *dl = effects->CL_AllocDlight( entindex() ); dl->origin = GetRenderOrigin(); if (GetTeamNumber() == 1) { dl->color.r = 40; dl->color.g = 60; dl->color.b = 250; } else { dl->color.r = 250; dl->color.g = 60; dl->color.b = 40; } dl->color.exponent = 5; dl->radius = 20 * m_flPower + 10; dl->die = gpGlobals->curtime + 0.01; }
//----------------------------------------------------------------------------- // Purpose: Draw function for the element //----------------------------------------------------------------------------- void CTargetID::Paint() { // No id if still choosing class if ( C_BaseTFPlayer::GetLocalPlayer()->GetClass() == TFCLASS_UNDECIDED ) return; // Get our target's ent index int iEntIndex = C_BaseTFPlayer::GetLocalPlayer()->GetIDTarget(); // Didn't find one? if ( !iEntIndex ) { // Check to see if we should clear our ID if ( m_flLastChangeTime && (gpGlobals->curtime > (m_flLastChangeTime + 0.5)) ) { m_flLastChangeTime = 0; m_sIDString[0] = 0; m_iLastEntIndex = 0; } else { // Keep re-using the old one iEntIndex = m_iLastEntIndex; } } else { m_flLastChangeTime = gpGlobals->curtime; } // Is this an entindex sent by the server? if ( iEntIndex ) { C_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>(cl_entitylist->GetEnt( iEntIndex )); C_BaseTFPlayer *pLocalPlayer = C_BaseTFPlayer::GetLocalPlayer(); // Some entities we always want to check, cause the text may change // even while we're looking at it // Is it a player? if ( IsPlayerIndex( iEntIndex ) ) { if ( pPlayer->InSameTeam(pLocalPlayer) ) { // Check distance to other player, and if the player is on the same team float flDistSq = pPlayer->GetRenderOrigin().DistToSqr( pLocalPlayer->GetRenderOrigin() ); if ( flDistSq < PLAYER_HINT_DISTANCE_SQ ) { Q_snprintf( m_sIDString, sizeof(m_sIDString), "%s\nHealth: %.0f percent\nUse to donate resources", pPlayer->GetPlayerName(), ((float)pPlayer->GetHealth() / (float)pPlayer->GetMaxHealth() ) * 100 ); } else { Q_snprintf( m_sIDString, sizeof(m_sIDString), "%s\nHealth: %.0f percent", pPlayer->GetPlayerName(), ((float)pPlayer->GetHealth() / (float)pPlayer->GetMaxHealth() ) * 100 ); } } else if (( pPlayer->GetHealth() == 0) && (pLocalPlayer->GetClass() == TFCLASS_INFILTRATOR) ) { Q_snprintf( m_sIDString, sizeof(m_sIDString), "%s\nUse to disguise as this player", pPlayer->GetPlayerName() ); } else { m_sIDString[0] = 0; m_iLastEntIndex = 0; } } else { // Objects C_BaseEntity *pEnt = cl_entitylist->GetEnt( iEntIndex ); if ( !pEnt || !pEnt->InSameTeam(pLocalPlayer) ) { // This can happen because the object was destroyed m_sIDString[0] = 0; m_iLastEntIndex = 0; } else { // Don't check validity if it's sent by the server Q_strncpy( m_sIDString, pEnt->GetIDString(), sizeof(m_sIDString) ); m_iLastEntIndex = iEntIndex; } } } // Draw our ID string if ( m_sIDString[0] ) { int width, height; int ypos = YRES(300); // Messagechars can't handle multiple line strings, so parse out the \n's and give it one line at a time char *ch = m_sIDString; while ( *ch ) { // Find the next newline char *next_line; for ( next_line = ch; *next_line != '\n' && *next_line != 0; next_line++ ) { } // Stomp the newline char *top = next_line; if ( *top == '\n' ) { *top = 0; } else { top = NULL; } // Draw the line messagechars->GetStringLength( m_hFont, &width, &height, ch ); messagechars->DrawString( m_hFont, (ScreenWidth() - width) / 2, ypos, 255, 255, 245, 255, ch, IMessageChars::MESSAGESTRINGID_NONE ); ypos += height; // Restore the newline if ( top ) { *top = '\n'; } // Move to the next line ch = next_line; if ( *ch == '\n' ) { ch++; } } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void C_WeaponMortar::Redraw() { BaseClass::Redraw(); // If the player's dead, abort C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); if ( pPlayer == NULL ) return; if ( pPlayer->GetHealth() < 1 ) { m_iFiringState = MORTAR_IDLE; m_bCarried = true; return; } // If it's reloading, tell the player if ( m_bMortarReloading ) { int width, height; messagechars->GetStringLength( m_hFontText, &width, &height, "Mortar is reloading..." ); messagechars->DrawString( m_hFontText, (ScreenWidth() - width) / 2, YRES(350), 192, 192, 192, 255, "Mortar is reloading...", IMessageChars::MESSAGESTRINGID_NONE ); return; } // Handle power charging switch( m_iFiringState ) { case MORTAR_IDLE: m_pPowerBar->m_flPower = 0; break; case MORTAR_CHARGING_POWER: m_pPowerBar->m_flPower = min( m_pPowerBar->m_flPower + ( (1.0 / MORTAR_CHARGE_POWER_RATE) * gpGlobals->curtimeDelta), 1.0f); m_pPowerBar->m_flFiringPower = 0; m_pPowerBar->m_flFiringAccuracy = 0; if ( m_pPowerBar->m_flPower >= 1.0 ) { // Hit Max, start going down m_pPowerBar->m_flFiringPower = m_pPowerBar->m_flPower; m_iFiringState = MORTAR_CHARGING_ACCURACY; m_flNextClick = gpGlobals->curtime + 0.25; } break; case MORTAR_CHARGING_ACCURACY: // Calculate accuracy speed m_flAccuracySpeed = (1.0 / MORTAR_CHARGE_ACCURACY_RATE); if ( m_pPowerBar->m_flFiringPower > 0.5 ) { // Shots over halfway suffer an increased speed to the accuracy power, making accurate shots harder float flAdjustedPower = (m_pPowerBar->m_flFiringPower - 0.5) * 3.0; m_flAccuracySpeed += (m_pPowerBar->m_flFiringPower * flAdjustedPower); } m_pPowerBar->m_flPower = max( m_pPowerBar->m_flPower - ( m_flAccuracySpeed * gpGlobals->curtimeDelta), -0.25f); if ( m_pPowerBar->m_flPower <= -0.25 ) { // Hit Min, fire mortar m_pPowerBar->m_flFiringAccuracy = m_pPowerBar->m_flPower; m_iFiringState = MORTAR_IDLE; FireMortar(); m_flNextClick = gpGlobals->curtime + 0.25; } break; default: break; } // Draw the rotate icon if the player's rotating the mortar if ( m_bRotating ) { vgui::Panel *pParent = GetClientModeNormal()->GetViewport(); int parentWidth, parentHeight; pParent->GetSize(parentWidth, parentHeight); int iWidth = 64; int iHeight = 64; int iX = (parentWidth - iWidth) / 2; int iY = (parentHeight - 216); IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pRotateIcon ); CMeshBuilder meshBuilder; meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); meshBuilder.Color3f( 1.0, 1.0, 1.0 ); meshBuilder.TexCoord2f( 0,0,0 ); meshBuilder.Position3f( iX,iY,0 ); meshBuilder.AdvanceVertex(); meshBuilder.Color3f( 1.0, 1.0, 1.0 ); meshBuilder.TexCoord2f( 0,1,0 ); meshBuilder.Position3f( iX+iWidth, iY, 0 ); meshBuilder.AdvanceVertex(); meshBuilder.Color3f( 1.0, 1.0, 1.0 ); meshBuilder.TexCoord2f( 0,1,1 ); meshBuilder.Position3f( iX+iWidth, iY+iHeight, 0 ); meshBuilder.AdvanceVertex(); meshBuilder.Color3f( 1.0, 1.0, 1.0 ); meshBuilder.TexCoord2f( 0,0,1 ); meshBuilder.Position3f( iX, iY+iHeight, 0 ); meshBuilder.AdvanceVertex(); meshBuilder.End(); pMesh->Draw(); } // Update the ground line if it's moved if ( !m_bCarried && (m_flPrevMortarYaw != m_flMortarYaw ) && gpGlobals->curtime > m_flLastGroundlineUpdateTime + g_CVMortarGroundLineUpdateInterval.GetFloat() ) { // Create the Ground line start & end points Vector vecForward; AngleVectors( QAngle( 0, m_flMortarYaw, 0 ), &vecForward ); Vector vecStart = m_vecMortarOrigin + (vecForward * MORTAR_RANGE_MIN); float flRange = MORTAR_RANGE_MAX_INITIAL; if ( pPlayer->HasNamedTechnology( "mortar_range" ) ) flRange = MORTAR_RANGE_MAX_UPGRADED; Vector vecEnd = m_vecMortarOrigin + (vecForward * flRange); m_pDarkLine->SetParameters( m_vecMortarOrigin, vecStart, Vector( 0.1,0.1,0.1 ), Vector( 0.1,0.1,0.1 ), 0.5, 22 ); m_pGroundLine->SetParameters( vecStart, vecEnd, Vector(0,1,0), Vector(1,0,0), 0.5, 22 ); m_flPrevMortarYaw = m_flMortarYaw; m_flLastGroundlineUpdateTime = gpGlobals->curtime; } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void C_WeaponMortar::HandleInput( void ) { // If it's being carried, ignore input if ( m_bCarried ) return; // If the player's dead, ignore input C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer(); if ( pPlayer == NULL ) return; if ( pPlayer->GetHealth() < 1 ) return; // Ignore input if it's reloading if ( m_bMortarReloading ) return; // Secondary fire rotates the mortar if ( gHUD.m_iKeyBits & IN_ATTACK2 ) { if ( pPlayer->HasPowerup(POWERUP_EMP) ) { CLocalPlayerFilter filter; EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "WeaponMortar.EMPed" ); return; } m_bRotating = true; gHUD.m_iKeyBits &= ~IN_ATTACK2; // Prevent firing while rotating m_pPowerBar->SetParent( (vgui::Panel *)NULL ); return; } else { if ( m_bRotating ) { // Bring up the firing bar again vgui::Panel *pParent = GetClientModeNormal()->GetViewport(); m_pPowerBar->SetParent(pParent); m_bRotating = false; } } // Primary fire launches mortars if (gHUD.m_iKeyBits & IN_ATTACK) { if ( pPlayer->HasPowerup(POWERUP_EMP) ) { CLocalPlayerFilter filter; EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "WeaponMortar.EMPed" ); return; } if ( m_flNextClick <= gpGlobals->curtime ) { // Play click animation // SendWeaponAnim( ACT_SLAM_DETONATOR_DETONATE ); // Switch states switch( m_iFiringState ) { case MORTAR_IDLE: m_iFiringState = MORTAR_CHARGING_POWER; break; case MORTAR_CHARGING_POWER: m_pPowerBar->m_flFiringPower = m_pPowerBar->m_flPower; m_iFiringState = MORTAR_CHARGING_ACCURACY; break; case MORTAR_CHARGING_ACCURACY: m_pPowerBar->m_flFiringAccuracy = m_pPowerBar->m_flPower; m_iFiringState = MORTAR_IDLE; FireMortar(); break; default: break; } input->ClearInputButton( IN_ATTACK ); gHUD.m_iKeyBits &= ~IN_ATTACK; m_flNextClick = gpGlobals->curtime + 0.05; } } }