/*** * * Copyright (c) 1999, 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. * ****/ // // Health.cpp // // implementation of CHudHealth class // #include #include #include #include "hud.h" #include "cl_util.h" #include "parsemsg.h" #include DECLARE_MESSAGE(m_Health, Health ) DECLARE_MESSAGE(m_Health, Damage ) DECLARE_MESSAGE(m_Health, Medkit ) // modif de Julien #define PAIN_NAME "sprites/%d_pain.spr" #define DAMAGE_NAME "sprites/%d_dmg.spr" int giDmgHeight, giDmgWidth; int giDmgFlags[NUM_DMG_TYPES] = { DMG_POISON, DMG_ACID, DMG_FREEZE|DMG_SLOWFREEZE, DMG_DROWN, DMG_BURN|DMG_SLOWBURN, DMG_NERVEGAS, DMG_RADIATION, DMG_SHOCK, DMG_CALTROP, DMG_TRANQ, DMG_CONCUSS, DMG_HALLUC }; int CHudHealth::Init(void) { HOOK_MESSAGE(Health); HOOK_MESSAGE(Damage); HOOK_MESSAGE(Medkit); // modif de Julien m_iHealth = 100; m_fFade = 0; m_iFlags = 0; m_bitsDamage = 0; m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; giDmgHeight = 0; giDmgWidth = 0; memset(m_dmg, 0, sizeof(DAMAGE_IMAGE) * NUM_DMG_TYPES); // modif de Julien m_sprDisposition = SPR_Load("sprites/hud_health_dispostion.spr"); m_wrcDisposition = CreateWrect ( 2, 2, 174, 158 ); m_sprVie = SPR_Load("sprites/hud_health_vie.spr"); float wrectTemporary = 144 * 0.01f * (100-m_iHealth); int wrectActual = static_cast(wrectTemporary); m_wrcVie = CreateWrect ( 1, 8 + wrectActual, 30, 158 ); m_sprMedkit = SPR_Load("sprites/hud_health_medkit.spr"); m_wrcMedkit = CreateWrect ( 0, 0, 104, 32 ); m_iMedkit = m_iBattery = 0; gHUD.AddHudElem(this); return 1; } void CHudHealth::Reset( void ) { // make sure the pain compass is cleared when the player respawns m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; // force all the flashing damage icons to expire m_bitsDamage = 0; for ( int i = 0; i < NUM_DMG_TYPES; i++ ) { m_dmg[i].fExpire = 0; } } int CHudHealth::VidInit(void) { m_hSprite = 0; m_HUD_dmg_bio = gHUD.GetSpriteIndex( "dmg_bio" ) + 1; m_HUD_cross = gHUD.GetSpriteIndex( "cross" ); giDmgHeight = gHUD.GetSpriteRect(m_HUD_dmg_bio).right - gHUD.GetSpriteRect(m_HUD_dmg_bio).left; giDmgWidth = gHUD.GetSpriteRect(m_HUD_dmg_bio).bottom - gHUD.GetSpriteRect(m_HUD_dmg_bio).top; // modif de Julien m_sprDisposition = SPR_Load("sprites/hud_health_dispostion.spr"); m_wrcDisposition = CreateWrect ( 2, 2, 174, 158 ); m_sprVie = SPR_Load("sprites/hud_health_vie.spr"); float wrectTemporary = 144 * 0.01f * (100-m_iHealth); int wrectActual = static_cast(wrectTemporary); m_wrcVie = CreateWrect ( 1, 8 + wrectActual, 30, 158 ); // m_wrcVie = CreateWrect ( 1, 8 + (int)(144*0.01f*(100-m_iHealth)), 30, 158 ); m_sprMedkit = SPR_Load("sprites/hud_health_medkit.spr"); m_wrcMedkit = CreateWrect ( 0, 0, 104, 32 ); return 1; } int CHudHealth:: MsgFunc_Medkit(const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); m_iMedkit = READ_BYTE(); m_iBattery = READ_BYTE(); return 1; } int CHudHealth:: MsgFunc_Health(const char *pszName, int iSize, void *pbuf ) { // TODO: update local health data BEGIN_READ( pbuf, iSize ); int x = READ_BYTE(); m_iFlags |= HUD_ACTIVE; // Only update the fade if we've changed health if (x != m_iHealth) { m_fFade = FADE_TIME; m_iHealth = x; //modif de Julien float wrectTemporary = 144 * 0.01f * (100-m_iHealth); int wrectActual = static_cast(wrectTemporary); m_wrcVie = CreateWrect ( 1, 8 + wrectActual, 30, 158 ); //m_wrcVie = CreateWrect ( 1, 8 + (int)(144*0.01f*(100-m_iHealth)), 30, 158 ); } return 1; } int CHudHealth:: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); int armor = READ_BYTE(); // armor int damageTaken = READ_BYTE(); // health long bitsDamage = READ_LONG(); // damage bits vec3_t vecFrom; for ( int i = 0 ; i < 3 ; i++) vecFrom[i] = READ_COORD(); UpdateTiles(gHUD.m_flTime, bitsDamage); // Actually took damage? if ( damageTaken > 0 || armor > 0 ) CalcDamageDirection(vecFrom); return 1; } // Returns back a color from the // Green <-> Yellow <-> Red ramp void CHudHealth::GetPainColor( int &r, int &g, int &b ) { int iHealth = m_iHealth; if (iHealth > 25) iHealth -= 25; else if ( iHealth < 0 ) iHealth = 0; #if 0 g = iHealth * 255 / 100; r = 255 - g; b = 0; #else if (m_iHealth > 25) { UnpackRGB(r,g,b, RGB_YELLOWISH); } else { r = 250; g = 0; b = 0; } #endif } int CHudHealth::Draw(float flTime) { // modif de juline if ( !(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT))) ) return 1; int r, g, b; int a = 0; /* int x, y; int HealthWidth; // if (m_iHealth <= 0) // return 1; if ( gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH ) return 1; if ( !m_hSprite ) m_hSprite = LoadSprite(PAIN_NAME); // Has health changed? Flash the health # if (m_fFade) { m_fFade -= (gHUD.m_flTimeDelta * 20); if (m_fFade <= 0) { a = MIN_ALPHA; m_fFade = 0; } // Fade the health number back to dim a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128; } else a = MIN_ALPHA; // If health is getting low, make it bright red if (m_iHealth <= 15) a = 255; GetPainColor( r, g, b ); ScaleColors(r, g, b, a ); // Only draw health if we have the suit. if (gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT))) { HealthWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; int CrossWidth = gHUD.GetSpriteRect(m_HUD_cross).right - gHUD.GetSpriteRect(m_HUD_cross).left; y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; x = CrossWidth /2; SPR_Set(gHUD.GetSprite(m_HUD_cross), r, g, b); // SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_cross)); x = CrossWidth + HealthWidth / 2; x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iHealth, r, g, b); x += HealthWidth/2; int iHeight = gHUD.m_iFontHeight; int iWidth = HealthWidth/10; FillRGBA(x, y, iWidth, iHeight, 255, 160, 0, a); } */ if ( !m_hSprite ) m_hSprite = LoadSprite(PAIN_NAME); // modif de Julien // dessin du nouveau hud pour le compteur de vie if (m_iHealth <= 25) { r = 255; g = 0; b = 0; a = 170; } else { r = g = b = 255; a = 255; } ScaleColors(r, g, b, a ); SPR_Set( m_sprDisposition, r, g, b ); SPR_DrawHoles(0, 0, 0, &m_wrcDisposition); char cNombre [16]; sprintf ( cNombre, "%i", m_iHealth ); gHUD.DrawHudStringReverse( 195, 135, 0, cNombre, r, g, b ); if ( m_iHealth > 0 ) { SPR_Set( m_sprVie, 255, 255, 255 ); SPR_DrawHoles(0, 150, m_wrcVie.top - 2, &m_wrcVie); } // medkits et battery SPR_Set( m_sprMedkit, 255, 255, 255 ); SPR_DrawHoles(0, 172, 0, &m_wrcMedkit); sprintf ( cNombre, "%i", m_iBattery ); gHUD.DrawHudStringReverse( 217, 10, 0, cNombre, 255, 255, 255 ); sprintf ( cNombre, "%i", m_iMedkit ); gHUD.DrawHudStringReverse( 284, 10, 0, cNombre, 255, 255, 255 ); //----------------- DrawDamage(flTime); DrawPain(flTime); return 1; } void CHudHealth::CalcDamageDirection(vec3_t vecFrom) { vec3_t forward, right, up; float side, front; vec3_t vecOrigin, vecAngles; if (!vecFrom[0] && !vecFrom[1] && !vecFrom[2]) { m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; return; } memcpy(vecOrigin, gHUD.m_vecOrigin, sizeof(vec3_t)); memcpy(vecAngles, gHUD.m_vecAngles, sizeof(vec3_t)); VectorSubtract (vecFrom, vecOrigin, vecFrom); float flDistToTarget = vecFrom.Length(); vecFrom = vecFrom.Normalize(); AngleVectors (vecAngles, forward, right, up); front = DotProduct (vecFrom, right); side = DotProduct (vecFrom, forward); if (flDistToTarget <= 50) { m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 1; } else { if (side > 0) { if (side > 0.3) m_fAttackFront = Q_max(m_fAttackFront, side); } else { float f = fabs(side); if (f > 0.3) m_fAttackRear = Q_max(m_fAttackRear, f); } if (front > 0) { if (front > 0.3) m_fAttackRight = Q_max(m_fAttackRight, front); } else { float f = fabs(front); if (f > 0.3) m_fAttackLeft = Q_max(m_fAttackLeft, f); } } } int CHudHealth::DrawPain(float flTime) { if (!(m_fAttackFront || m_fAttackRear || m_fAttackLeft || m_fAttackRight)) return 1; int r, g, b; int x, y, a, shade; // TODO: get the shift value of the health a = 255; // max brightness until then float fFade = gHUD.m_flTimeDelta * 2; // SPR_Draw top if (m_fAttackFront > 0.4) { GetPainColor(r,g,b); shade = a * Q_max( m_fAttackFront, 0.5 ); ScaleColors(r, g, b, shade); SPR_Set(m_hSprite, r, g, b ); x = ScreenWidth/2 - SPR_Width(m_hSprite, 0)/2; y = ScreenHeight/2 - SPR_Height(m_hSprite,0) * 3; SPR_DrawAdditive(0, x, y, NULL); m_fAttackFront = Q_max( 0, m_fAttackFront - fFade ); } else m_fAttackFront = 0; if (m_fAttackRight > 0.4) { GetPainColor(r,g,b); shade = a * Q_max( m_fAttackRight, 0.5 ); ScaleColors(r, g, b, shade); SPR_Set(m_hSprite, r, g, b ); x = ScreenWidth/2 + SPR_Width(m_hSprite, 1) * 2; y = ScreenHeight/2 - SPR_Height(m_hSprite,1)/2; SPR_DrawAdditive(1, x, y, NULL); m_fAttackRight = Q_max( 0, m_fAttackRight - fFade ); } else m_fAttackRight = 0; if (m_fAttackRear > 0.4) { GetPainColor(r,g,b); shade = a * Q_max( m_fAttackRear, 0.5 ); ScaleColors(r, g, b, shade); SPR_Set(m_hSprite, r, g, b ); x = ScreenWidth/2 - SPR_Width(m_hSprite, 2)/2; y = ScreenHeight/2 + SPR_Height(m_hSprite,2) * 2; SPR_DrawAdditive(2, x, y, NULL); m_fAttackRear = Q_max( 0, m_fAttackRear - fFade ); } else m_fAttackRear = 0; if (m_fAttackLeft > 0.4) { GetPainColor(r,g,b); shade = a * Q_max( m_fAttackLeft, 0.5 ); ScaleColors(r, g, b, shade); SPR_Set(m_hSprite, r, g, b ); x = ScreenWidth/2 - SPR_Width(m_hSprite, 3) * 3; y = ScreenHeight/2 - SPR_Height(m_hSprite,3)/2; SPR_DrawAdditive(3, x, y, NULL); m_fAttackLeft = Q_max( 0, m_fAttackLeft - fFade ); } else m_fAttackLeft = 0; return 1; } int CHudHealth::DrawDamage(float flTime) { int r, g, b, a; DAMAGE_IMAGE *pdmg; if (!m_bitsDamage) return 1; UnpackRGB(r,g,b, RGB_YELLOWISH); a = (int)( fabs(sin(flTime*2)) * 256.0); ScaleColors(r, g, b, a); // Draw all the items for (int i = 0; i < NUM_DMG_TYPES; i++) { if (m_bitsDamage & giDmgFlags[i]) { pdmg = &m_dmg[i]; SPR_Set(gHUD.GetSprite(m_HUD_dmg_bio + i), r, g, b ); SPR_DrawAdditive(0, pdmg->x, pdmg->y, &gHUD.GetSpriteRect(m_HUD_dmg_bio + i)); } } int i = 0; //Loop iterator fix. // check for bits that should be expired for ( i = 0; i < NUM_DMG_TYPES; i++ ) { DAMAGE_IMAGE *pdmg = &m_dmg[i]; if ( m_bitsDamage & giDmgFlags[i] ) { pdmg->fExpire = Q_min( flTime + DMG_IMAGE_LIFE, pdmg->fExpire ); if ( pdmg->fExpire <= flTime // when the time has expired && a < 40 ) // and the flash is at the low point of the cycle { pdmg->fExpire = 0; int y = pdmg->y; pdmg->x = pdmg->y = 0; // move everyone above down for (int j = 0; j < NUM_DMG_TYPES; j++) { pdmg = &m_dmg[j]; if ((pdmg->y) && (pdmg->y < y)) pdmg->y += giDmgHeight; } m_bitsDamage &= ~giDmgFlags[i]; // clear the bits } } } return 1; } void CHudHealth::UpdateTiles(float flTime, long bitsDamage) { DAMAGE_IMAGE *pdmg; // Which types are new? long bitsOn = ~m_bitsDamage & bitsDamage; for (int i = 0; i < NUM_DMG_TYPES; i++) { pdmg = &m_dmg[i]; // Is this one already on? if (m_bitsDamage & giDmgFlags[i]) { pdmg->fExpire = flTime + DMG_IMAGE_LIFE; // extend the duration if (!pdmg->fBaseline) pdmg->fBaseline = flTime; } // Are we just turning it on? if (bitsOn & giDmgFlags[i]) { // put this one at the bottom pdmg->x = giDmgWidth/8; pdmg->y = ScreenHeight - giDmgHeight * 2; pdmg->fExpire=flTime + DMG_IMAGE_LIFE; // move everyone else up for (int j = 0; j < NUM_DMG_TYPES; j++) { if (j == i) continue; pdmg = &m_dmg[j]; if (pdmg->y) pdmg->y -= giDmgHeight; } pdmg = &m_dmg[i]; } } // damage bits are only turned on here; they are turned off when the draw time has expired (in DrawDamage()) m_bitsDamage |= bitsDamage; }