mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@766 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2285 lines
60 KiB
C++
2285 lines
60 KiB
C++
#ifdef PRECOMPILEDHEADERS
|
|
#include "Tactical All.h"
|
|
#else
|
|
#include "math.h"
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
|
|
#include "worlddef.h"
|
|
#include "renderworld.h"
|
|
#include "vsurface.h"
|
|
#include "Render Dirty.h"
|
|
#include "sysutil.h"
|
|
#include "container.h"
|
|
#include "wcheck.h"
|
|
#include "video.h"
|
|
#include "vobject_blitters.h"
|
|
#include "faces.h"
|
|
#include "utilities.h"
|
|
#include "overhead.h"
|
|
#include "gap.h"
|
|
#include "Soldier Profile.h"
|
|
#include "sound control.h"
|
|
#include "teamturns.h"
|
|
#include "soldier macros.h"
|
|
#include "dialogue control.h"
|
|
#include "font control.h"
|
|
#include "Assignments.h"
|
|
#include "Random.h"
|
|
#include "line.h"
|
|
#include "GameSettings.h"
|
|
#include "squads.h"
|
|
#include "interface.h"
|
|
#include "Quests.h"
|
|
#include "animation control.h"
|
|
#endif
|
|
|
|
// Defines
|
|
#define NUM_FACE_SLOTS 50
|
|
|
|
#define END_FACE_OVERLAY_DELAY 2000
|
|
|
|
|
|
// GLOBAL FOR FACES LISTING
|
|
FACETYPE gFacesData[ NUM_FACE_SLOTS ];
|
|
UINT32 guiNumFaces = 0;
|
|
|
|
// LOCAL FUNCTIONS
|
|
void NewEye( FACETYPE *pFace );
|
|
void NewMouth( FACETYPE *pFace );
|
|
INT32 GetFreeFace(void);
|
|
void RecountFaces(void);
|
|
void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLEAN fUseExternBuffer, UINT32 uiBuffer, INT16 sFaceX, INT16 sFaceY, UINT16 usEyesX, UINT16 usEyesY );
|
|
|
|
extern BOOLEAN gfInItemPickupMenu;
|
|
|
|
|
|
|
|
typedef struct
|
|
{
|
|
INT8 bEyesX;
|
|
INT8 bEyesY;
|
|
INT8 bMouthX;
|
|
INT8 bMouthY;
|
|
|
|
} RPC_SMALL_FACE_VALUES;
|
|
|
|
|
|
RPC_SMALL_FACE_VALUES gRPCSmallFaceValues[ ] =
|
|
{
|
|
9, 8, 8, 24, // MIGUEL ( 57 )
|
|
8, 8, 7, 24, // CARLOS ( 58 )
|
|
10, 8, 8, 26, // IRA ( 59 )
|
|
7, 8, 7, 26, // DIMITRI ( 60 )
|
|
6, 7, 7, 23, // DEVIN ( 61 )
|
|
0, 0, 0, 0, // THE RAT ( 62 )
|
|
8, 7, 8, 23, // ( 63 )
|
|
8, 8, 8, 22, // SLAY ( 64 )
|
|
0, 0, 0, 0, // ( 65 )
|
|
9, 4, 7, 22, // DYNAMO ( 66 )
|
|
8, 8, 8, 25, // SHANK ( 67 )
|
|
4, 6, 5, 22, // IGGY ( 68 )
|
|
8, 9, 7, 25, // VINCE ( 69 )
|
|
4, 7, 5, 25, // CONRAD ( 70 )
|
|
9, 7, 8, 22, // CARL ( 71 )
|
|
9, 7, 9, 25, // MADDOG ( 72 )
|
|
0, 0, 0, 0, // ( 73 )
|
|
0, 0, 0, 0, // ( 74 )
|
|
|
|
9, 3, 8, 23, // MARIA ( 88 )
|
|
|
|
9, 3, 8, 25, // JOEY ( 90 )
|
|
|
|
11, 7, 9, 24, // SKYRIDER ( 97 )
|
|
9, 5, 7, 23, // Miner ( 106 )
|
|
|
|
6, 4, 6, 24, // JOHN ( 118 )
|
|
12,4, 10, 24, // ( 119 )
|
|
8, 6, 8, 23, // Miner ( 148 )
|
|
6, 5, 6, 23, // Miner ( 156 )
|
|
13, 7, 11, 24, // Miner ( 157 )
|
|
9, 7, 8, 22, // Miner ( 158 )
|
|
|
|
};
|
|
|
|
UINT8 gubRPCSmallFaceProfileNum[] =
|
|
{
|
|
57, // entry 0
|
|
58,
|
|
59,
|
|
60,
|
|
61,
|
|
62,
|
|
63,
|
|
64,
|
|
65,
|
|
66, // entry 9
|
|
67,
|
|
68,
|
|
69,
|
|
70,
|
|
71,
|
|
72,
|
|
73,
|
|
74,
|
|
88,
|
|
90, // entry 19
|
|
97,
|
|
106,
|
|
118,
|
|
119,
|
|
148, // entry 24
|
|
156,
|
|
157,
|
|
158,
|
|
|
|
};
|
|
|
|
UINT8 ubRPCNumSmallFaceValues = 28;
|
|
|
|
|
|
extern BOOLEAN gfSMDisableForItems;
|
|
extern INT16 gsCurInterfacePanel;
|
|
extern UINT16 gusSMCurrentMerc;
|
|
extern BOOLEAN gfRerenderInterfaceFromHelpText;
|
|
extern BOOLEAN gfInItemPickupMenu;
|
|
|
|
BOOLEAN FaceRestoreSavedBackgroundRect( INT32 iFaceIndex, INT16 sDestLeft, INT16 sDestTop, INT16 sSrcLeft, INT16 sSrcTop, INT16 sWidth, INT16 sHeight );
|
|
void SetupFinalTalkingDelay( FACETYPE *pFace );
|
|
|
|
|
|
INT32 GetFreeFace(void)
|
|
{
|
|
UINT32 uiCount;
|
|
|
|
for(uiCount=0; uiCount < guiNumFaces; uiCount++)
|
|
{
|
|
if((gFacesData[uiCount].fAllocated==FALSE) )
|
|
return((INT32)uiCount);
|
|
}
|
|
|
|
if(guiNumFaces < NUM_FACE_SLOTS )
|
|
return((INT32)guiNumFaces++);
|
|
|
|
return(-1);
|
|
}
|
|
|
|
void RecountFaces(void)
|
|
{
|
|
INT32 uiCount;
|
|
|
|
for(uiCount=guiNumFaces-1; (uiCount >=0) ; uiCount--)
|
|
{
|
|
if( ( gFacesData[uiCount].fAllocated ) )
|
|
{
|
|
guiNumFaces=(UINT32)(uiCount+1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
INT32 InitSoldierFace( SOLDIERTYPE *pSoldier )
|
|
{
|
|
INT32 iFaceIndex;
|
|
|
|
// Check if we have a face init already
|
|
iFaceIndex = pSoldier->iFaceIndex;
|
|
|
|
if ( iFaceIndex != -1 )
|
|
{
|
|
return( iFaceIndex );
|
|
}
|
|
|
|
return( InitFace( pSoldier->ubProfile, pSoldier->ubID, 0) );
|
|
}
|
|
|
|
|
|
INT32 InitFace( UINT8 usMercProfileID, UINT8 ubSoldierID, UINT32 uiInitFlags )
|
|
{
|
|
UINT32 uiBlinkFrequency;
|
|
UINT32 uiExpressionFrequency;
|
|
|
|
if ( usMercProfileID == NO_PROFILE )
|
|
{
|
|
return( -1 );
|
|
}
|
|
|
|
uiBlinkFrequency = gMercProfiles[ usMercProfileID ].uiBlinkFrequency;
|
|
uiExpressionFrequency = gMercProfiles[ usMercProfileID ].uiExpressionFrequency;
|
|
|
|
if ( Random( 2 ) )
|
|
{
|
|
uiBlinkFrequency += Random( 2000 );
|
|
}
|
|
else
|
|
{
|
|
uiBlinkFrequency -= Random( 2000 );
|
|
}
|
|
|
|
return( InternalInitFace( usMercProfileID, ubSoldierID, uiInitFlags, gMercProfiles[ usMercProfileID ].ubFaceIndex, uiBlinkFrequency, uiExpressionFrequency ) );
|
|
|
|
}
|
|
|
|
|
|
INT32 InternalInitFace( UINT8 usMercProfileID, UINT8 ubSoldierID, UINT32 uiInitFlags, INT32 iFaceFileID, UINT32 uiBlinkFrequency, UINT32 uiExpressionFrequency )
|
|
{
|
|
FACETYPE *pFace;
|
|
VOBJECT_DESC VObjectDesc;
|
|
UINT32 uiVideoObject;
|
|
INT32 iFaceIndex;
|
|
ETRLEObject ETRLEObject;
|
|
HVOBJECT hVObject;
|
|
UINT32 uiCount;
|
|
SGPPaletteEntry Pal[256];
|
|
|
|
if( ( iFaceIndex = GetFreeFace() )==(-1) )
|
|
return(-1);
|
|
|
|
// Load face file
|
|
VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE;
|
|
|
|
// ATE: If we are merc profile ID #151-154, all use 151's protrait....
|
|
if ( usMercProfileID >= 151 && usMercProfileID <= 154 )
|
|
{
|
|
iFaceFileID = 151;
|
|
}
|
|
|
|
|
|
// Check if we are a big-face....
|
|
if ( uiInitFlags & FACE_BIGFACE )
|
|
{
|
|
// The filename is the profile ID!
|
|
if( iFaceFileID < 100 )
|
|
{
|
|
sprintf( VObjectDesc.ImageFile, "FACES\\b%02d.sti", iFaceFileID );
|
|
}
|
|
else
|
|
{
|
|
sprintf( VObjectDesc.ImageFile, "FACES\\b%03d.sti", iFaceFileID );
|
|
}
|
|
|
|
// ATE: Check for profile - if elliot , use special face :)
|
|
if ( usMercProfileID == ELLIOT )
|
|
{
|
|
if ( gMercProfiles[ ELLIOT ].bNPCData > 3 && gMercProfiles[ ELLIOT ].bNPCData < 7 )
|
|
{
|
|
sprintf( VObjectDesc.ImageFile, "FACES\\b%02da.sti", iFaceFileID );
|
|
}
|
|
else if ( gMercProfiles[ ELLIOT ].bNPCData > 6 && gMercProfiles[ ELLIOT ].bNPCData < 10 )
|
|
{
|
|
sprintf( VObjectDesc.ImageFile, "FACES\\b%02db.sti", iFaceFileID );
|
|
}
|
|
else if ( gMercProfiles[ ELLIOT ].bNPCData > 9 && gMercProfiles[ ELLIOT ].bNPCData < 13 )
|
|
{
|
|
sprintf( VObjectDesc.ImageFile, "FACES\\b%02dc.sti", iFaceFileID );
|
|
}
|
|
else if ( gMercProfiles[ ELLIOT ].bNPCData > 12 && gMercProfiles[ ELLIOT ].bNPCData < 16 )
|
|
{
|
|
sprintf( VObjectDesc.ImageFile, "FACES\\b%02dd.sti", iFaceFileID );
|
|
}
|
|
else if ( gMercProfiles[ ELLIOT ].bNPCData == 17 )
|
|
{
|
|
sprintf( VObjectDesc.ImageFile, "FACES\\b%02de.sti", iFaceFileID );
|
|
}
|
|
}
|
|
else if ( usMercProfileID == TEX )
|
|
{
|
|
if( gMercProfiles[ TEX ].bSkillTrait2 == CAMOUFLAGED )
|
|
{
|
|
sprintf( VObjectDesc.ImageFile, "FACES\\B167c.sti" );
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
if( iFaceFileID < 100 )
|
|
{
|
|
// The filename is the profile ID!
|
|
sprintf( VObjectDesc.ImageFile, "FACES\\%02d.sti", iFaceFileID );
|
|
}
|
|
else
|
|
{
|
|
sprintf( VObjectDesc.ImageFile, "FACES\\%03d.sti", iFaceFileID );
|
|
}
|
|
}
|
|
|
|
// Load
|
|
if( AddVideoObject( &VObjectDesc, &uiVideoObject ) == FALSE )
|
|
{
|
|
// If we are a big face, use placeholder...
|
|
if ( uiInitFlags & FACE_BIGFACE )
|
|
{
|
|
sprintf( VObjectDesc.ImageFile, "FACES\\placeholder.sti" );
|
|
|
|
if( AddVideoObject( &VObjectDesc, &uiVideoObject ) == FALSE )
|
|
{
|
|
return( -1 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return( -1 );
|
|
}
|
|
}
|
|
|
|
memset(&gFacesData[ iFaceIndex ], 0, sizeof( FACETYPE ) );
|
|
|
|
pFace = &gFacesData[ iFaceIndex ];
|
|
|
|
// Get profile data and set into face data
|
|
pFace->ubSoldierID = ubSoldierID;
|
|
|
|
pFace->iID = iFaceIndex;
|
|
pFace->fAllocated = TRUE;
|
|
|
|
//Default to off!
|
|
pFace->fDisabled = TRUE;
|
|
pFace->iVideoOverlay = -1;
|
|
//pFace->uiEyeDelay = gMercProfiles[ usMercProfileID ].uiEyeDelay;
|
|
//pFace->uiMouthDelay = gMercProfiles[ usMercProfileID ].uiMouthDelay;
|
|
pFace->uiEyeDelay = 50 + Random( 30 );
|
|
pFace->uiMouthDelay = 120;
|
|
pFace->ubCharacterNum = usMercProfileID;
|
|
|
|
|
|
pFace->uiBlinkFrequency = uiBlinkFrequency;
|
|
pFace->uiExpressionFrequency = uiExpressionFrequency;
|
|
|
|
pFace->sEyeFrame = 0;
|
|
pFace->sMouthFrame = 0;
|
|
pFace->uiFlags = uiInitFlags;
|
|
|
|
|
|
// Set palette
|
|
if( GetVideoObject( &hVObject, uiVideoObject ) )
|
|
{
|
|
// Build a grayscale palette! ( for testing different looks )
|
|
for(uiCount=0; uiCount < 256; uiCount++)
|
|
{
|
|
Pal[uiCount].peRed=255;
|
|
Pal[uiCount].peGreen=255;
|
|
Pal[uiCount].peBlue=255;
|
|
}
|
|
|
|
hVObject->pShades[ FLASH_PORTRAIT_NOSHADE ] = Create16BPPPaletteShaded( hVObject->pPaletteEntry, 255, 255, 255, FALSE );
|
|
hVObject->pShades[ FLASH_PORTRAIT_STARTSHADE ] = Create16BPPPaletteShaded( Pal, 255, 255, 255, FALSE );
|
|
hVObject->pShades[ FLASH_PORTRAIT_ENDSHADE ] = Create16BPPPaletteShaded( hVObject->pPaletteEntry, 250, 25, 25, TRUE );
|
|
hVObject->pShades[ FLASH_PORTRAIT_DARKSHADE ] = Create16BPPPaletteShaded( hVObject->pPaletteEntry, 100, 100, 100, TRUE );
|
|
hVObject->pShades[ FLASH_PORTRAIT_LITESHADE ] = Create16BPPPaletteShaded( hVObject->pPaletteEntry, 100, 100, 100, FALSE );
|
|
|
|
for(uiCount=0; uiCount < 256; uiCount++)
|
|
{
|
|
Pal[uiCount].peRed=(UINT8)(uiCount%128)+128;
|
|
Pal[uiCount].peGreen=(UINT8)(uiCount%128)+128;
|
|
Pal[uiCount].peBlue=(UINT8)(uiCount%128)+128;
|
|
}
|
|
hVObject->pShades[ FLASH_PORTRAIT_GRAYSHADE ] = Create16BPPPaletteShaded( Pal, 255, 255, 255, FALSE );
|
|
|
|
}
|
|
|
|
|
|
// Get FACE height, width
|
|
if( GetVideoObjectETRLEPropertiesFromIndex( uiVideoObject, &ETRLEObject, 0 ) == FALSE )
|
|
{
|
|
return( -1 );
|
|
}
|
|
pFace->usFaceWidth = ETRLEObject.usWidth;
|
|
pFace->usFaceHeight = ETRLEObject.usHeight;
|
|
|
|
|
|
// OK, check # of items
|
|
if ( hVObject->usNumberOfObjects == 8 )
|
|
{
|
|
pFace->fInvalidAnim = FALSE;
|
|
|
|
// Get EYE height, width
|
|
if( GetVideoObjectETRLEPropertiesFromIndex( uiVideoObject, &ETRLEObject, 1 ) == FALSE )
|
|
{
|
|
return( -1 );
|
|
}
|
|
pFace->usEyesWidth = ETRLEObject.usWidth;
|
|
pFace->usEyesHeight = ETRLEObject.usHeight;
|
|
|
|
|
|
// Get Mouth height, width
|
|
if( GetVideoObjectETRLEPropertiesFromIndex( uiVideoObject, &ETRLEObject, 5 ) == FALSE )
|
|
{
|
|
return( -1 );
|
|
}
|
|
pFace->usMouthWidth = ETRLEObject.usWidth;
|
|
pFace->usMouthHeight = ETRLEObject.usHeight;
|
|
}
|
|
else
|
|
{
|
|
pFace->fInvalidAnim = TRUE;
|
|
}
|
|
|
|
// Set id
|
|
pFace->uiVideoObject = uiVideoObject;
|
|
|
|
return( iFaceIndex );
|
|
|
|
}
|
|
|
|
|
|
void DeleteSoldierFace( SOLDIERTYPE *pSoldier )
|
|
{
|
|
DeleteFace( pSoldier->iFaceIndex );
|
|
|
|
pSoldier->iFaceIndex = -1;
|
|
}
|
|
|
|
|
|
void DeleteFace( INT32 iFaceIndex )
|
|
{
|
|
FACETYPE *pFace;
|
|
|
|
// Check face index
|
|
CHECKV( iFaceIndex != -1 );
|
|
|
|
pFace = &gFacesData[ iFaceIndex ];
|
|
|
|
// Check for a valid slot!
|
|
CHECKV( pFace->fAllocated != FALSE );
|
|
|
|
pFace->fCanHandleInactiveNow = TRUE;
|
|
|
|
if ( !pFace->fDisabled )
|
|
{
|
|
SetAutoFaceInActive( iFaceIndex );
|
|
}
|
|
|
|
// If we are still talking, stop!
|
|
if ( pFace->fTalking )
|
|
{
|
|
// Call dialogue handler function
|
|
pFace->fTalking = FALSE;
|
|
|
|
HandleDialogueEnd( pFace );
|
|
}
|
|
|
|
// Delete vo
|
|
DeleteVideoObjectFromIndex( pFace->uiVideoObject );
|
|
|
|
// Set uncallocated
|
|
pFace->fAllocated = FALSE;
|
|
|
|
RecountFaces( );
|
|
|
|
}
|
|
|
|
void SetAutoFaceActiveFromSoldier( UINT32 uiDisplayBuffer, UINT32 uiRestoreBuffer, UINT8 ubSoldierID , UINT16 usFaceX, UINT16 usFaceY )
|
|
{
|
|
if( ubSoldierID == NOBODY )
|
|
{
|
|
return;
|
|
}
|
|
|
|
SetAutoFaceActive( uiDisplayBuffer, uiRestoreBuffer, MercPtrs[ ubSoldierID ]->iFaceIndex, usFaceX, usFaceY );
|
|
|
|
}
|
|
|
|
void GetFaceRelativeCoordinates( FACETYPE *pFace, UINT16 *pusEyesX, UINT16 *pusEyesY, UINT16 *pusMouthX, UINT16 *pusMouthY )
|
|
{
|
|
UINT16 usMercProfileID;
|
|
UINT16 usEyesX;
|
|
UINT16 usEyesY;
|
|
UINT16 usMouthX;
|
|
UINT16 usMouthY;
|
|
INT32 cnt;
|
|
|
|
usMercProfileID = pFace->ubCharacterNum;
|
|
|
|
//Take eyes x,y from profile unless we are an RPC and we are small faced.....
|
|
usEyesX = gMercProfiles[ usMercProfileID ].usEyesX;
|
|
usEyesY = gMercProfiles[ usMercProfileID ].usEyesY;
|
|
usMouthY = gMercProfiles[ usMercProfileID ].usMouthY;
|
|
usMouthX = gMercProfiles[ usMercProfileID ].usMouthX;
|
|
|
|
//if( usMercProfileID == TEX && gMercProfiles[ TEX ].bSkillTrait2 == CAMOUFLAGED )
|
|
//{
|
|
// usEyesX = 13;
|
|
// usEyesY = 34;
|
|
// usMouthX = 13;
|
|
// usMouthY = 55;
|
|
//}
|
|
|
|
// Use some other values for x,y, base on if we are a RPC!
|
|
if ( !( pFace->uiFlags & FACE_BIGFACE ) ||( pFace->uiFlags & FACE_FORCE_SMALL ))
|
|
{
|
|
if (usMercProfileID == TEX)
|
|
{
|
|
// 3, 6, 3, 23, // Tex ( 64 )
|
|
usEyesX = 3;
|
|
usEyesY = 6;
|
|
usMouthX = 3;
|
|
usMouthY = 23;
|
|
}
|
|
else if (usMercProfileID == BIGGENS)
|
|
{
|
|
// 5, 6, 5, 25, // Biggens ( 61 )
|
|
usEyesX = 5;
|
|
usEyesY = 6;
|
|
usMouthX = 5;
|
|
usMouthY = 25;
|
|
|
|
}
|
|
// Are we a recruited merc? .. or small?
|
|
else if( ( gMercProfiles[ usMercProfileID ].ubMiscFlags & ( PROFILE_MISC_FLAG_RECRUITED | PROFILE_MISC_FLAG_EPCACTIVE ) ) ||( pFace->uiFlags & FACE_FORCE_SMALL ) )
|
|
{
|
|
// Loop through all values of availible merc IDs to find ours!
|
|
for ( cnt = 0; cnt < ubRPCNumSmallFaceValues; cnt++ )
|
|
{
|
|
// We've found one!
|
|
if ( gubRPCSmallFaceProfileNum[ cnt ] == usMercProfileID )
|
|
{
|
|
usEyesX = gRPCSmallFaceValues[ cnt ].bEyesX;
|
|
usEyesY = gRPCSmallFaceValues[ cnt ].bEyesY;
|
|
usMouthY = gRPCSmallFaceValues[ cnt ].bMouthY;
|
|
usMouthX = gRPCSmallFaceValues[ cnt ].bMouthX;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
(*pusEyesX) = usEyesX;
|
|
(*pusEyesY) = usEyesY;
|
|
(*pusMouthX) = usMouthX;
|
|
(*pusMouthY) = usMouthY;
|
|
|
|
}
|
|
|
|
|
|
void SetAutoFaceActive( UINT32 uiDisplayBuffer, UINT32 uiRestoreBuffer, INT32 iFaceIndex , UINT16 usFaceX, UINT16 usFaceY )
|
|
{
|
|
UINT16 usEyesX;
|
|
UINT16 usEyesY;
|
|
UINT16 usMouthX;
|
|
UINT16 usMouthY;
|
|
FACETYPE *pFace;
|
|
|
|
// Check face index
|
|
CHECKV( iFaceIndex != -1 );
|
|
|
|
pFace = &gFacesData[ iFaceIndex ];
|
|
|
|
GetFaceRelativeCoordinates( pFace, &usEyesX, &usEyesY, &usMouthX, &usMouthY );
|
|
|
|
InternalSetAutoFaceActive( uiDisplayBuffer, uiRestoreBuffer, iFaceIndex , usFaceX, usFaceY, usEyesX, usEyesY, usMouthX, usMouthY );
|
|
|
|
}
|
|
|
|
|
|
void InternalSetAutoFaceActive( UINT32 uiDisplayBuffer, UINT32 uiRestoreBuffer, INT32 iFaceIndex , UINT16 usFaceX, UINT16 usFaceY, UINT16 usEyesX, UINT16 usEyesY, UINT16 usMouthX, UINT16 usMouthY )
|
|
{
|
|
UINT16 usMercProfileID;
|
|
FACETYPE *pFace;
|
|
VSURFACE_DESC vs_desc;
|
|
UINT16 usWidth;
|
|
UINT16 usHeight;
|
|
UINT8 ubBitDepth;
|
|
|
|
// Check face index
|
|
CHECKV( iFaceIndex != -1 );
|
|
|
|
pFace = &gFacesData[ iFaceIndex ];
|
|
|
|
// IF we are already being contained elsewhere, return without doing anything!
|
|
|
|
// ATE: Don't allow another activity from setting active....
|
|
if ( pFace->uiFlags & FACE_INACTIVE_HANDLED_ELSEWHERE )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Check if we are active already, remove if so!
|
|
if ( pFace->fDisabled )
|
|
{
|
|
SetAutoFaceInActive( iFaceIndex );
|
|
}
|
|
|
|
if ( uiRestoreBuffer == FACE_AUTO_RESTORE_BUFFER )
|
|
{
|
|
// BUILD A BUFFER
|
|
GetCurrentVideoSettings( &usWidth, &usHeight, &ubBitDepth );
|
|
// OK, ignore screen widths, height, only use BPP
|
|
vs_desc.fCreateFlags = VSURFACE_CREATE_DEFAULT | VSURFACE_SYSTEM_MEM_USAGE;
|
|
vs_desc.usWidth = pFace->usFaceWidth;
|
|
vs_desc.usHeight = pFace->usFaceHeight;
|
|
vs_desc.ubBitDepth = ubBitDepth;
|
|
|
|
pFace->fAutoRestoreBuffer = TRUE;
|
|
|
|
CHECKV( AddVideoSurface( &vs_desc, &(pFace->uiAutoRestoreBuffer) ) );
|
|
}
|
|
else
|
|
{
|
|
pFace->fAutoRestoreBuffer = FALSE;
|
|
pFace->uiAutoRestoreBuffer = uiRestoreBuffer;
|
|
}
|
|
|
|
if ( uiDisplayBuffer == FACE_AUTO_DISPLAY_BUFFER )
|
|
{
|
|
// BUILD A BUFFER
|
|
GetCurrentVideoSettings( &usWidth, &usHeight, &ubBitDepth );
|
|
// OK, ignore screen widths, height, only use BPP
|
|
vs_desc.fCreateFlags = VSURFACE_CREATE_DEFAULT | VSURFACE_SYSTEM_MEM_USAGE;
|
|
vs_desc.usWidth = pFace->usFaceWidth;
|
|
vs_desc.usHeight = pFace->usFaceHeight;
|
|
vs_desc.ubBitDepth = ubBitDepth;
|
|
|
|
pFace->fAutoDisplayBuffer = TRUE;
|
|
|
|
CHECKV( AddVideoSurface( &vs_desc, &(pFace->uiAutoDisplayBuffer) ) );
|
|
}
|
|
else
|
|
{
|
|
pFace->fAutoDisplayBuffer = FALSE;
|
|
pFace->uiAutoDisplayBuffer = uiDisplayBuffer;
|
|
}
|
|
|
|
|
|
usMercProfileID = pFace->ubCharacterNum;
|
|
|
|
pFace->usFaceX = usFaceX;
|
|
pFace->usFaceY = usFaceY;
|
|
pFace->fCanHandleInactiveNow = FALSE;
|
|
|
|
|
|
//Take eyes x,y from profile unless we are an RPC and we are small faced.....
|
|
pFace->usEyesX = usEyesX + usFaceX;
|
|
pFace->usEyesY = usEyesY + usFaceY;
|
|
pFace->usMouthY = usMouthY + usFaceY;
|
|
pFace->usMouthX = usMouthX + usFaceX;
|
|
|
|
// Save offset values
|
|
pFace->usEyesOffsetX = usEyesX;
|
|
pFace->usEyesOffsetY = usEyesY;
|
|
pFace->usMouthOffsetY = usMouthY;
|
|
pFace->usMouthOffsetX = usMouthX;
|
|
|
|
|
|
if ( pFace->usEyesY == usFaceY || pFace->usMouthY == usFaceY )
|
|
{
|
|
pFace->fInvalidAnim = TRUE;
|
|
}
|
|
|
|
pFace->fDisabled = FALSE;
|
|
pFace->uiLastBlink = GetJA2Clock();
|
|
pFace->uiLastExpression = GetJA2Clock();
|
|
pFace->uiEyelast = GetJA2Clock();
|
|
pFace->fStartFrame = TRUE;
|
|
|
|
// Are we a soldier?
|
|
if ( pFace->ubSoldierID != NOBODY )
|
|
{
|
|
pFace->bOldSoldierLife = MercPtrs[ pFace->ubSoldierID ]->bLife;
|
|
}
|
|
}
|
|
|
|
|
|
void SetAutoFaceInActiveFromSoldier( UINT8 ubSoldierID )
|
|
{
|
|
// Check for valid soldier
|
|
CHECKV( ubSoldierID != NOBODY );
|
|
|
|
SetAutoFaceInActive( MercPtrs[ ubSoldierID ]->iFaceIndex );
|
|
}
|
|
|
|
|
|
void SetAutoFaceInActive(INT32 iFaceIndex )
|
|
{
|
|
FACETYPE *pFace;
|
|
SOLDIERTYPE *pSoldier;
|
|
|
|
// Check face index
|
|
CHECKV( iFaceIndex != -1 );
|
|
|
|
pFace = &gFacesData[ iFaceIndex ];
|
|
|
|
// Check for a valid slot!
|
|
CHECKV( pFace->fAllocated != FALSE );
|
|
|
|
|
|
// Turn off some flags
|
|
if ( pFace->uiFlags & FACE_INACTIVE_HANDLED_ELSEWHERE )
|
|
{
|
|
if ( !pFace->fCanHandleInactiveNow )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( pFace->uiFlags & FACE_MAKEACTIVE_ONCE_DONE )
|
|
{
|
|
//
|
|
if ( pFace->ubSoldierID != NOBODY )
|
|
{
|
|
pSoldier = MercPtrs[ pFace->ubSoldierID ];
|
|
|
|
// IF we are in tactical
|
|
if ( pSoldier->bAssignment == iCurrentTacticalSquad && guiCurrentScreen == GAME_SCREEN )
|
|
{
|
|
// Make the interfac panel dirty..
|
|
// This will dirty the panel next frame...
|
|
gfRerenderInterfaceFromHelpText = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( pFace->fAutoRestoreBuffer )
|
|
{
|
|
DeleteVideoSurfaceFromIndex( pFace->uiAutoRestoreBuffer );
|
|
}
|
|
|
|
if ( pFace->fAutoDisplayBuffer )
|
|
{
|
|
DeleteVideoSurfaceFromIndex( pFace->uiAutoDisplayBuffer );
|
|
}
|
|
|
|
if ( pFace->iVideoOverlay != -1 )
|
|
{
|
|
RemoveVideoOverlay( pFace->iVideoOverlay );
|
|
pFace->iVideoOverlay = -1;
|
|
}
|
|
|
|
// Turn off some flags
|
|
pFace->uiFlags &= ( ~FACE_INACTIVE_HANDLED_ELSEWHERE );
|
|
|
|
// Disable!
|
|
pFace->fDisabled = TRUE;
|
|
|
|
}
|
|
|
|
|
|
void SetAllAutoFacesInactive( )
|
|
{
|
|
UINT32 uiCount;
|
|
FACETYPE *pFace;
|
|
|
|
for ( uiCount = 0; uiCount < guiNumFaces; uiCount++ )
|
|
{
|
|
if ( gFacesData[ uiCount ].fAllocated )
|
|
{
|
|
pFace = &gFacesData[ uiCount ];
|
|
|
|
SetAutoFaceInActive( uiCount );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void BlinkAutoFace( INT32 iFaceIndex )
|
|
{
|
|
FACETYPE *pFace;
|
|
INT16 sFrame;
|
|
BOOLEAN fDoBlink = FALSE;
|
|
|
|
if ( gFacesData[ iFaceIndex ].fAllocated && !gFacesData[ iFaceIndex ].fDisabled && !gFacesData[ iFaceIndex ].fInvalidAnim )
|
|
{
|
|
pFace = &gFacesData[ iFaceIndex ];
|
|
|
|
// CHECK IF BUDDY IS DEAD, UNCONSCIOUS, ASLEEP, OR POW!
|
|
if ( pFace->ubSoldierID != NOBODY )
|
|
{
|
|
if ( ( MercPtrs[ pFace->ubSoldierID ]->bLife < OKLIFE ) ||
|
|
( MercPtrs[ pFace->ubSoldierID ]->fMercAsleep == TRUE ) ||
|
|
( MercPtrs[ pFace->ubSoldierID ]->bAssignment == ASSIGNMENT_POW ) )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( pFace->ubExpression == NO_EXPRESSION )
|
|
{
|
|
// Get Delay time, if the first frame, use a different delay
|
|
if ( ( GetJA2Clock() - pFace->uiLastBlink ) > pFace->uiBlinkFrequency )
|
|
{
|
|
pFace->uiLastBlink = GetJA2Clock();
|
|
pFace->ubExpression = BLINKING;
|
|
pFace->uiEyelast = GetJA2Clock();
|
|
}
|
|
|
|
if ( pFace->fAnimatingTalking )
|
|
{
|
|
if ( ( GetJA2Clock() - pFace->uiLastExpression ) > pFace->uiExpressionFrequency )
|
|
{
|
|
pFace->uiLastExpression = GetJA2Clock();
|
|
|
|
if ( Random( 2 ) == 0 )
|
|
{
|
|
pFace->ubExpression = ANGRY;
|
|
}
|
|
else
|
|
{
|
|
pFace->ubExpression = SURPRISED;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( pFace->ubExpression != NO_EXPRESSION )
|
|
{
|
|
if ( pFace->fStartFrame )
|
|
{
|
|
if ( ( GetJA2Clock() - pFace->uiEyelast ) > pFace->uiEyeDelay ) //> Random( 10000 ) )
|
|
{
|
|
fDoBlink = TRUE;
|
|
pFace->fStartFrame = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( ( GetJA2Clock() - pFace->uiEyelast ) > pFace->uiEyeDelay )
|
|
{
|
|
fDoBlink = TRUE;
|
|
}
|
|
}
|
|
|
|
// Are we going to blink?
|
|
if ( fDoBlink )
|
|
{
|
|
pFace->uiEyelast = GetJA2Clock();
|
|
|
|
// Adjust
|
|
NewEye( pFace );
|
|
|
|
sFrame = pFace->sEyeFrame;
|
|
|
|
if ( sFrame >= 5 )
|
|
{
|
|
sFrame = 4;
|
|
}
|
|
|
|
if ( sFrame > 0 )
|
|
{
|
|
// Blit Accordingly!
|
|
BltVideoObjectFromIndex( pFace->uiAutoDisplayBuffer, pFace->uiVideoObject, (INT16)( sFrame ), pFace->usEyesX, pFace->usEyesY, VO_BLT_SRCTRANSPARENCY, NULL );
|
|
|
|
if ( pFace->uiAutoDisplayBuffer == FRAME_BUFFER )
|
|
{
|
|
InvalidateRegion( pFace->usEyesX, pFace->usEyesY, pFace->usEyesX + pFace->usEyesWidth, pFace->usEyesY + pFace->usEyesHeight );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//RenderFace( uiDestBuffer , uiCount );
|
|
pFace->ubExpression = NO_EXPRESSION;
|
|
// Update rects just for eyes
|
|
|
|
if ( pFace->uiAutoRestoreBuffer == guiSAVEBUFFER )
|
|
{
|
|
FaceRestoreSavedBackgroundRect( iFaceIndex, pFace->usEyesX, pFace->usEyesY, pFace->usEyesX, pFace->usEyesY, pFace->usEyesWidth, pFace->usEyesHeight );
|
|
}
|
|
else
|
|
{
|
|
FaceRestoreSavedBackgroundRect( iFaceIndex, pFace->usEyesX, pFace->usEyesY, pFace->usEyesOffsetX, pFace->usEyesOffsetY, pFace->usEyesWidth, pFace->usEyesHeight );
|
|
}
|
|
|
|
}
|
|
|
|
HandleRenderFaceAdjustments( pFace, TRUE, FALSE, 0, pFace->usFaceX, pFace->usFaceY, pFace->usEyesX, pFace->usEyesY );
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void HandleFaceHilights( FACETYPE *pFace, UINT32 uiBuffer, INT16 sFaceX, INT16 sFaceY )
|
|
{
|
|
UINT32 uiDestPitchBYTES;
|
|
UINT8 *pDestBuf;
|
|
UINT16 usLineColor;
|
|
INT32 iFaceIndex;
|
|
|
|
iFaceIndex = pFace->iID;
|
|
|
|
if ( !gFacesData[ iFaceIndex ].fDisabled )
|
|
{
|
|
if ( pFace->uiAutoDisplayBuffer == FRAME_BUFFER && guiCurrentScreen == GAME_SCREEN )
|
|
{
|
|
// If we are highlighted, do this now!
|
|
if ( ( pFace->uiFlags & FACE_SHOW_WHITE_HILIGHT ) )
|
|
{
|
|
// Lock buffer
|
|
pDestBuf = LockVideoSurface( uiBuffer, &uiDestPitchBYTES );
|
|
SetClippingRegionAndImageWidth( uiDestPitchBYTES, sFaceX-2, sFaceY-1, sFaceX + pFace->usFaceWidth + 4, sFaceY + pFace->usFaceHeight + 4 );
|
|
|
|
usLineColor = Get16BPPColor( FROMRGB( 255, 255, 255 ) );
|
|
RectangleDraw( TRUE, (sFaceX - 2 ), (sFaceY - 1),sFaceX + pFace->usFaceWidth + 1, sFaceY + pFace->usFaceHeight , usLineColor, pDestBuf );
|
|
|
|
SetClippingRegionAndImageWidth( uiDestPitchBYTES, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
|
|
|
|
UnLockVideoSurface( uiBuffer );
|
|
}
|
|
else if ( ( pFace->uiFlags & FACE_SHOW_MOVING_HILIGHT ) )
|
|
{
|
|
if ( pFace->ubSoldierID != NOBODY )
|
|
{
|
|
if ( MercPtrs[ pFace->ubSoldierID ]->bLife >= OKLIFE )
|
|
{
|
|
// Lock buffer
|
|
pDestBuf = LockVideoSurface( uiBuffer, &uiDestPitchBYTES );
|
|
SetClippingRegionAndImageWidth( uiDestPitchBYTES, sFaceX-2, sFaceY-1, sFaceX + pFace->usFaceWidth + 4, sFaceY + pFace->usFaceHeight + 4 );
|
|
|
|
if ( MercPtrs[ pFace->ubSoldierID ]->bStealthMode )
|
|
{
|
|
usLineColor = Get16BPPColor( FROMRGB( 158, 158, 12 ) );
|
|
}
|
|
else
|
|
{
|
|
usLineColor = Get16BPPColor( FROMRGB( 8, 12, 118 ) );
|
|
}
|
|
RectangleDraw( TRUE, (sFaceX - 2 ), (sFaceY - 1),sFaceX + pFace->usFaceWidth + 1, sFaceY + pFace->usFaceHeight , usLineColor, pDestBuf );
|
|
|
|
SetClippingRegionAndImageWidth( uiDestPitchBYTES, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
|
|
|
|
UnLockVideoSurface( uiBuffer );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// ATE: Zero out any highlight boxzes....
|
|
// Lock buffer
|
|
pDestBuf = LockVideoSurface( pFace->uiAutoDisplayBuffer, &uiDestPitchBYTES );
|
|
SetClippingRegionAndImageWidth( uiDestPitchBYTES, pFace->usFaceX-2, pFace->usFaceY-1, pFace->usFaceX + pFace->usFaceWidth + 4, pFace->usFaceY + pFace->usFaceHeight + 4 );
|
|
|
|
usLineColor = Get16BPPColor( FROMRGB( 0, 0, 0 ) );
|
|
RectangleDraw( TRUE, (pFace->usFaceX - 2 ), (pFace->usFaceY - 1), pFace->usFaceX + pFace->usFaceWidth + 1, pFace->usFaceY + pFace->usFaceHeight , usLineColor, pDestBuf );
|
|
|
|
SetClippingRegionAndImageWidth( uiDestPitchBYTES, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
|
|
|
|
UnLockVideoSurface( pFace->uiAutoDisplayBuffer );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if ( ( pFace->fCompatibleItems && !gFacesData[ iFaceIndex ].fDisabled ) )
|
|
{
|
|
// Lock buffer
|
|
pDestBuf = LockVideoSurface( uiBuffer, &uiDestPitchBYTES );
|
|
SetClippingRegionAndImageWidth( uiDestPitchBYTES, sFaceX-2, sFaceY-1, sFaceX + pFace->usFaceWidth+ 4, sFaceY + pFace->usFaceHeight + 4 );
|
|
|
|
usLineColor = Get16BPPColor( FROMRGB( 255, 0, 0 ) );
|
|
RectangleDraw( TRUE, (sFaceX - 2), (sFaceY - 1), sFaceX + pFace->usFaceWidth + 1, sFaceY + pFace->usFaceHeight , usLineColor, pDestBuf );
|
|
|
|
SetClippingRegionAndImageWidth( uiDestPitchBYTES, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
|
|
|
|
UnLockVideoSurface( uiBuffer );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void MouthAutoFace( INT32 iFaceIndex )
|
|
{
|
|
FACETYPE *pFace;
|
|
INT16 sFrame;
|
|
|
|
if ( gFacesData[ iFaceIndex ].fAllocated )
|
|
{
|
|
pFace = &gFacesData[ iFaceIndex ];
|
|
|
|
// Remove video overlay is present....
|
|
if ( pFace->uiFlags & FACE_DESTROY_OVERLAY )
|
|
{
|
|
//if ( pFace->iVideoOverlay != -1 )
|
|
//{
|
|
// if ( pFace->uiStopOverlayTimer != 0 )
|
|
// {
|
|
// if ( ( GetJA2Clock( ) - pFace->uiStopOverlayTimer ) > END_FACE_OVERLAY_DELAY )
|
|
// {
|
|
// RemoveVideoOverlay( pFace->iVideoOverlay );
|
|
// pFace->iVideoOverlay = -1;
|
|
// }
|
|
// }
|
|
//}
|
|
}
|
|
|
|
if ( pFace->fTalking )
|
|
{
|
|
if ( !gFacesData[ iFaceIndex ].fDisabled && !gFacesData[ iFaceIndex ].fInvalidAnim )
|
|
{
|
|
if ( pFace->fAnimatingTalking )
|
|
{
|
|
PollAudioGap( pFace->uiSoundID, &(pFace->GapList ) );
|
|
|
|
// Check if we have an audio gap
|
|
if ( pFace->GapList.audio_gap_active )
|
|
{
|
|
pFace->sMouthFrame = 0;
|
|
|
|
if ( pFace->uiAutoRestoreBuffer == guiSAVEBUFFER )
|
|
{
|
|
FaceRestoreSavedBackgroundRect( iFaceIndex, pFace->usMouthX, pFace->usMouthY, pFace->usMouthX, pFace->usMouthY, pFace->usMouthWidth, pFace->usMouthHeight );
|
|
}
|
|
else
|
|
{
|
|
FaceRestoreSavedBackgroundRect( iFaceIndex, pFace->usMouthX, pFace->usMouthY, pFace->usMouthOffsetX, pFace->usMouthOffsetY, pFace->usMouthWidth, pFace->usMouthHeight );
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// Get Delay time
|
|
if ( ( GetJA2Clock() - pFace->uiMouthlast ) > pFace->uiMouthDelay )
|
|
{
|
|
pFace->uiMouthlast = GetJA2Clock();
|
|
|
|
// Adjust
|
|
NewMouth( pFace );
|
|
|
|
sFrame = pFace->sMouthFrame;
|
|
|
|
if ( sFrame > 0 )
|
|
{
|
|
// Blit Accordingly!
|
|
BltVideoObjectFromIndex( pFace->uiAutoDisplayBuffer, pFace->uiVideoObject, (INT16)( sFrame + 4 ), pFace->usMouthX, pFace->usMouthY, VO_BLT_SRCTRANSPARENCY, NULL );
|
|
|
|
// Update rects
|
|
if ( pFace->uiAutoDisplayBuffer == FRAME_BUFFER )
|
|
{
|
|
InvalidateRegion( pFace->usMouthX, pFace->usMouthY, pFace->usMouthX + pFace->usMouthWidth, pFace->usMouthY + pFace->usMouthHeight );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//RenderFace( uiDestBuffer , uiCount );
|
|
//pFace->fTaking = FALSE;
|
|
// Update rects just for Mouth
|
|
if ( pFace->uiAutoRestoreBuffer == guiSAVEBUFFER )
|
|
{
|
|
FaceRestoreSavedBackgroundRect( iFaceIndex, pFace->usMouthX, pFace->usMouthY, pFace->usMouthX, pFace->usMouthY, pFace->usMouthWidth, pFace->usMouthHeight );
|
|
}
|
|
else
|
|
{
|
|
FaceRestoreSavedBackgroundRect( iFaceIndex, pFace->usMouthX, pFace->usMouthY, pFace->usMouthOffsetX, pFace->usMouthOffsetY, pFace->usMouthWidth, pFace->usMouthHeight );
|
|
}
|
|
|
|
}
|
|
|
|
HandleRenderFaceAdjustments( pFace, TRUE, FALSE, 0, pFace->usFaceX, pFace->usFaceY, pFace->usEyesX, pFace->usEyesY );
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !( pFace->uiFlags & FACE_INACTIVE_HANDLED_ELSEWHERE ) )
|
|
{
|
|
HandleFaceHilights( pFace, pFace->uiAutoDisplayBuffer, pFace->usFaceX, pFace->usFaceY );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void HandleTalkingAutoFace( INT32 iFaceIndex )
|
|
{
|
|
FACETYPE *pFace;
|
|
|
|
if ( gFacesData[ iFaceIndex ].fAllocated )
|
|
{
|
|
pFace = &gFacesData[ iFaceIndex ];
|
|
|
|
if ( pFace->fTalking )
|
|
{
|
|
// Check if we are done! ( Check this first! )
|
|
if ( pFace->fValidSpeech )
|
|
{
|
|
// Check if we have finished, set some flags for the final delay down if so!
|
|
if ( !SoundIsPlaying( pFace->uiSoundID ) && !pFace->fFinishTalking )
|
|
{
|
|
SetupFinalTalkingDelay( pFace );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Check if our delay is over
|
|
if ( !pFace->fFinishTalking )
|
|
{
|
|
if ( ( GetJA2Clock() - pFace->uiTalkingTimer ) > pFace->uiTalkingDuration )
|
|
{
|
|
// If here, setup for last delay!
|
|
SetupFinalTalkingDelay( pFace );
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now check for end of talking
|
|
if ( pFace->fFinishTalking )
|
|
{
|
|
if ( ( GetJA2Clock() - pFace->uiTalkingTimer ) > pFace->uiTalkingDuration )
|
|
{
|
|
pFace->fTalking = FALSE;
|
|
pFace->fAnimatingTalking = FALSE;
|
|
|
|
// Remove gap info
|
|
AudioGapListDone( &(pFace->GapList) );
|
|
|
|
// Remove video overlay is present....
|
|
if ( pFace->iVideoOverlay != -1 )
|
|
{
|
|
//if ( pFace->uiStopOverlayTimer == 0 )
|
|
//{
|
|
// pFace->uiStopOverlayTimer = GetJA2Clock();
|
|
//}
|
|
}
|
|
|
|
// Call dialogue handler function
|
|
HandleDialogueEnd( pFace );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Local function - uses these variables because they have already been validated
|
|
void SetFaceShade( SOLDIERTYPE *pSoldier, FACETYPE *pFace, BOOLEAN fExternBlit )
|
|
{
|
|
// Set to default
|
|
SetObjectHandleShade( pFace->uiVideoObject, FLASH_PORTRAIT_NOSHADE );
|
|
|
|
if ( pFace->iVideoOverlay == -1 && !fExternBlit )
|
|
{
|
|
if ( ( pSoldier->bActionPoints == 0 ) && !( gTacticalStatus.uiFlags & REALTIME ) && (gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
{
|
|
SetObjectHandleShade( pFace->uiVideoObject, FLASH_PORTRAIT_LITESHADE );
|
|
}
|
|
}
|
|
|
|
if ( pSoldier->bLife < OKLIFE )
|
|
{
|
|
SetObjectHandleShade( pFace->uiVideoObject, FLASH_PORTRAIT_DARKSHADE );
|
|
}
|
|
|
|
// ATE: Don't shade for damage if blitting extern face...
|
|
if ( !fExternBlit )
|
|
{
|
|
if ( pSoldier->fFlashPortrait == FLASH_PORTRAIT_START )
|
|
{
|
|
SetObjectHandleShade( pFace->uiVideoObject, pSoldier->bFlashPortraitFrame );
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOLEAN RenderAutoFaceFromSoldier( UINT8 ubSoldierID )
|
|
{
|
|
// Check for valid soldier
|
|
CHECKF( ubSoldierID != NOBODY );
|
|
|
|
return( RenderAutoFace( MercPtrs[ ubSoldierID ]->iFaceIndex ) );
|
|
}
|
|
|
|
void GetXYForIconPlacement( FACETYPE *pFace, UINT16 ubIndex, INT16 sFaceX, INT16 sFaceY, INT16 *psX, INT16 *psY )
|
|
{
|
|
INT16 sX, sY;
|
|
UINT16 usWidth, usHeight;
|
|
ETRLEObject *pTrav;
|
|
HVOBJECT hVObject;
|
|
|
|
|
|
// Get height, width of icon...
|
|
GetVideoObject( &hVObject, guiPORTRAITICONS );
|
|
pTrav = &(hVObject->pETRLEObject[ ubIndex ] );
|
|
usHeight = pTrav->usHeight;
|
|
usWidth = pTrav->usWidth;
|
|
|
|
sX = sFaceX + pFace->usFaceWidth - usWidth - 1;
|
|
sY = sFaceY + pFace->usFaceHeight - usHeight - 1;
|
|
|
|
*psX = sX;
|
|
*psY = sY;
|
|
}
|
|
|
|
void GetXYForRightIconPlacement( FACETYPE *pFace, UINT16 ubIndex, INT16 sFaceX, INT16 sFaceY, INT16 *psX, INT16 *psY, INT8 bNumIcons )
|
|
{
|
|
INT16 sX, sY;
|
|
UINT16 usWidth, usHeight;
|
|
ETRLEObject *pTrav;
|
|
HVOBJECT hVObject;
|
|
|
|
|
|
// Get height, width of icon...
|
|
GetVideoObject( &hVObject, guiPORTRAITICONS );
|
|
pTrav = &(hVObject->pETRLEObject[ ubIndex ] );
|
|
usHeight = pTrav->usHeight;
|
|
usWidth = pTrav->usWidth;
|
|
|
|
sX = sFaceX + ( usWidth * bNumIcons ) + 1;
|
|
sY = sFaceY + pFace->usFaceHeight - usHeight - 1;
|
|
|
|
*psX = sX;
|
|
*psY = sY;
|
|
}
|
|
|
|
|
|
|
|
void DoRightIcon( UINT32 uiRenderBuffer, FACETYPE *pFace, INT16 sFaceX, INT16 sFaceY, INT8 bNumIcons, INT8 sIconIndex )
|
|
{
|
|
INT16 sIconX, sIconY;
|
|
|
|
// Find X, y for placement
|
|
GetXYForRightIconPlacement( pFace, sIconIndex, sFaceX, sFaceY, &sIconX, &sIconY, bNumIcons );
|
|
BltVideoObjectFromIndex( uiRenderBuffer, guiPORTRAITICONS, sIconIndex, sIconX, sIconY, VO_BLT_SRCTRANSPARENCY, NULL );
|
|
}
|
|
|
|
|
|
void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLEAN fUseExternBuffer, UINT32 uiBuffer, INT16 sFaceX, INT16 sFaceY, UINT16 usEyesX, UINT16 usEyesY )
|
|
{
|
|
INT16 sIconX, sIconY;
|
|
INT16 sIconIndex=-1;
|
|
BOOLEAN fDoIcon = FALSE;
|
|
UINT32 uiRenderBuffer;
|
|
INT16 sPtsAvailable = 0;
|
|
UINT16 usMaximumPts = 0;
|
|
CHAR16 sString[ 32 ];
|
|
UINT16 usTextWidth;
|
|
BOOLEAN fAtGunRange = FALSE;
|
|
BOOLEAN fShowNumber = FALSE;
|
|
BOOLEAN fShowMaximum = FALSE;
|
|
SOLDIERTYPE *pSoldier;
|
|
INT16 sFontX, sFontY;
|
|
INT16 sX1, sY1, sY2, sX2;
|
|
UINT32 uiDestPitchBYTES;
|
|
UINT8 *pDestBuf;
|
|
UINT16 usLineColor;
|
|
INT8 bNumRightIcons = 0;
|
|
|
|
// If we are using an extern buffer...
|
|
if ( fUseExternBuffer )
|
|
{
|
|
uiRenderBuffer = uiBuffer;
|
|
}
|
|
else
|
|
{
|
|
if ( fDisplayBuffer )
|
|
{
|
|
uiRenderBuffer = pFace->uiAutoDisplayBuffer;
|
|
}
|
|
else
|
|
{
|
|
uiRenderBuffer = pFace->uiAutoRestoreBuffer;
|
|
|
|
if ( pFace->uiAutoRestoreBuffer == FACE_NO_RESTORE_BUFFER )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// BLIT HATCH
|
|
if ( pFace->ubSoldierID != NOBODY )
|
|
{
|
|
pSoldier = MercPtrs[ pFace->ubSoldierID ];
|
|
|
|
if ( ( MercPtrs[ pFace->ubSoldierID ]->bLife < CONSCIOUSNESS || MercPtrs[ pFace->ubSoldierID ]->fDeadPanel ) )
|
|
{
|
|
// Blit Closed eyes here!
|
|
BltVideoObjectFromIndex( uiRenderBuffer, pFace->uiVideoObject, 1, usEyesX, usEyesY, VO_BLT_SRCTRANSPARENCY, NULL );
|
|
|
|
// Blit hatch!
|
|
BltVideoObjectFromIndex( uiRenderBuffer, guiHATCH, 0, sFaceX, sFaceY, VO_BLT_SRCTRANSPARENCY, NULL );
|
|
}
|
|
|
|
if( MercPtrs[ pFace->ubSoldierID ]->fMercAsleep == TRUE )
|
|
{
|
|
// blit eyes closed
|
|
BltVideoObjectFromIndex( uiRenderBuffer, pFace->uiVideoObject, 1, usEyesX, usEyesY, VO_BLT_SRCTRANSPARENCY, NULL );
|
|
}
|
|
|
|
if ( ( pSoldier->uiStatusFlags & SOLDIER_DEAD ) )
|
|
{
|
|
// IF we are in the process of doing any deal/close animations, show face, not skill...
|
|
if ( !pSoldier->fClosePanel && !pSoldier->fDeadPanel && !pSoldier->fUIdeadMerc && !pSoldier->fUICloseMerc )
|
|
{
|
|
// Put close panel there
|
|
BltVideoObjectFromIndex( uiRenderBuffer, guiDEAD, 5, sFaceX, sFaceY, VO_BLT_SRCTRANSPARENCY, NULL );
|
|
|
|
// Blit hatch!
|
|
BltVideoObjectFromIndex( uiRenderBuffer, guiHATCH, 0, sFaceX, sFaceY, VO_BLT_SRCTRANSPARENCY, NULL );
|
|
}
|
|
}
|
|
|
|
// ATE: If talking in popup, don't do the other things.....
|
|
if ( pFace->fTalking && gTacticalStatus.uiFlags & IN_ENDGAME_SEQUENCE )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// ATE: Only do this, because we can be talking during an interrupt....
|
|
if ( ( pFace->uiFlags & FACE_INACTIVE_HANDLED_ELSEWHERE ) && !fUseExternBuffer )
|
|
{
|
|
// Don't do this if we are being handled elsewhere and it's not an extern buffer...
|
|
}
|
|
else
|
|
{
|
|
HandleFaceHilights( pFace, uiRenderBuffer, sFaceX, sFaceY );
|
|
|
|
#ifdef JA2BETAVERSION
|
|
if ( pSoldier->bOppCnt != 0 )
|
|
#else
|
|
if ( pSoldier->bOppCnt > 0 )
|
|
#endif
|
|
{
|
|
SetFontDestBuffer( uiRenderBuffer, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
|
|
|
|
swprintf( sString, L"%d", pSoldier->bOppCnt );
|
|
|
|
SetFont( TINYFONT1 );
|
|
SetFontForeground( FONT_DKRED );
|
|
SetFontBackground( FONT_NEARBLACK );
|
|
|
|
sX1 = (INT16)( sFaceX );
|
|
sY1 = (INT16)( sFaceY );
|
|
|
|
sX2 = sX1 + StringPixLength( sString, TINYFONT1 ) + 1;
|
|
sY2 = sY1 + GetFontHeight( TINYFONT1 ) - 1;
|
|
|
|
mprintf( (INT16)( sX1 + 1), (INT16)( sY1 - 1 ), sString );
|
|
SetFontDestBuffer( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
|
|
|
|
// Draw box
|
|
pDestBuf = LockVideoSurface( uiRenderBuffer, &uiDestPitchBYTES );
|
|
SetClippingRegionAndImageWidth( uiDestPitchBYTES, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
|
|
|
|
usLineColor = Get16BPPColor( FROMRGB( 105, 8, 9 ) );
|
|
RectangleDraw( TRUE, sX1, sY1, sX2, sY2, usLineColor, pDestBuf );
|
|
|
|
UnLockVideoSurface( uiRenderBuffer );
|
|
|
|
}
|
|
|
|
if ( MercPtrs[ pFace->ubSoldierID ]->bInSector && ( ( ( gTacticalStatus.ubCurrentTeam != OUR_TEAM ) || !OK_INTERRUPT_MERC( MercPtrs[ pFace->ubSoldierID ] ) ) && !gfHiddenInterrupt ) || ( ( gfSMDisableForItems && !gfInItemPickupMenu ) && gusSMCurrentMerc == pFace->ubSoldierID && gsCurInterfacePanel == SM_PANEL ) )
|
|
{
|
|
// Blit hatch!
|
|
BltVideoObjectFromIndex( uiRenderBuffer, guiHATCH, 0, sFaceX, sFaceY, VO_BLT_SRCTRANSPARENCY, NULL );
|
|
}
|
|
|
|
if ( !pFace->fDisabled && !pFace->fInvalidAnim )
|
|
{
|
|
// Render text above here if that's what was asked for
|
|
if ( pFace->fDisplayTextOver != FACE_NO_TEXT_OVER )
|
|
{
|
|
SetFont( TINYFONT1 );
|
|
SetFontBackground( FONT_MCOLOR_BLACK );
|
|
SetFontForeground( FONT_MCOLOR_WHITE );
|
|
|
|
SetFontDestBuffer( uiRenderBuffer, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
|
|
|
|
VarFindFontCenterCoordinates( sFaceX, sFaceY, pFace->usFaceWidth, pFace->usFaceHeight, TINYFONT1, &sFontX, &sFontY, pFace->zDisplayText );
|
|
|
|
if ( pFace->fDisplayTextOver == FACE_DRAW_TEXT_OVER )
|
|
{
|
|
gprintfinvalidate( sFontX, sFontY, pFace->zDisplayText );
|
|
mprintf( sFontX, sFontY, pFace->zDisplayText );
|
|
}
|
|
else if ( pFace->fDisplayTextOver == FACE_ERASE_TEXT_OVER )
|
|
{
|
|
gprintfRestore( sFontX, sFontY, pFace->zDisplayText );
|
|
pFace->fDisplayTextOver = FACE_NO_TEXT_OVER;
|
|
}
|
|
|
|
SetFontDestBuffer( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Check if a robot and is not controlled....
|
|
if ( MercPtrs[ pFace->ubSoldierID ]->uiStatusFlags & SOLDIER_ROBOT )
|
|
{
|
|
if ( !CanRobotBeControlled( MercPtrs[ pFace->ubSoldierID ] ) )
|
|
{
|
|
// Not controlled robot
|
|
sIconIndex = 5;
|
|
fDoIcon = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( ControllingRobot( MercPtrs[ pFace->ubSoldierID ] ) )
|
|
{
|
|
// controlling robot
|
|
sIconIndex = 4;
|
|
fDoIcon = TRUE;
|
|
}
|
|
|
|
// If blind...
|
|
if ( MercPtrs[ pFace->ubSoldierID ]->bBlindedCounter > 0 )
|
|
{
|
|
DoRightIcon( uiRenderBuffer, pFace, sFaceX, sFaceY, bNumRightIcons, 6 );
|
|
bNumRightIcons++;
|
|
}
|
|
|
|
if ( MercPtrs[ pFace->ubSoldierID ]->bDrugEffect[ DRUG_TYPE_ADRENALINE ] )
|
|
{
|
|
DoRightIcon( uiRenderBuffer, pFace, sFaceX, sFaceY, bNumRightIcons, 7 );
|
|
bNumRightIcons++;
|
|
}
|
|
|
|
if ( GetDrunkLevel( MercPtrs[ pFace->ubSoldierID ] ) != SOBER )
|
|
{
|
|
DoRightIcon( uiRenderBuffer, pFace, sFaceX, sFaceY, bNumRightIcons, 8 );
|
|
bNumRightIcons++;
|
|
}
|
|
|
|
|
|
switch( pSoldier->bAssignment )
|
|
{
|
|
case DOCTOR:
|
|
|
|
sIconIndex = 1;
|
|
fDoIcon = TRUE;
|
|
sPtsAvailable = CalculateHealingPointsForDoctor( MercPtrs[ pFace->ubSoldierID ], &usMaximumPts, FALSE );
|
|
fShowNumber = TRUE;
|
|
fShowMaximum = TRUE;
|
|
|
|
// divide both amounts by 10 to make the displayed numbers a little more user-palatable (smaller)
|
|
sPtsAvailable = ( sPtsAvailable + 5 ) / 10;
|
|
usMaximumPts = ( usMaximumPts + 5 ) / 10;
|
|
break;
|
|
|
|
case PATIENT:
|
|
|
|
sIconIndex = 2;
|
|
fDoIcon = TRUE;
|
|
// show current health / maximum health
|
|
sPtsAvailable = MercPtrs[ pFace->ubSoldierID ]->bLife;
|
|
usMaximumPts = MercPtrs[ pFace->ubSoldierID ]->bLifeMax;
|
|
fShowNumber = TRUE;
|
|
fShowMaximum = TRUE;
|
|
break;
|
|
|
|
case TRAIN_SELF:
|
|
case TRAIN_TOWN:
|
|
case TRAIN_TEAMMATE:
|
|
case TRAIN_BY_OTHER:
|
|
sIconIndex = 3;
|
|
fDoIcon = TRUE;
|
|
fShowNumber = TRUE;
|
|
fShowMaximum = TRUE;
|
|
// there could be bonus pts for training at gun range
|
|
if ( ( MercPtrs[ pFace->ubSoldierID ]->sSectorX == 13) && (MercPtrs[ pFace->ubSoldierID ]->sSectorY == MAP_ROW_H) && (MercPtrs[ pFace->ubSoldierID ]->bSectorZ == 0) )
|
|
{
|
|
fAtGunRange = TRUE;
|
|
}
|
|
|
|
switch( MercPtrs[ pFace->ubSoldierID ]->bAssignment )
|
|
{
|
|
case( TRAIN_SELF ):
|
|
sPtsAvailable = GetSoldierTrainingPts( MercPtrs[ pFace->ubSoldierID ], MercPtrs[ pFace->ubSoldierID ]->bTrainStat, fAtGunRange, &usMaximumPts );
|
|
break;
|
|
case( TRAIN_BY_OTHER ):
|
|
sPtsAvailable = GetSoldierStudentPts( MercPtrs[ pFace->ubSoldierID ], MercPtrs[ pFace->ubSoldierID ]->bTrainStat, fAtGunRange, &usMaximumPts );
|
|
break;
|
|
case( TRAIN_TOWN ):
|
|
sPtsAvailable = GetTownTrainPtsForCharacter( MercPtrs[ pFace->ubSoldierID ], &usMaximumPts );
|
|
// divide both amounts by 10 to make the displayed numbers a little more user-palatable (smaller)
|
|
sPtsAvailable = ( sPtsAvailable + 5 ) / 10;
|
|
usMaximumPts = ( usMaximumPts + 5 ) / 10;
|
|
break;
|
|
case( TRAIN_TEAMMATE ):
|
|
sPtsAvailable = GetBonusTrainingPtsDueToInstructor( MercPtrs[ pFace->ubSoldierID ], NULL , MercPtrs[ pFace->ubSoldierID ]->bTrainStat, fAtGunRange, &usMaximumPts );
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case REPAIR:
|
|
|
|
sIconIndex = 0;
|
|
fDoIcon = TRUE;
|
|
sPtsAvailable = CalculateRepairPointsForRepairman( MercPtrs[ pFace->ubSoldierID ], &usMaximumPts, FALSE );
|
|
fShowNumber = TRUE;
|
|
fShowMaximum = TRUE;
|
|
|
|
// check if we are repairing a vehicle
|
|
if ( Menptr[ pFace->ubSoldierID ].bVehicleUnderRepairID != -1 )
|
|
{
|
|
// reduce to a multiple of VEHICLE_REPAIR_POINTS_DIVISOR. This way skill too low will show up as 0 repair pts.
|
|
sPtsAvailable -= ( sPtsAvailable % VEHICLE_REPAIR_POINTS_DIVISOR );
|
|
usMaximumPts -= ( usMaximumPts % VEHICLE_REPAIR_POINTS_DIVISOR );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// Check for being serviced...
|
|
if ( MercPtrs[ pFace->ubSoldierID ]->ubServicePartner != NOBODY )
|
|
{
|
|
// Doctor...
|
|
sIconIndex = 1;
|
|
fDoIcon = TRUE;
|
|
}
|
|
|
|
if ( MercPtrs[ pFace->ubSoldierID ]->ubServiceCount != 0 )
|
|
{
|
|
// Patient
|
|
sIconIndex = 2;
|
|
fDoIcon = TRUE;
|
|
}
|
|
|
|
|
|
if ( fDoIcon )
|
|
{
|
|
// Find X, y for placement
|
|
GetXYForIconPlacement( pFace, sIconIndex, sFaceX, sFaceY, &sIconX, &sIconY );
|
|
BltVideoObjectFromIndex( uiRenderBuffer, guiPORTRAITICONS, sIconIndex, sIconX, sIconY, VO_BLT_SRCTRANSPARENCY, NULL );
|
|
|
|
// ATE: Show numbers only in mapscreen
|
|
if( fShowNumber )
|
|
{
|
|
SetFontDestBuffer( uiRenderBuffer, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
|
|
|
|
if ( fShowMaximum )
|
|
{
|
|
swprintf( sString, L"%d/%d", sPtsAvailable, usMaximumPts );
|
|
}
|
|
else
|
|
{
|
|
swprintf( sString, L"%d", sPtsAvailable );
|
|
}
|
|
|
|
usTextWidth = StringPixLength( sString, FONT10ARIAL );
|
|
usTextWidth += 1;
|
|
|
|
SetFont( FONT10ARIAL );
|
|
SetFontForeground( FONT_YELLOW );
|
|
SetFontBackground( FONT_BLACK );
|
|
|
|
mprintf( sFaceX + pFace->usFaceWidth - usTextWidth, ( INT16 )( sFaceY + 3 ), sString );
|
|
SetFontDestBuffer( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( pFace->ubCharacterNum == FATHER || pFace->ubCharacterNum == MICKY )
|
|
{
|
|
if ( gMercProfiles[ pFace->ubCharacterNum ].bNPCData >= 5 )
|
|
{
|
|
DoRightIcon( uiRenderBuffer, pFace, sFaceX, sFaceY, 0, 8 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN RenderAutoFace( INT32 iFaceIndex )
|
|
{
|
|
FACETYPE *pFace;
|
|
|
|
// Check face index
|
|
CHECKF( iFaceIndex != -1 );
|
|
|
|
pFace = &gFacesData[ iFaceIndex ];
|
|
|
|
// Check for a valid slot!
|
|
CHECKF( pFace->fAllocated != FALSE );
|
|
|
|
// Check for disabled guy!
|
|
CHECKF( pFace->fDisabled != TRUE );
|
|
|
|
// Set shade
|
|
if ( pFace->ubSoldierID != NOBODY )
|
|
{
|
|
SetFaceShade( MercPtrs[ pFace->ubSoldierID ], pFace, FALSE );
|
|
}
|
|
|
|
// Blit face to save buffer!
|
|
if ( pFace->uiAutoRestoreBuffer != FACE_NO_RESTORE_BUFFER )
|
|
{
|
|
if ( pFace->uiAutoRestoreBuffer == guiSAVEBUFFER )
|
|
{
|
|
BltVideoObjectFromIndex( pFace->uiAutoRestoreBuffer, pFace->uiVideoObject, 0, pFace->usFaceX, pFace->usFaceY, VO_BLT_SRCTRANSPARENCY, NULL );
|
|
}
|
|
else
|
|
{
|
|
BltVideoObjectFromIndex( pFace->uiAutoRestoreBuffer, pFace->uiVideoObject, 0, 0, 0, VO_BLT_SRCTRANSPARENCY, NULL );
|
|
}
|
|
}
|
|
|
|
HandleRenderFaceAdjustments( pFace, FALSE, FALSE, 0, pFace->usFaceX, pFace->usFaceY, pFace->usEyesX, pFace->usEyesY );
|
|
|
|
// Restore extern rect
|
|
if ( pFace->uiAutoRestoreBuffer == guiSAVEBUFFER )
|
|
{
|
|
FaceRestoreSavedBackgroundRect( iFaceIndex, (INT16)( pFace->usFaceX ), (INT16)( pFace->usFaceY ), (INT16)( pFace->usFaceX ), (INT16)( pFace->usFaceY ), ( INT16)( pFace->usFaceWidth ), (INT16)( pFace->usFaceHeight ) );
|
|
}
|
|
else
|
|
{
|
|
FaceRestoreSavedBackgroundRect( iFaceIndex, pFace->usFaceX, pFace->usFaceY, 0, 0, pFace->usFaceWidth, pFace->usFaceHeight );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN ExternRenderFaceFromSoldier( UINT32 uiBuffer, UINT8 ubSoldierID, INT16 sX, INT16 sY )
|
|
{
|
|
// Check for valid soldier
|
|
CHECKF( ubSoldierID != NOBODY );
|
|
|
|
return( ExternRenderFace( uiBuffer, MercPtrs[ ubSoldierID ]->iFaceIndex, sX, sY ) );
|
|
}
|
|
|
|
|
|
BOOLEAN ExternRenderFace( UINT32 uiBuffer, INT32 iFaceIndex, INT16 sX, INT16 sY )
|
|
{
|
|
UINT16 usEyesX;
|
|
UINT16 usEyesY;
|
|
UINT16 usMouthX;
|
|
UINT16 usMouthY;
|
|
FACETYPE *pFace;
|
|
|
|
// Check face index
|
|
CHECKF( iFaceIndex != -1 );
|
|
|
|
pFace = &gFacesData[ iFaceIndex ];
|
|
|
|
// Check for a valid slot!
|
|
CHECKF( pFace->fAllocated != FALSE );
|
|
|
|
// Here, any face can be rendered, even if disabled
|
|
|
|
// Set shade
|
|
if ( pFace->ubSoldierID != NOBODY )
|
|
{
|
|
SetFaceShade( MercPtrs[ pFace->ubSoldierID ], pFace , TRUE );
|
|
}
|
|
|
|
// Blit face to save buffer!
|
|
BltVideoObjectFromIndex( uiBuffer, pFace->uiVideoObject, 0, sX, sY, VO_BLT_SRCTRANSPARENCY, NULL );
|
|
|
|
GetFaceRelativeCoordinates( pFace, &usEyesX, &usEyesY, &usMouthX, &usMouthY );
|
|
|
|
HandleRenderFaceAdjustments( pFace, FALSE, TRUE, uiBuffer, sX, sY, ( UINT16)( sX + usEyesX ), ( UINT16)( sY + usEyesY ) );
|
|
|
|
// Restore extern rect
|
|
if ( uiBuffer == guiSAVEBUFFER )
|
|
{
|
|
RestoreExternBackgroundRect( sX, sY, pFace->usFaceWidth, pFace->usFaceWidth );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
void NewEye( FACETYPE *pFace )
|
|
{
|
|
|
|
switch(pFace->sEyeFrame)
|
|
{
|
|
case 0 : //pFace->sEyeFrame = (INT16)Random(2); // normal - can blink or frown
|
|
if ( pFace->ubExpression == ANGRY )
|
|
{
|
|
pFace->ubEyeWait = 0;
|
|
pFace->sEyeFrame = 3;
|
|
}
|
|
else if ( pFace->ubExpression == SURPRISED )
|
|
{
|
|
pFace->ubEyeWait = 0;
|
|
pFace->sEyeFrame = 4;
|
|
}
|
|
else
|
|
//if (pFace->sEyeFrame && Talk.talking && Talk.expression != DYING)
|
|
/// pFace->sEyeFrame = 3;
|
|
//else
|
|
pFace->sEyeFrame = 1;
|
|
break;
|
|
case 1 : // starting to blink - has to finish unless dying
|
|
//if (Talk.expression == DYING)
|
|
// pFace->sEyeFrame = 1;
|
|
//else
|
|
pFace->sEyeFrame = 2;
|
|
break;
|
|
case 2 : //pFace->sEyeFrame = (INT16)Random(2); // finishing blink - can go normal or frown
|
|
//if (pFace->sEyeFrame && Talk.talking)
|
|
// pFace->sEyeFrame = 3;
|
|
//else
|
|
// if (Talk.expression == ANGRY)
|
|
// pFace->sEyeFrame = 3;
|
|
// else
|
|
pFace->sEyeFrame = 0;
|
|
break;
|
|
|
|
case 3 : //pFace->sEyeFrame = 4; break; // frown
|
|
|
|
pFace->ubEyeWait++;
|
|
|
|
if ( pFace->ubEyeWait > 6 )
|
|
{
|
|
pFace->sEyeFrame = 0;
|
|
}
|
|
break;
|
|
|
|
case 4 :
|
|
|
|
pFace->ubEyeWait++;
|
|
|
|
if ( pFace->ubEyeWait > 6 )
|
|
{
|
|
pFace->sEyeFrame = 0;
|
|
}
|
|
break;
|
|
|
|
case 5 : pFace->sEyeFrame = 6;
|
|
|
|
pFace->sEyeFrame = 0;
|
|
break;
|
|
|
|
case 6 : pFace->sEyeFrame = 7; break;
|
|
case 7 : pFace->sEyeFrame = (INT16)Random(2); // can stop frowning or continue
|
|
//if (pFace->sEyeFrame && Talk.expression != DYING)
|
|
// pFace->sEyeFrame = 8;
|
|
//else
|
|
// pFace->sEyeFrame = 0;
|
|
//break;
|
|
case 8 : pFace->sEyeFrame = 9; break;
|
|
case 9 : pFace->sEyeFrame = 10; break;
|
|
case 10: pFace->sEyeFrame = 11; break;
|
|
case 11: pFace->sEyeFrame = 12; break;
|
|
case 12: pFace->sEyeFrame = 0; break;
|
|
}
|
|
}
|
|
|
|
|
|
void NewMouth( FACETYPE *pFace )
|
|
{
|
|
BOOLEAN OK = FALSE;
|
|
UINT16 sOld = pFace->sMouthFrame;
|
|
|
|
// if (audio_gap_active == 1)
|
|
// {
|
|
// Talk.mouth = 0;
|
|
// return;
|
|
// }
|
|
|
|
do
|
|
{
|
|
//Talk.mouth = random(4);
|
|
|
|
pFace->sMouthFrame = (INT16)Random(6);
|
|
|
|
if ( pFace->sMouthFrame > 3)
|
|
{
|
|
pFace->sMouthFrame = 0;
|
|
}
|
|
|
|
switch( sOld)
|
|
{
|
|
case 0 : if ( pFace->sMouthFrame != 0 )
|
|
OK = TRUE;
|
|
break;
|
|
case 1 : if ( pFace->sMouthFrame != 1 )
|
|
OK = TRUE;
|
|
break;
|
|
case 2 : if ( pFace->sMouthFrame != 2 )
|
|
OK = TRUE;
|
|
break;
|
|
case 3 : if ( pFace->sMouthFrame != 3 )
|
|
OK = TRUE;
|
|
break;
|
|
}
|
|
|
|
} while (!OK);
|
|
|
|
}
|
|
|
|
|
|
void HandleAutoFaces( )
|
|
{
|
|
UINT32 uiCount;
|
|
FACETYPE *pFace;
|
|
INT8 bLife;
|
|
INT8 bInSector;
|
|
INT8 bAPs;
|
|
BOOLEAN fRerender = FALSE;
|
|
BOOLEAN fHandleFace;
|
|
BOOLEAN fHandleUIHatch;
|
|
SOLDIERTYPE *pSoldier;
|
|
|
|
|
|
for ( uiCount = 0; uiCount < guiNumFaces; uiCount++ )
|
|
{
|
|
fRerender = FALSE;
|
|
fHandleFace = TRUE;
|
|
fHandleUIHatch = FALSE;
|
|
|
|
// OK, NOW, check if our bLife status has changed, re-render if so!
|
|
if ( gFacesData[ uiCount ].fAllocated )
|
|
{
|
|
pFace = &gFacesData[ uiCount ];
|
|
|
|
// Are we a soldier?
|
|
if ( pFace->ubSoldierID != NOBODY )
|
|
{
|
|
// Get Life now
|
|
pSoldier = MercPtrs[ pFace->ubSoldierID ];
|
|
bLife = pSoldier->bLife;
|
|
bInSector = pSoldier->bInSector;
|
|
bAPs = pSoldier->bActionPoints;
|
|
|
|
if ( pSoldier->ubID == gsSelectedGuy && gfUIHandleSelectionAboveGuy )
|
|
{
|
|
pFace->uiFlags |= FACE_SHOW_WHITE_HILIGHT;
|
|
}
|
|
else
|
|
{
|
|
pFace->uiFlags &= ( ~FACE_SHOW_WHITE_HILIGHT );
|
|
}
|
|
|
|
if ( pSoldier->sGridNo != pSoldier->sFinalDestination && pSoldier->sGridNo != NOWHERE )
|
|
{
|
|
pFace->uiFlags |= FACE_SHOW_MOVING_HILIGHT;
|
|
}
|
|
else
|
|
{
|
|
pFace->uiFlags &= ( ~FACE_SHOW_MOVING_HILIGHT );
|
|
}
|
|
|
|
if ( pSoldier->bStealthMode != pFace->bOldStealthMode )
|
|
{
|
|
fRerender = TRUE;
|
|
}
|
|
|
|
// Check if we have fallen below OKLIFE...
|
|
if ( bLife < OKLIFE && pFace->bOldSoldierLife >= OKLIFE )
|
|
{
|
|
fRerender = TRUE;
|
|
}
|
|
|
|
if ( bLife >= OKLIFE && pFace->bOldSoldierLife < OKLIFE )
|
|
{
|
|
fRerender = TRUE;
|
|
}
|
|
|
|
// Check if we have fallen below CONSCIOUSNESS
|
|
if ( bLife < CONSCIOUSNESS && pFace->bOldSoldierLife >= CONSCIOUSNESS )
|
|
{
|
|
fRerender = TRUE;
|
|
}
|
|
|
|
if ( bLife >= CONSCIOUSNESS && pFace->bOldSoldierLife < CONSCIOUSNESS )
|
|
{
|
|
fRerender = TRUE;
|
|
}
|
|
|
|
if ( pSoldier->bOppCnt != pFace->bOldOppCnt )
|
|
{
|
|
fRerender = TRUE;
|
|
}
|
|
|
|
// Check if assignment is idfferent....
|
|
if ( pSoldier->bAssignment != pFace->bOldAssignment )
|
|
{
|
|
pFace->bOldAssignment = pSoldier->bAssignment;
|
|
fRerender = TRUE;
|
|
}
|
|
|
|
// Check if we have fallen below CONSCIOUSNESS
|
|
if ( bAPs == 0 && pFace->bOldActionPoints > 0 )
|
|
{
|
|
fRerender = TRUE;
|
|
}
|
|
|
|
if ( bAPs > 0 && pFace->bOldActionPoints == 0 )
|
|
{
|
|
fRerender = TRUE;
|
|
}
|
|
|
|
if ( !( pFace->uiFlags & FACE_SHOW_WHITE_HILIGHT ) && pFace->fOldShowHighlight )
|
|
{
|
|
fRerender = TRUE;
|
|
}
|
|
|
|
if ( ( pFace->uiFlags & FACE_SHOW_WHITE_HILIGHT ) && !( pFace->fOldShowHighlight ) )
|
|
{
|
|
fRerender = TRUE;
|
|
}
|
|
|
|
if ( !( pFace->uiFlags & FACE_SHOW_MOVING_HILIGHT ) && pFace->fOldShowMoveHilight )
|
|
{
|
|
fRerender = TRUE;
|
|
}
|
|
|
|
if ( ( pFace->uiFlags & FACE_SHOW_MOVING_HILIGHT ) && !( pFace->fOldShowMoveHilight ) )
|
|
{
|
|
fRerender = TRUE;
|
|
}
|
|
|
|
if ( pFace->ubOldServiceCount != pSoldier->ubServiceCount )
|
|
{
|
|
fRerender = TRUE;
|
|
pFace->ubOldServiceCount = pSoldier->ubServiceCount;
|
|
}
|
|
|
|
if ( pFace->fOldCompatibleItems != pFace->fCompatibleItems || gfInItemPickupMenu || gpItemPointer != NULL )
|
|
{
|
|
fRerender = TRUE;
|
|
pFace->fOldCompatibleItems = pFace->fCompatibleItems;
|
|
}
|
|
|
|
|
|
if ( pFace->ubOldServicePartner != pSoldier->ubServicePartner )
|
|
{
|
|
fRerender = TRUE;
|
|
pFace->ubOldServicePartner = pSoldier->ubServicePartner;
|
|
}
|
|
|
|
pFace->fOldHandleUIHatch = fHandleUIHatch;
|
|
pFace->bOldSoldierLife = bLife;
|
|
pFace->bOldActionPoints = bAPs;
|
|
pFace->bOldStealthMode = pSoldier->bStealthMode;
|
|
pFace->bOldOppCnt = pSoldier->bOppCnt;
|
|
|
|
if ( pFace->uiFlags & FACE_SHOW_WHITE_HILIGHT )
|
|
{
|
|
pFace->fOldShowHighlight = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pFace->fOldShowHighlight = FALSE;
|
|
}
|
|
|
|
if ( pFace->uiFlags & FACE_SHOW_MOVING_HILIGHT )
|
|
{
|
|
pFace->fOldShowMoveHilight = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pFace->fOldShowMoveHilight = FALSE;
|
|
}
|
|
|
|
|
|
if ( pSoldier->fGettingHit && pSoldier->fFlashPortrait == FLASH_PORTRAIT_STOP )
|
|
{
|
|
pSoldier->fFlashPortrait = TRUE;
|
|
pSoldier->bFlashPortraitFrame = FLASH_PORTRAIT_STARTSHADE;
|
|
RESETTIMECOUNTER( pSoldier->PortraitFlashCounter, FLASH_PORTRAIT_DELAY );
|
|
fRerender = TRUE;
|
|
}
|
|
if ( pSoldier->fFlashPortrait == FLASH_PORTRAIT_START )
|
|
{
|
|
// Loop through flash values
|
|
if ( TIMECOUNTERDONE( pSoldier->PortraitFlashCounter, FLASH_PORTRAIT_DELAY ) )
|
|
{
|
|
RESETTIMECOUNTER( pSoldier->PortraitFlashCounter, FLASH_PORTRAIT_DELAY );
|
|
pSoldier->bFlashPortraitFrame++;
|
|
|
|
if ( pSoldier->bFlashPortraitFrame > FLASH_PORTRAIT_ENDSHADE )
|
|
{
|
|
pSoldier->bFlashPortraitFrame = FLASH_PORTRAIT_ENDSHADE;
|
|
|
|
if ( pSoldier->fGettingHit )
|
|
{
|
|
pSoldier->fFlashPortrait = FLASH_PORTRAIT_WAITING;
|
|
}
|
|
else
|
|
{
|
|
// Render face again!
|
|
pSoldier->fFlashPortrait = FLASH_PORTRAIT_STOP;
|
|
}
|
|
|
|
fRerender = TRUE;
|
|
}
|
|
}
|
|
}
|
|
// CHECK IF WE WERE WAITING FOR GETTING HIT TO FINISH!
|
|
if ( !pSoldier->fGettingHit && pSoldier->fFlashPortrait == FLASH_PORTRAIT_WAITING )
|
|
{
|
|
pSoldier->fFlashPortrait = FALSE;
|
|
fRerender = TRUE;
|
|
}
|
|
|
|
if ( pSoldier->fFlashPortrait == FLASH_PORTRAIT_START )
|
|
{
|
|
fRerender = TRUE;
|
|
}
|
|
|
|
if( pFace->uiFlags & FACE_REDRAW_WHOLE_FACE_NEXT_FRAME )
|
|
{
|
|
pFace->uiFlags &= ~FACE_REDRAW_WHOLE_FACE_NEXT_FRAME;
|
|
|
|
fRerender = TRUE;
|
|
}
|
|
|
|
if ( fInterfacePanelDirty == DIRTYLEVEL2 && guiCurrentScreen == GAME_SCREEN )
|
|
{
|
|
fRerender = TRUE;
|
|
}
|
|
|
|
if ( fRerender )
|
|
{
|
|
RenderAutoFace( uiCount );
|
|
}
|
|
|
|
if ( bLife < CONSCIOUSNESS )
|
|
{
|
|
fHandleFace = FALSE;
|
|
}
|
|
}
|
|
|
|
if ( fHandleFace )
|
|
{
|
|
BlinkAutoFace( uiCount );
|
|
}
|
|
|
|
MouthAutoFace( uiCount );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void HandleTalkingAutoFaces( )
|
|
{
|
|
UINT32 uiCount;
|
|
FACETYPE *pFace;
|
|
|
|
for ( uiCount = 0; uiCount < guiNumFaces; uiCount++ )
|
|
{
|
|
// OK, NOW, check if our bLife status has changed, re-render if so!
|
|
if ( gFacesData[ uiCount ].fAllocated )
|
|
{
|
|
pFace = &gFacesData[ uiCount ];
|
|
|
|
HandleTalkingAutoFace( uiCount );
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN FaceRestoreSavedBackgroundRect( INT32 iFaceIndex, INT16 sDestLeft, INT16 sDestTop, INT16 sSrcLeft, INT16 sSrcTop, INT16 sWidth, INT16 sHeight )
|
|
{
|
|
FACETYPE *pFace;
|
|
UINT32 uiDestPitchBYTES, uiSrcPitchBYTES;
|
|
UINT8 *pDestBuf, *pSrcBuf;
|
|
|
|
// Check face index
|
|
CHECKF( iFaceIndex != -1 );
|
|
|
|
pFace = &gFacesData[ iFaceIndex ];
|
|
|
|
// DOn't continue if we do not want the resotre to happen ( ei blitting entrie thing every frame...
|
|
if ( pFace->uiAutoRestoreBuffer == FACE_NO_RESTORE_BUFFER )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
pDestBuf = LockVideoSurface(pFace->uiAutoDisplayBuffer, &uiDestPitchBYTES);
|
|
pSrcBuf = LockVideoSurface( pFace->uiAutoRestoreBuffer, &uiSrcPitchBYTES);
|
|
|
|
Blt16BPPTo16BPP((UINT16 *)pDestBuf, uiDestPitchBYTES,
|
|
(UINT16 *)pSrcBuf, uiSrcPitchBYTES,
|
|
sDestLeft , sDestTop,
|
|
sSrcLeft , sSrcTop,
|
|
sWidth, sHeight);
|
|
|
|
UnLockVideoSurface(pFace->uiAutoDisplayBuffer);
|
|
UnLockVideoSurface(pFace->uiAutoRestoreBuffer);
|
|
|
|
// Add rect to frame buffer queue
|
|
if ( pFace->uiAutoDisplayBuffer == FRAME_BUFFER )
|
|
{
|
|
InvalidateRegionEx( sDestLeft - 2, sDestTop - 2, (sDestLeft + sWidth + 3), ( sDestTop + sHeight + 2 ), 0 );
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOLEAN SetFaceTalking( INT32 iFaceIndex, CHAR8 *zSoundFile, STR16 zTextString,
|
|
UINT32 usRate, UINT32 ubVolume, UINT32 ubLoops, UINT32 uiPan )
|
|
{
|
|
FACETYPE *pFace;
|
|
|
|
pFace = &gFacesData[ iFaceIndex ];
|
|
|
|
// Set face to talking
|
|
pFace->fTalking = TRUE;
|
|
pFace->fAnimatingTalking = TRUE;
|
|
pFace->fFinishTalking = FALSE;
|
|
|
|
if ( !AreInMeanwhile( ) )
|
|
{
|
|
TurnOnSectorLocator( pFace->ubCharacterNum );
|
|
}
|
|
|
|
// Play sample
|
|
if( gGameSettings.fOptions[ TOPTION_SPEECH ] )
|
|
pFace->uiSoundID = PlayJA2GapSample( zSoundFile, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN, &(pFace->GapList ) );
|
|
else
|
|
pFace->uiSoundID = SOUND_ERROR;
|
|
|
|
if ( pFace->uiSoundID != SOUND_ERROR )
|
|
{
|
|
pFace->fValidSpeech = TRUE;
|
|
|
|
pFace->uiTalkingFromVeryBeginningTimer = GetJA2Clock( );
|
|
}
|
|
else
|
|
{
|
|
pFace->fValidSpeech = FALSE;
|
|
|
|
// Set delay based on sound...
|
|
pFace->uiTalkingTimer = pFace->uiTalkingFromVeryBeginningTimer = GetJA2Clock( );
|
|
|
|
pFace->uiTalkingDuration = FindDelayForString( zTextString );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN ExternSetFaceTalking( INT32 iFaceIndex, UINT32 uiSoundID )
|
|
{
|
|
FACETYPE *pFace;
|
|
|
|
pFace = &gFacesData[ iFaceIndex ];
|
|
|
|
// Set face to talki ng
|
|
pFace->fTalking = TRUE;
|
|
pFace->fAnimatingTalking = TRUE;
|
|
pFace->fFinishTalking = FALSE;
|
|
pFace->fValidSpeech = TRUE;
|
|
|
|
pFace->uiSoundID = uiSoundID;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
void InternalShutupaYoFace( INT32 iFaceIndex, BOOLEAN fForce )
|
|
{
|
|
FACETYPE *pFace;
|
|
|
|
// Check face index
|
|
CHECKV( iFaceIndex != -1 );
|
|
|
|
pFace = &gFacesData[ iFaceIndex ];
|
|
|
|
if ( pFace->fTalking )
|
|
{
|
|
// OK, only do this if we have been talking for a min. amount fo time...
|
|
if ( ( GetJA2Clock( ) - pFace->uiTalkingFromVeryBeginningTimer ) < 500 && !fForce )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( pFace->uiSoundID != SOUND_ERROR )
|
|
{
|
|
SoundStop( pFace->uiSoundID );
|
|
}
|
|
|
|
// Remove gap info
|
|
AudioGapListDone( &(pFace->GapList) );
|
|
|
|
// Shutup mouth!
|
|
pFace->sMouthFrame = 0;
|
|
|
|
// ATE: Only change if active!
|
|
if ( !pFace->fDisabled )
|
|
{
|
|
if ( pFace->uiAutoRestoreBuffer == guiSAVEBUFFER )
|
|
{
|
|
FaceRestoreSavedBackgroundRect( iFaceIndex, pFace->usMouthX, pFace->usMouthY, pFace->usMouthX, pFace->usMouthY, pFace->usMouthWidth, pFace->usMouthHeight );
|
|
}
|
|
else
|
|
{
|
|
FaceRestoreSavedBackgroundRect( iFaceIndex, pFace->usMouthX, pFace->usMouthY, pFace->usMouthOffsetX, pFace->usMouthOffsetY, pFace->usMouthWidth, pFace->usMouthHeight );
|
|
}
|
|
}
|
|
// OK, smart guy, make sure this guy has finished talking,
|
|
// before attempting to end dialogue UI.
|
|
pFace->fTalking = FALSE;
|
|
|
|
// Call dialogue handler function
|
|
HandleDialogueEnd( pFace );
|
|
|
|
pFace->fTalking = FALSE;
|
|
pFace->fAnimatingTalking = FALSE;
|
|
|
|
gfUIWaitingForUserSpeechAdvance = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void ShutupaYoFace( INT32 iFaceIndex )
|
|
{
|
|
InternalShutupaYoFace( iFaceIndex, TRUE );
|
|
}
|
|
|
|
void SetupFinalTalkingDelay( FACETYPE *pFace )
|
|
{
|
|
pFace->fFinishTalking = TRUE;
|
|
|
|
pFace->fAnimatingTalking = FALSE;
|
|
|
|
pFace->uiTalkingTimer = GetJA2Clock( );
|
|
|
|
if ( gGameSettings.fOptions[ TOPTION_SUBTITLES ] )
|
|
{
|
|
//pFace->uiTalkingDuration = FINAL_TALKING_DURATION;
|
|
pFace->uiTalkingDuration = 300;
|
|
}
|
|
else
|
|
{
|
|
pFace->uiTalkingDuration = 300;
|
|
}
|
|
|
|
pFace->sMouthFrame = 0;
|
|
|
|
// Close mouth!
|
|
if ( !pFace->fDisabled )
|
|
{
|
|
if ( pFace->uiAutoRestoreBuffer == guiSAVEBUFFER )
|
|
{
|
|
FaceRestoreSavedBackgroundRect( pFace->iID, pFace->usMouthX, pFace->usMouthY, pFace->usMouthX, pFace->usMouthY, pFace->usMouthWidth, pFace->usMouthHeight );
|
|
}
|
|
else
|
|
{
|
|
FaceRestoreSavedBackgroundRect( pFace->iID, pFace->usMouthX, pFace->usMouthY, pFace->usMouthOffsetX, pFace->usMouthOffsetY, pFace->usMouthWidth, pFace->usMouthHeight );
|
|
}
|
|
}
|
|
|
|
// Setup flag to wait for advance ( because we have no text! )
|
|
if ( gGameSettings.fOptions[ TOPTION_KEY_ADVANCE_SPEECH ] && ( pFace->uiFlags & FACE_POTENTIAL_KEYWAIT ) )
|
|
{
|
|
|
|
// Check if we have had valid speech!
|
|
if ( !pFace->fValidSpeech || gGameSettings.fOptions[ TOPTION_SUBTITLES ] )
|
|
{
|
|
// Set false!
|
|
pFace->fFinishTalking = FALSE;
|
|
// Set waiting for advance to true!
|
|
gfUIWaitingForUserSpeechAdvance = TRUE;
|
|
}
|
|
}
|
|
|
|
// Set final delay!
|
|
pFace->fValidSpeech = FALSE;
|
|
|
|
|
|
}
|