diff --git a/GameVersion.cpp b/GameVersion.cpp index f270a1af..4d14bd4a 100644 --- a/GameVersion.cpp +++ b/GameVersion.cpp @@ -23,7 +23,7 @@ INT16 zVersionLabel[256] = { L"Beta v. 0.98" }; #else //RELEASE BUILD VERSION - INT16 zVersionLabel[256] = { L"Release v1.13.492" }; + INT16 zVersionLabel[256] = { L"Release v1.13.493" }; #endif diff --git a/Tactical/SoldierTooltips.cpp b/Tactical/SoldierTooltips.cpp new file mode 100644 index 00000000..2420060b --- /dev/null +++ b/Tactical/SoldierTooltips.cpp @@ -0,0 +1,371 @@ +#include "Tactical All.h" + +struct MOUSETT +{ + CHAR16 FastHelpText[ 1024 ]; + INT32 iX; + INT32 iY; + INT32 iW; +}; + +extern struct MOUSETT mouseTT; +extern BOOL mouseTTrender,mouseTTdone; + +const int DL_Limited = 1; +const int DL_Basic = 2; +const int DL_Full = 3; +const int DL_Debug = 4; + +void DisplayWeaponInfo( SOLDIERTYPE*, CHAR16*, UINT8 ); +void DrawMouseTooltip(void); + +void SoldierTooltip( SOLDIERTYPE* pSoldier ) +{ + SGPRect aRect; + extern void GetSoldierScreenRect(SOLDIERTYPE*,SGPRect*); + GetSoldierScreenRect( pSoldier, &aRect ); + INT16 a1,a2; + + if ( gfKeyState[ALT] && pSoldier && + IsPointInScreenRectWithRelative( gusMouseXPos, gusMouseYPos, &aRect, &a1, &a2 ) ) + { + MOUSETT *pRegion = &mouseTT; + CHAR16 pStrInfo[ sizeof( pRegion->FastHelpText ) ]; + int iNVG = 0; + + INT16 sSoldierGridNo; + + //Get the gridno the cursor is at + GetMouseMapPos( &sSoldierGridNo ); + + swprintf( pStrInfo, L"" ); + if ( gGameExternalOptions.ubSoldierTooltipDetailLevel == DL_Debug ) + { + // display "debug" info + if ( gGameExternalOptions.fEnableSoldierTooltipLocation ) + swprintf( pStrInfo, L"%s|Location: %d\n", pStrInfo, sSoldierGridNo ); + if ( gGameExternalOptions.fEnableSoldierTooltipBrightness ) + swprintf( pStrInfo, L"%s|Brightness: %d / %d\n", pStrInfo, SHADE_MIN - LightTrueLevel( sSoldierGridNo, gsInterfaceLevel ), SHADE_MIN ); + if ( ( gGameExternalOptions.fEnableSoldierTooltipRangeToTarget ) && + ( gusSelectedSoldier != NOBODY ) ) + { + swprintf( pStrInfo, L"%s|Range to |Target: %d\n", pStrInfo, + GetRangeInCellCoordsFromGridNoDiff( MercPtrs[ gusSelectedSoldier ]->sGridNo, sSoldierGridNo ) / 10 ); + } + if ( gGameExternalOptions.fEnableSoldierTooltipID ) + swprintf( pStrInfo, L"%s|I|D: %d\n", pStrInfo, pSoldier->ubID ); + if ( gGameExternalOptions.fEnableSoldierTooltipOrders ) + swprintf( pStrInfo, L"%s|Orders: %d\n", pStrInfo, pSoldier->bOrders ); + if ( gGameExternalOptions.fEnableSoldierTooltipAttitude ) + swprintf( pStrInfo, L"%s|Attitude: %d\n", pStrInfo, pSoldier->bAttitude ); + if ( gGameExternalOptions.fEnableSoldierTooltipActionPoints ) + swprintf( pStrInfo, L"%s|Current |A|Ps: %d\n", pStrInfo, pSoldier->bActionPoints ); + if ( gGameExternalOptions.fEnableSoldierTooltipHealth ) + swprintf( pStrInfo, L"%s|Current |Health: %d\n", pStrInfo, pSoldier->bLife ); + } + + // armor info code block start + if ( gGameExternalOptions.ubSoldierTooltipDetailLevel >= DL_Full ) + { + if ( gGameExternalOptions.fEnableSoldierTooltipHelmet ) + swprintf( pStrInfo, L"%s|Helmet: %s\n", pStrInfo, pSoldier->inv[HELMETPOS].usItem ? ItemNames[ pSoldier->inv[HELMETPOS].usItem ] : L"No helmet" ); + if ( gGameExternalOptions.fEnableSoldierTooltipVest ) + swprintf( pStrInfo, L"%s|Vest: %s\n", pStrInfo, pSoldier->inv[VESTPOS].usItem ? ItemNames[ pSoldier->inv[VESTPOS].usItem ] : L"No vest" ); + if ( gGameExternalOptions.fEnableSoldierTooltipLeggings ) + swprintf( pStrInfo, L"%s|Leggings: %s\n", pStrInfo, pSoldier->inv[LEGPOS].usItem ? ItemNames[ pSoldier->inv[LEGPOS].usItem ] : L"No leggings" ); + } + else + { + if ( !( !gGameExternalOptions.fEnableSoldierTooltipHelmet && + !gGameExternalOptions.fEnableSoldierTooltipVest && + !gGameExternalOptions.fEnableSoldierTooltipLeggings) ) + // do not display the armor line if all the armor toggles are set to false + { + if ( ArmourPercent( pSoldier ) ) + { + swprintf( pStrInfo, L"|Armor: " ); + if ( gGameExternalOptions.ubSoldierTooltipDetailLevel == DL_Basic ) + { + if ( gGameExternalOptions.fEnableSoldierTooltipHelmet ) + swprintf( pStrInfo, L"%s%s", pStrInfo, pSoldier->inv[HELMETPOS].usItem ? L"helmet " : L"" ); + if ( gGameExternalOptions.fEnableSoldierTooltipVest ) + swprintf( pStrInfo, L"%s%s", pStrInfo, pSoldier->inv[VESTPOS].usItem ? L"vest " : L"" ); + if ( gGameExternalOptions.fEnableSoldierTooltipLeggings ) + swprintf( pStrInfo, L"%s%s", pStrInfo, pSoldier->inv[LEGPOS].usItem ? L"leggings" : L"" ); + wcscat( pStrInfo, L"\n" ); + } + else // gGameExternalOptions.ubSoldierTooltipDetailLevel == DL_Limited + { + swprintf( pStrInfo, L"|Armor: %s\n", L"worn" ); + } + } + else + { + swprintf( pStrInfo, L"|Armor: %s\n", L"no armor" ); + } + } + } + // armor info code block end + + // head slots info code block start + if ( gGameExternalOptions.ubSoldierTooltipDetailLevel != DL_Debug ) + { + + if( Item[pSoldier->inv[HEAD1POS].usItem].nightvisionrangebonus > 0 ) + iNVG = HEAD1POS; + else if( Item[pSoldier->inv[HEAD2POS].usItem].nightvisionrangebonus > 0 ) + iNVG = HEAD2POS; + + if ( !( !gGameExternalOptions.fEnableSoldierTooltipHeadItem1 && + !gGameExternalOptions.fEnableSoldierTooltipHeadItem2) ) + // do not display the NVG/mask lines if both head slot toggles are set to false + { + if ( gGameExternalOptions.ubSoldierTooltipDetailLevel >= DL_Full ) + { + swprintf( pStrInfo, L"%s|N|V|G: %s\n", pStrInfo, + iNVG ? ItemNames[ pSoldier->inv[ iNVG ].usItem ] : L"no NVG" ); + } + else + { + swprintf( pStrInfo, L"%s|N|V|G: %s\n", pStrInfo, iNVG ? L"worn" : L"no NVG" ); + } + swprintf( pStrInfo, L"%s|Gas |Mask: %s\n", pStrInfo, + ( FindGasMask(pSoldier) ) ? L"worn" : L"no mask" ); + } + } + else // gGameExternalOptions.ubSoldierTooltipDetailLevel == DL_Debug + { + if ( gGameExternalOptions.fEnableSoldierTooltipHeadItem1 ) + swprintf( pStrInfo, L"%s|Head |Position |1: %s\n", pStrInfo, ItemNames[ pSoldier->inv[HEAD1POS].usItem ] ); + if ( gGameExternalOptions.fEnableSoldierTooltipHeadItem2 ) + swprintf( pStrInfo, L"%s|Head |Position |2: %s\n", pStrInfo, ItemNames[ pSoldier->inv[HEAD2POS].usItem ] ); + } + // head slots info code block end + + // weapon in primary hand info code block start + if ( gGameExternalOptions.fEnableSoldierTooltipWeapon ) + { + DisplayWeaponInfo( pSoldier, pStrInfo, HANDPOS ); + } // gGameExternalOptions.fEnableSoldierTooltipWeapon + // weapon in primary hand info code block end + + // weapon in off hand info code block start + if ( gGameExternalOptions.fEnableSoldierTooltipSecondHand ) + { + if ( pSoldier->inv[SECONDHANDPOS].usItem ) + { + // if there's something in the slot display it + wcscat( pStrInfo, L"\n" ); + DisplayWeaponInfo( pSoldier, pStrInfo, SECONDHANDPOS ); + } + } + // weapon in off hand info code block end + + // large objects in big inventory slots info code block start + for ( UINT8 BigSlot = BIGPOCK1POS; BigSlot <= BIGPOCK4POS; BigSlot++ ) + { + if ( pSoldier->inv[ BigSlot ].usItem == 0 ) + continue; // slot is empty, move on to the next slot + + switch( BigSlot ) + { + // if display of this big slot is toggled off then move on to the next slot + case BIGPOCK1POS: + if ( !gGameExternalOptions.fEnableSoldierTooltipBigSlot1 ) + continue; + break; + case BIGPOCK2POS: + if ( !gGameExternalOptions.fEnableSoldierTooltipBigSlot2 ) + continue; + break; + case BIGPOCK3POS: + if ( !gGameExternalOptions.fEnableSoldierTooltipBigSlot3 ) + continue; + break; + case BIGPOCK4POS: + if ( !gGameExternalOptions.fEnableSoldierTooltipBigSlot4 ) + continue; + break; + } + + if ( ( Item[ pSoldier->inv[ BigSlot ].usItem ].usItemClass == IC_LAUNCHER ) || + ( Item[ pSoldier->inv[ BigSlot ].usItem ].usItemClass == IC_GUN ) ) + { + // it's a firearm + if ( ( Weapon[pSoldier->inv[ BigSlot ].usItem].ubWeaponClass != HANDGUNCLASS ) && + ( Weapon[pSoldier->inv[ BigSlot ].usItem].ubWeaponClass != SMGCLASS ) ) + { + // it's a long gun or heavy weapon + wcscat( pStrInfo, L"\n(In Backpack) " ); + DisplayWeaponInfo( pSoldier, pStrInfo, BigSlot ); + } + } + } + // large objects in big inventory slots info code block end + + pRegion->iX = gusMouseXPos; + pRegion->iY = gusMouseYPos; + + if ( gGameExternalOptions.ubSoldierTooltipDetailLevel == DL_Debug ) + swprintf( pRegion->FastHelpText, L"%s\n|String |Length|: %d", pStrInfo, wcslen(pStrInfo) ); + else + wcscpy( pRegion->FastHelpText, pStrInfo ); + } + + if ( gfKeyState[ ALT ] ) + { + DrawMouseTooltip(); + SetRenderFlags( RENDER_FLAG_FULL ); + } +} // SoldierTooltip(SOLDIERTYPE* pSoldier) + + +void DisplayWeaponInfo( SOLDIERTYPE* pSoldier, CHAR16* pStrInfo, UINT8 ubSlot ) +{ + INT32 iNumAttachments = 0; + + if ( gGameExternalOptions.ubSoldierTooltipDetailLevel >= DL_Full ) + { + // display exact weapon model + swprintf( pStrInfo, L"%s|Weapon: %s ", pStrInfo, + WeaponInHand( pSoldier ) ? ItemNames[ pSoldier->inv[ubSlot].usItem ] : L"no weapon" ); + } + else + { + if ( gGameExternalOptions.ubSoldierTooltipDetailLevel == DL_Limited ) + { + // display general weapon class + switch( Weapon[pSoldier->inv[ubSlot].usItem].ubWeaponClass ) + { + case HANDGUNCLASS: + swprintf( pStrInfo, L"%s|Weapon: %s ", pStrInfo, L"handgun" ); + break; + case SMGCLASS: + swprintf( pStrInfo, L"%s|Weapon: %s ", pStrInfo, L"SMG" ); + break; + case RIFLECLASS: + swprintf( pStrInfo, L"%s|Weapon: %s ", pStrInfo, L"rifle" ); + break; + case MGCLASS: + swprintf( pStrInfo, L"%s|Weapon: %s ", pStrInfo, L"MG" ); + break; + case SHOTGUNCLASS: + swprintf( pStrInfo, L"%s|Weapon: %s ", pStrInfo, L"shotgun" ); + break; + case KNIFECLASS: + swprintf( pStrInfo, L"%s|Weapon: %s ", pStrInfo, L"knife" ); + break; + default: + swprintf( pStrInfo, L"%s|Weapon: %s ", pStrInfo, L"heavy weapon" ); + break; + } + } + else + { + // display general weapon type + swprintf( pStrInfo, L"%s|Weapon: %s ", pStrInfo, + WeaponInHand( pSoldier) ? WeaponType[Weapon[pSoldier->inv[ubSlot].usItem].ubWeaponType] : L"no weapon" ); + } + } + + if ( gGameExternalOptions.ubSoldierTooltipDetailLevel >= DL_Basic ) + { + // display weapon attachments + for ( INT32 cnt = 0; cnt < MAX_ATTACHMENTS; cnt++ ) + { + if ( pSoldier->inv[ubSlot].usAttachItem[ cnt ] != NOTHING ) + { + if ( gGameExternalOptions.ubSoldierTooltipDetailLevel == DL_Basic ) + { + // display only externally-visible weapon attachments + // don't display inseparable attachments + if ( !Item[pSoldier->inv[ubSlot].usAttachItem[ cnt ]].inseparable ) + { + iNumAttachments++; + if ( iNumAttachments == 1 ) + wcscat( pStrInfo, L"\n[" ); + else + wcscat( pStrInfo, L", " ); + wcscat( pStrInfo, ItemNames[ pSoldier->inv[ubSlot].usAttachItem[ cnt ] ] ); + + } + } + else + { + // display all weapon attachments + iNumAttachments++; + if ( iNumAttachments == 1 ) + wcscat( pStrInfo, L"\n[" ); + else + wcscat( pStrInfo, L", " ); + wcscat( pStrInfo, ItemNames[ pSoldier->inv[ubSlot].usAttachItem[ cnt ] ] ); + } + } // pSoldier->inv[HANDPOS].usAttachItem[ cnt ] != NOTHING + } // for + if ( iNumAttachments > 0 ) + wcscat( pStrInfo, pMessageStrings[ MSG_END_ATTACHMENT_LIST ] ); // append ' attached]' to end of string + } // gGameExternalOptions.ubSoldierTooltipDetailLevel >= DL_Basic +} + +MOUSETT mouseTT; +BOOL mouseTTrender, mouseTTdone; + +void DrawMouseTooltip() +{ + UINT8 *pDestBuf; + UINT32 uiDestPitchBYTES; + UINT16 usFillColor = Get16BPPColor(FROMRGB(250, 240, 188)); + UINT16 usRectColor1 = Get16BPPColor( FROMRGB( 65, 57, 15 ) ); + UINT16 usRectColor2 = Get16BPPColor( FROMRGB( 227, 198, 88 ) ); + static INT32 iX, iY, iW, iH; + + extern INT16 GetWidthOfString(STR16); + extern INT16 GetNumberOfLinesInHeight(STR16); + extern void DisplayHelpTokenizedString(STR16,INT16,INT16); + extern BOOLEAN initTooltipBuffer(); + extern PTR LockTooltipBuffer(UINT32*); + extern void UnlockTooltipBuffer(); + extern void DisplayTooltipString( STR16 pStringA, INT16 sX, INT16 sY ); + extern void j_log(PTR,...); + +// if (!gGameExternalOptions.gfAllowSoldierToolTips) return; + + iX = mouseTT.iX;iY = mouseTT.iY; + iW = (INT32)GetWidthOfString( mouseTT.FastHelpText ) + 10; + iH = (INT32)( GetNumberOfLinesInHeight( mouseTT.FastHelpText ) * (GetFontHeight(FONT10ARIAL)+1) + 8 ); + + if(1)//draw at cursor + { + iY -= (iH / 2); + if (gusMouseXPos > (SCREEN_WIDTH / 2)) + iX = gusMouseXPos - iW - 24; + else + iX = gusMouseXPos + 24; + //if (gusMouseYPos > (SCREEN_HEIGHT / 2)) + // iY -= 32; + + if (iY <= 0) iY += 32; + } + else + { //draw in panel + //502,485 658,596 160*110 580,540 + iX = 580 - (iW / 2); + iY = 540 - (iH/2); + if (iY + iH > SCREEN_HEIGHT) iY = SCREEN_HEIGHT - iH - 3 ; + } + + pDestBuf = LockVideoSurface( FRAME_BUFFER, &uiDestPitchBYTES ); + SetClippingRegionAndImageWidth( uiDestPitchBYTES, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT ); + RectangleDraw( TRUE, iX + 1, iY + 1, iX + iW - 1, iY + iH - 1, Get16BPPColor( FROMRGB( 65, 57, 15 ) ), pDestBuf ); + RectangleDraw( TRUE, iX, iY, iX + iW - 2, iY + iH - 2, Get16BPPColor( FROMRGB( 227, 198, 88 ) ), pDestBuf ); + UnLockVideoSurface( FRAME_BUFFER ); + ShadowVideoSurfaceRect( FRAME_BUFFER, iX + 2, iY + 2, iX + iW - 3, iY + iH - 3 ); + ShadowVideoSurfaceRect( FRAME_BUFFER, iX + 2, iY + 2, iX + iW - 3, iY + iH - 3 ); + + SetFont( FONT10ARIAL ); + SetFontShadow( FONT_NEARBLACK ); + DisplayHelpTokenizedString( mouseTT.FastHelpText ,( INT16 )( iX + 5 ), ( INT16 )( iY + 5 ) ); + InvalidateRegion( iX, iY, (iX + iW) , (iY + iH) ); + + //InvalidateScreen(); +} \ No newline at end of file