/*** * * Copyright (c) 1996-2001, Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. * All Rights Reserved. * * Use, distribution, and modification of this source code and/or resulting * object code is restricted to non-commercial enhancements to products from * Valve LLC. All other use, distribution, or modification is prohibited * without written permission from Valve LLC. * ****/ // // death notice // #include "hud.h" #include "cl_util.h" #include "parsemsg.h" #include #include #include "tw_vgui.h" #include "vgui_TheWastesViewport.h" DECLARE_MESSAGE( m_DeathNotice, DeathMsg ); struct DeathNoticeItem { char szKiller[MAX_PLAYER_NAME_LENGTH*2]; char szVictim[MAX_PLAYER_NAME_LENGTH*2]; char szDeathMessage[128]; int iId; // the index number of the associated sprite int iSuicide; int iTeamKill; int iNonPlayerKill; int iSpecialDeath; float flDisplayTime; float *KillerColor; float *VictimColor; }; #define MAX_DEATHNOTICES 4 static int DEATHNOTICE_DISPLAY_TIME = 6; #define DEATHNOTICE_TOP ScreenHeight - 72 DeathNoticeItem rgDeathNoticeList[ MAX_DEATHNOTICES + 1 ]; float g_ColorBlue[3] = { 0.6, 0.8, 1.0 }; float g_ColorRed[3] = { 1.0, 0.25, 0.25 }; float g_ColorGreen[3] = { 0.6, 1.0, 0.6 }; float g_ColorYellow[3] = { 1.0, 0.7, 0.0 }; float *GetClientColor( int clientIndex ) { switch ( g_PlayerExtraInfo[clientIndex].teamnumber ) { case 1: return g_ColorBlue; case 2: return g_ColorRed; case 3: return g_ColorYellow; case 4: return g_ColorGreen; } return NULL; } int CHudDeathNotice :: Init( void ) { gHUD.AddHudElem( this ); HOOK_MESSAGE( DeathMsg ); CVAR_CREATE( "hud_deathnotice_time", "6", 0 ); return 1; } void CHudDeathNotice :: InitHUDData( void ) { memset( rgDeathNoticeList, 0, sizeof(rgDeathNoticeList) ); } int CHudDeathNotice :: VidInit( void ) { m_HUD_d_skull = gHUD.GetSpriteIndex( "d_skull" ); m_HUD_d_headshot = gHUD.GetSpriteIndex( "d_headshot" ); m_HUD_d_bleeding = gHUD.GetSpriteIndex( "d_bleed" ); return 1; } int CHudDeathNotice :: Draw( float flTime ) { int x, y, r, g, b; int text_y; int deathcount = 0; // How many death messages are there. for( int i = 0;i < MAX_DEATHNOTICES; i++) { if(rgDeathNoticeList[i].iId == 0) break; deathcount++; } for ( i = 0; i < MAX_DEATHNOTICES; i++ ) { if ( rgDeathNoticeList[i].iId == 0 ) break; // we've gone through them all if ( rgDeathNoticeList[i].flDisplayTime < flTime ) { // display time has expired // remove the current item from the list memmove( &rgDeathNoticeList[i], &rgDeathNoticeList[i+1], sizeof(DeathNoticeItem) * (MAX_DEATHNOTICES - i) ); i--; // continue on the next item; stop the counter getting incremented continue; } rgDeathNoticeList[i].flDisplayTime = Q_min( rgDeathNoticeList[i].flDisplayTime, gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME ); // Only draw if the viewport will let me if ( gViewPort && gViewPort->AllowedToPrintText() ) { // Get the initial offset. int offset = (20 * deathcount ); // Draw the death notice y = DEATHNOTICE_TOP + (20 * i) - offset; //!!! int id,special_id = 0; switch(rgDeathNoticeList[i].iSpecialDeath) { default: case 0: break; case 1: special_id = m_HUD_d_headshot; break; case 2: special_id = m_HUD_d_bleeding; break; } id = (rgDeathNoticeList[i].iId == -1) ? m_HUD_d_skull : rgDeathNoticeList[i].iId; int id_length; if(rgDeathNoticeList[i].iSpecialDeath == 2 && !rgDeathNoticeList[i].iSuicide) id_length = 0; else id_length = (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); int special_id_length = (rgDeathNoticeList[i].iSpecialDeath && !rgDeathNoticeList[i].iSuicide) ? (gHUD.GetSpriteRect(special_id).right - gHUD.GetSpriteRect(special_id).left) : 0; // Put in center x = (ScreenWidth/2) - (ConsoleStringLen(rgDeathNoticeList[i].szVictim) - id_length - special_id_length)/2; if ( !rgDeathNoticeList[i].iSuicide ) { x -= (5 + ConsoleStringLen( rgDeathNoticeList[i].szKiller ) ); // Draw killers name if ( rgDeathNoticeList[i].KillerColor ) gEngfuncs.pfnDrawSetTextColor( rgDeathNoticeList[i].KillerColor[0], rgDeathNoticeList[i].KillerColor[1], rgDeathNoticeList[i].KillerColor[2] ); x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller ); } // r = 255; g = 80; b = 0; r = g = b = 255; // WHITE - Gage if ( rgDeathNoticeList[i].iTeamKill ) { r = 10; g = 240; b = 10; // display it in sickly green } // Draw death weapon if needed if(!(special_id_length && rgDeathNoticeList[i].iSuicide) && id_length) { SPR_Set( gHUD.GetSprite(id), r, g, b ); SPR_DrawHoles( 0, x, y, &gHUD.GetSpriteRect(id) ); x += (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); } if(special_id_length) { SPR_Set(gHUD.GetSprite(special_id),r,g,b); SPR_DrawHoles(0,x,y,&gHUD.GetSpriteRect(special_id)); x += (gHUD.GetSpriteRect(special_id).right - gHUD.GetSpriteRect(special_id).left); } // Draw victims name (if it was a player that was killed) if (rgDeathNoticeList[i].iNonPlayerKill == FALSE) { if ( rgDeathNoticeList[i].VictimColor ) gEngfuncs.pfnDrawSetTextColor( rgDeathNoticeList[i].VictimColor[0], rgDeathNoticeList[i].VictimColor[1], rgDeathNoticeList[i].VictimColor[2] ); x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim ); } int text_w,text_h; GetConsoleStringSize(rgDeathNoticeList[i].szDeathMessage,&text_w,&text_h); text_y = text_h*i; DrawConsoleString(ScreenWidth-text_w,text_y,rgDeathNoticeList[i].szDeathMessage); } } return 1; } // This message handler may be better off elsewhere int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf ) { m_iFlags |= HUD_ACTIVE; BEGIN_READ( pbuf, iSize ); int killer = READ_BYTE(); int victim = READ_BYTE(); int special = READ_BYTE(); char killedwith[32]; strcpy( killedwith, "d_" ); strncat( killedwith, READ_STRING(), 32 ); if (gViewPort) gViewPort->DeathMsg( killer, victim ); gHUD.m_Spectator.DeathMessage(victim); for ( int i = 0; i < MAX_DEATHNOTICES; i++ ) { if ( rgDeathNoticeList[i].iId == 0 ) break; } if ( i == MAX_DEATHNOTICES ) { // move the rest of the list forward to make room for this item memmove( rgDeathNoticeList, rgDeathNoticeList+1, sizeof(DeathNoticeItem) * MAX_DEATHNOTICES ); i = MAX_DEATHNOTICES - 1; } if (gViewPort) gViewPort->GetAllPlayersInfo(); // Set special death rgDeathNoticeList[i].iSpecialDeath = special; // Get the Killer's name const char *killer_name = g_PlayerInfoList[ killer ].name; if ( !killer_name ) { killer_name = ""; rgDeathNoticeList[i].szKiller[0] = 0; } else { rgDeathNoticeList[i].KillerColor = GetClientColor( killer ); strncpy( rgDeathNoticeList[i].szKiller, killer_name, MAX_PLAYER_NAME_LENGTH ); rgDeathNoticeList[i].szKiller[MAX_PLAYER_NAME_LENGTH-1] = 0; } // Get the Victim's name const char *victim_name = NULL; // If victim is -1, the killer killed a specific, non-player object (like a sentrygun) if ( ((char)victim) != -1 ) victim_name = g_PlayerInfoList[ victim ].name; if ( !victim_name ) { victim_name = ""; rgDeathNoticeList[i].szVictim[0] = 0; } else { rgDeathNoticeList[i].VictimColor = GetClientColor( victim ); strncpy( rgDeathNoticeList[i].szVictim, victim_name, MAX_PLAYER_NAME_LENGTH ); rgDeathNoticeList[i].szVictim[MAX_PLAYER_NAME_LENGTH-1] = 0; } // Is it a non-player object kill? if ( ((char)victim) == -1 ) { rgDeathNoticeList[i].iNonPlayerKill = TRUE; // Store the object's name in the Victim slot (skip the d_ bit) strcpy( rgDeathNoticeList[i].szVictim, killedwith+2 ); } else { if ( killer == victim || killer == 0 ) rgDeathNoticeList[i].iSuicide = TRUE; if ( !strcmp( killedwith, "d_teammate" ) ) rgDeathNoticeList[i].iTeamKill = TRUE; } char *szDeathMessage = READ_STRING(); // fill deathmessage string if(killer == victim || killer == 0) sprintf(rgDeathNoticeList[i].szDeathMessage,"%s commited suicide",victim_name); else sprintf(rgDeathNoticeList[i].szDeathMessage,szDeathMessage,killer_name,victim_name); // Find the sprite in the list int spr = gHUD.GetSpriteIndex( killedwith ); rgDeathNoticeList[i].iId = spr; DEATHNOTICE_DISPLAY_TIME = CVAR_GET_FLOAT( "hud_deathnotice_time" ); rgDeathNoticeList[i].flDisplayTime = gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME; if (rgDeathNoticeList[i].iNonPlayerKill) { ConsolePrint( rgDeathNoticeList[i].szKiller ); ConsolePrint( " killed a " ); ConsolePrint( rgDeathNoticeList[i].szVictim ); ConsolePrint( "\n" ); } else { // record new death notices ConsolePrint(rgDeathNoticeList[i].szDeathMessage); ConsolePrint("\n"); } return 1; }