Files
source/Ja2/Credits.cpp
T
2025-12-03 23:52:05 +02:00

1467 lines
35 KiB
C++

#include "types.h"
#include "Credits.h"
#include "vsurface.h"
#include "mousesystem.h"
#include "Text.h"
#include "WordWrap.h"
#include "video.h"
#include "Render Dirty.h"
#include "local.h"
#include "Utilities.h"
#include "WCheck.h"
#include "screenids.h"
#include "Font Control.h"
#include "Cursors.h"
#include "Font.h"
#include "sysutil.h"
#include "input.h"
#include "english.h"
#include "Encrypted File.h"
#include "random.h"
//externals
extern HVSURFACE ghFrameBuffer;
//local Defines
enum
{
CRDT_RENDER_NONE,
CRDT_RENDER_ALL,
};
//nnn
typedef struct _CRDT_NODE
{
UINT32 uiType; //the type of node
CHAR16 *pString; //string for the node if the node contains a string
UINT32 uiFlags; //various flags
INT16 sPosX; //position of the node on the screen if the node is displaying stuff
INT16 sPosY;
INT16 sOldPosX; //position of the node on the screen if the node is displaying stuff
INT16 sOldPosY;
INT16 sHeightOfString; //The height of the displayed string
BOOLEAN fDelete; //Delete this loop
UINT32 uiLastTime; // The last time the node was udated
UINT32 uiVideoSurfaceImage;
struct _CRDT_NODE *pPrev;
struct _CRDT_NODE *pNext;
} CRDT_NODE;
//type of credits
enum
{
CRDT_NODE_NONE,
CRDT_NODE_DEFAULT, // scrolls up and off the screen
};
//flags for the credits
//Flags:
#define CRDT_FLAG__TITLE 0x00000001
#define CRDT_FLAG__START_SECTION 0x00000002
#define CRDT_FLAG__END_SECTION 0x00000004
#define CRDT_NAME_OF_CREDIT_FILE "BINARYDATA\\Credits.edt"
#define CRDT_NAME_OF_MOD_CREDIT_FILE "BINARYDATA\\Credits_Mod.edt"
#define CREDITS_LINESIZE (80 * 2)
//
// Code tokens
//
//new codes:
#define CRDT_START_CODE '@'
#define CRDT_SEPARATION_CODE L","
#define CRDT_END_CODE L";"
#define CRDT_DELAY_BN_STRINGS_CODE 'D'
#define CRDT_DELAY_BN_SECTIONS_CODE 'B'
#define CRDT_SCROLL_SPEED 'S'
#define CRDT_FONT_JUSTIFICATION 'J'
#define CRDT_TITLE_FONT_COLOR 'C'
#define CRDT_ACTIVE_FONT_COLOR 'R'
//Flags:
#define CRDT_TITLE 'T'
#define CRDT_START_OF_SECTION '{'
#define CRDT_END_OF_SECTION '}'
#define CRDT_NAME_FONT FONT12ARIAL
#define CRDT_LINE_NODE_DISAPPEARS_AT 0
#define CRDT_WIDTH_OF_TEXT_AREA 210
#define CRDT_SCROLL_PIXEL_AMOUNT 1
#define CRDT_NODE_DELAY_AMOUNT 25
#define CRDT_DELAY_BN_NODES 750
#define CRDT_DELAY_BN_SECTIONS 2500
#define CRDT_SPACE_BN_SECTIONS 50
#define CRDT_SPACE_BN_NODES 12
#define CRDT_START_POS_Y (SCREEN_HEIGHT - 1)
#define CRDT_EYE_WIDTH 30
#define CRDT_EYE_HEIGHT 12
#define CRDT_EYES_CLOSED_TIME 150
//ddd
typedef struct
{
INT16 sX;
INT16 sY;
INT16 sWidth;
INT16 sHeight;
INT16 sEyeX;
INT16 sEyeY;
INT16 sMouthX;
INT16 sMouthY;
INT16 sBlinkFreq;
UINT32 uiLastBlinkTime;
UINT32 uiEyesClosedTime;
} CDRT_FACE;
CDRT_FACE gCreditFaces[] =
{
// x y w h
298, 137, 37, 49, 310, 157, 304, 170, 2500, 0, 0, //Camfield
348, 137, 43, 47, 354, 153, 354, 153, 3700, 0, 0, //Shawn
407, 132, 30, 50, 408, 151, 410, 164, 3000, 0, 0, //Kris
443, 131, 30, 50, 447, 151, 446, 161, 4000, 0, 0, //Ian
487, 136, 43, 50, 493, 155, 493, 155, 3500, 0, 0, //Linda
529, 145, 43, 50, 536, 164, 536, 164, 4000, 0, 0, //Eric
581, 132, 43, 48, 584, 150, 583, 161, 3500, 0, 0, //Lynn
278, 211, 36, 51, 283, 232, 283, 241, 3700, 0, 0, //Norm
319, 210, 34, 49, 323, 227, 320, 339, 4000, 0, 0, //George
358, 211, 38, 49, 364, 226, 361, 239, 3600, 0, 0, //Andrew Stacey
396, 200, 42, 50, 406, 220, 403, 230, 4600, 0, 0, //Scott
444, 202, 43, 51, 452, 220, 452, 231, 2800, 0, 0, //Emmons
493, 188, 36, 51, 501, 207, 499, 217, 4500, 0, 0, //Dave
531, 199, 47, 56, 541, 221, 540, 232, 4000, 0, 0, //Alex
585, 196, 39, 49, 593, 218, 593, 228, 3500, 0, 0, //Joey
};
//Global Variables
MOUSE_REGION gCrdtMouseRegions[ NUM_PEOPLE_IN_CREDITS ];
void SelectCreditFaceRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
void SelectCreditFaceMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
UINT32 guiCreditBackGroundImage;
UINT32 guiCreditFaces;
BOOLEAN gfCreditsScreenEntry = TRUE;
BOOLEAN gfCreditsScreenExit = FALSE;
UINT32 guiCreditsExitScreen;
UINT8 gubCreditScreenRenderFlags = CRDT_RENDER_ALL;
CRDT_NODE *gCrdtRootNode=NULL;
CRDT_NODE *gCrdtLastAddedNode=NULL;
BOOLEAN gfCrdtHaveRenderedFirstFrameToSaveBuffer; // need to render background image to save buffer once
INT32 giCurrentlySelectedFace = -1;
//
//VAriables needed for processing of the nodes:
//
UINT32 guiCreditScreenActiveFont; // the font that is used
UINT32 guiCreditScreenTitleFont; // the font that is used
UINT8 gubCreditScreenActiveColor; // color of the font
UINT8 gubCreditScreenTitleColor; // color of a Title node
UINT32 guiCrdtNodeScrollSpeed = CRDT_NODE_DELAY_AMOUNT; //speed credits go up at
UINT32 guiCrdtLastTimeUpdatingNode=0; // the last time a node was read from the file
UINT8 gubCrdtJustification = CENTER_JUSTIFIED; // the current justification
UINT32 guiGapBetweenCreditSections = CRDT_SPACE_BN_SECTIONS;
UINT32 guiGapBetweenCreditNodes = CRDT_SPACE_BN_NODES;
UINT32 guiGapTillReadNextCredit = CRDT_SPACE_BN_NODES;
UINT32 guiCurrentCreditRecord = 0;
BOOLEAN gfPauseCreditScreen = FALSE;
BOOLEAN gfModCredits = TRUE;
HWFILE ghFile;
//Function Prototypes
BOOLEAN EnterCreditsScreen();
BOOLEAN ExitCreditScreen();
void HandleCreditScreen();
BOOLEAN RenderCreditScreen();
void GetCreditScreenUserInput();
void SetCreditsExitScreen( UINT32 uiScreenToGoTo );
BOOLEAN ShutDownCreditList();
BOOLEAN AddCreditNode( UINT32 uiType, UINT32 uiFlags, STR16 pString );
BOOLEAN InitCreditNode( );
BOOLEAN DisplayCreditNode( CRDT_NODE *pCurrent );
void HandleCreditNodes();
void HandleNode_Default( CRDT_NODE *pCurrent );
void HandleCurrentCreditNode( CRDT_NODE *pCurrent );
BOOLEAN DeleteNode( CRDT_NODE *pNodeToDelete );
UINT32 GetAndHandleCreditCodeFromCodeString( STR16 pzCode );
BOOLEAN GetNextCreditFromTextFile();
UINT32 CountNumberOfCreditNodes();
STR16 GetNextCreditCode( STR16 pString, UINT32 *pSizeOfCode );
void HandleCreditFlags( UINT32 uiFlags );
void HandleCreditEyeBlinking();
void InitCreditEyeBlinking();
UINT32 CreditScreenInit( void )
{
gfCreditsScreenEntry = TRUE;
return( 1 );
}
UINT32 CreditScreenHandle( void )
{
StartFrameBufferRender();
if( gfCreditsScreenEntry )
{
if( !EnterCreditsScreen() )
{
gfCreditsScreenEntry = FALSE;
gfCreditsScreenExit = TRUE;
}
else
{
gfCreditsScreenEntry = FALSE;
gfCreditsScreenExit = FALSE;
}
gubCreditScreenRenderFlags = CRDT_RENDER_ALL;
}
GetCreditScreenUserInput();
HandleCreditScreen();
ExecuteBaseDirtyRectQueue();
EndFrameBufferRender();
if( gfCreditsScreenExit )
{
ExitCreditScreen();
gfCreditsScreenEntry = TRUE;
gfCreditsScreenExit = FALSE;
}
return( guiCreditsExitScreen );
}
UINT32 CreditScreenShutdown( void )
{
return( 1 );
}
BOOLEAN EnterCreditsScreen()
{
UINT32 uiCnt;
VOBJECT_DESC VObjectDesc;
gfModCredits = TRUE;
ColorFillVideoSurfaceArea( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0 );
VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE;
if (iResolution >= _640x480 && iResolution < _800x600)
{
FilenameForBPP("INTERFACE\\Credits.sti", VObjectDesc.ImageFile);
}
else if (iResolution < _1024x768)
{
FilenameForBPP("INTERFACE\\Credits_800x600.sti", VObjectDesc.ImageFile);
}
else
{
FilenameForBPP("INTERFACE\\Credits_1024x768.sti", VObjectDesc.ImageFile);
}
CHECKF(AddVideoObject(&VObjectDesc, &guiCreditBackGroundImage ));
VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE;
FilenameForBPP("INTERFACE\\Credit Faces.sti", VObjectDesc.ImageFile);
CHECKF(AddVideoObject(&VObjectDesc, &guiCreditFaces ));
//Initialize the root credit node
InitCreditNode( );
guiCreditsExitScreen = CREDIT_SCREEN;
gfCrdtHaveRenderedFirstFrameToSaveBuffer = FALSE;
guiCreditScreenActiveFont = FONT12ARIAL;
gubCreditScreenActiveColor = FONT_MCOLOR_DKWHITE;
guiCreditScreenTitleFont = FONT14ARIAL;
gubCreditScreenTitleColor = FONT_MCOLOR_RED;
guiCrdtNodeScrollSpeed = CRDT_NODE_DELAY_AMOUNT;
gubCrdtJustification = CENTER_JUSTIFIED;
guiCurrentCreditRecord = 0;
guiCrdtLastTimeUpdatingNode = GetJA2Clock();
guiGapBetweenCreditSections = CRDT_SPACE_BN_SECTIONS;
guiGapBetweenCreditNodes = CRDT_SPACE_BN_NODES;
guiGapTillReadNextCredit = CRDT_SPACE_BN_NODES;
for( uiCnt=0; uiCnt < NUM_PEOPLE_IN_CREDITS; uiCnt++)
{
// Make a mouse region
MSYS_DefineRegion( &gCrdtMouseRegions[uiCnt], gCreditFaces[uiCnt].sX + xResOffset, gCreditFaces[uiCnt].sY + yResOffset, (INT16)(gCreditFaces[uiCnt].sX + gCreditFaces[uiCnt].sWidth + xResOffset), (INT16)(gCreditFaces[uiCnt].sY + gCreditFaces[uiCnt].sHeight + yResOffset), MSYS_PRIORITY_NORMAL,
CURSOR_WWW, SelectCreditFaceMovementRegionCallBack, SelectCreditFaceRegionCallBack );
// Add region
MSYS_AddRegion( &gCrdtMouseRegions[uiCnt] );
MSYS_SetRegionUserData( &gCrdtMouseRegions[uiCnt], 0, uiCnt );
}
giCurrentlySelectedFace = -1;
gfPauseCreditScreen = FALSE;
InitCreditEyeBlinking();
return( TRUE );
}
BOOLEAN ExitCreditScreen()
{
UINT32 uiCnt;
DeleteVideoObjectFromIndex( guiCreditBackGroundImage );
DeleteVideoObjectFromIndex( guiCreditFaces );
//ShutDown Credit link list
ShutDownCreditList();
for( uiCnt=0; uiCnt < NUM_PEOPLE_IN_CREDITS; uiCnt++)
{
MSYS_RemoveRegion( &gCrdtMouseRegions[uiCnt] );
}
return( TRUE );
}
//hhh
void HandleCreditScreen()
{
UINT16 CRDT_NAME_LOC_X = 375 + xResOffset;
UINT16 CRDT_NAME_LOC_Y = 420 + yResOffset;
UINT16 CRDT_NAME_TITLE_LOC_Y = 435 + yResOffset;
UINT16 CRDT_NAME_FUNNY_LOC_Y = 450 + yResOffset;
UINT16 CRDT_NAME_LOC_WIDTH = 260;
UINT16 CRDT_NAME_LOC_HEIGHT = ( CRDT_NAME_FUNNY_LOC_Y - CRDT_NAME_LOC_Y + GetFontHeight( CRDT_NAME_FONT ) );
if( gubCreditScreenRenderFlags == CRDT_RENDER_ALL )
{
RenderCreditScreen();
gubCreditScreenRenderFlags = CRDT_RENDER_NONE;
}
//Handle the Credit linked list
HandleCreditNodes();
//Handle the blinkng eyes
HandleCreditEyeBlinking();
//is it time to get a new node
if( gCrdtLastAddedNode == NULL || ( CRDT_START_POS_Y - ( gCrdtLastAddedNode->sPosY + gCrdtLastAddedNode->sHeightOfString - 16 ) ) >= (INT16)guiGapTillReadNextCredit )
{
//if there are no more credits in the file
if( !GetNextCreditFromTextFile() && gCrdtLastAddedNode == NULL )
{
SetCreditsExitScreen( MAINMENU_SCREEN );
}
}
RestoreExternBackgroundRect( CRDT_NAME_LOC_X, CRDT_NAME_LOC_Y, CRDT_NAME_LOC_WIDTH, (INT16)CRDT_NAME_LOC_HEIGHT );
if( giCurrentlySelectedFace != -1 )
{
DrawTextToScreen( gzCreditNames[giCurrentlySelectedFace], CRDT_NAME_LOC_X, CRDT_NAME_LOC_Y, CRDT_NAME_LOC_WIDTH, CRDT_NAME_FONT, FONT_MCOLOR_WHITE, 0, FALSE, INVALIDATE_TEXT | CENTER_JUSTIFIED );
DrawTextToScreen( gzCreditNameTitle[giCurrentlySelectedFace], CRDT_NAME_LOC_X, CRDT_NAME_TITLE_LOC_Y, CRDT_NAME_LOC_WIDTH, CRDT_NAME_FONT, FONT_MCOLOR_WHITE, 0, FALSE, INVALIDATE_TEXT | CENTER_JUSTIFIED );
DrawTextToScreen( gzCreditNameFunny[giCurrentlySelectedFace], CRDT_NAME_LOC_X, CRDT_NAME_FUNNY_LOC_Y, CRDT_NAME_LOC_WIDTH, CRDT_NAME_FONT, FONT_MCOLOR_WHITE, 0, FALSE, INVALIDATE_TEXT | CENTER_JUSTIFIED );
}
}
//rrr
BOOLEAN RenderCreditScreen()
{
HVOBJECT hPixHandle;
GetVideoObject(&hPixHandle, guiCreditBackGroundImage );
BltVideoObject( FRAME_BUFFER, hPixHandle, 0, xResOffset, yResOffset, VO_BLT_SRCTRANSPARENCY, NULL);
if( !gfCrdtHaveRenderedFirstFrameToSaveBuffer )
{
gfCrdtHaveRenderedFirstFrameToSaveBuffer = TRUE;
//blit everything to the save buffer ( cause the save buffer can bleed through )
BlitBufferToBuffer(guiRENDERBUFFER, guiSAVEBUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
UnmarkButtonsDirty( );
}
InvalidateScreen( );
return( TRUE );
}
void GetCreditScreenUserInput()
{
InputAtom Event;
while (DequeueSpecificEvent(&Event, KEY_DOWN|KEY_UP|KEY_REPEAT))
{
if( Event.usEvent == KEY_DOWN )
{
switch( Event.usParam )
{
case ESC:
//Exit out of the screen
SetCreditsExitScreen( MAINMENU_SCREEN );
break;
case 'r':
gubCreditScreenRenderFlags = CRDT_RENDER_ALL;
break;
case 'i':
InvalidateRegion( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
break;
case UPARROW:
guiCrdtNodeScrollSpeed+=5;
break;
case DNARROW:
if( guiCrdtNodeScrollSpeed > 5 )
guiCrdtNodeScrollSpeed-=5;
break;
case PAUSE:
case SPACE:
if( gfPauseCreditScreen )
gfPauseCreditScreen = FALSE;
else
gfPauseCreditScreen = TRUE;
break;
}
}
}
}
void SetCreditsExitScreen( UINT32 uiScreenToGoTo )
{
gfCreditsScreenExit = TRUE;
guiCreditsExitScreen = uiScreenToGoTo;
}
BOOLEAN InitCreditNode( )
{
if( gCrdtRootNode != NULL )
Assert( 0 );
gCrdtRootNode = NULL;
return( TRUE );
}
BOOLEAN ShutDownCreditList()
{
CRDT_NODE *pNodeToDelete=NULL;
CRDT_NODE *pTemp=NULL;
pNodeToDelete = gCrdtRootNode;
while( pNodeToDelete!= NULL )
{
pTemp = pNodeToDelete;
pNodeToDelete = pNodeToDelete->pNext;
//Delete the current node
DeleteNode( pTemp );
}
return( TRUE );
}
BOOLEAN DeleteNode( CRDT_NODE *pNodeToDelete )
{
CRDT_NODE *pTempNode;
pTempNode = pNodeToDelete;
if( gCrdtLastAddedNode == pNodeToDelete )
{
gCrdtLastAddedNode = NULL;
}
//if its Not the first node
if( pNodeToDelete->pPrev != NULL )
pNodeToDelete->pPrev = pNodeToDelete->pNext;
else
{
if( gCrdtRootNode->pNext != NULL )
{
gCrdtRootNode = gCrdtRootNode->pNext;
gCrdtRootNode->pPrev = NULL;
}
}
//if its the last node in the list
if( pNodeToDelete->pNext == NULL && pNodeToDelete->pPrev != NULL )
pNodeToDelete->pPrev->pNext = NULL;
//iof the node that is being deleted is the first node
if( pTempNode == gCrdtRootNode )
gCrdtRootNode = NULL;
//Free the string
if( pTempNode->pString != NULL )
{
MemFree( pTempNode->pString );
pTempNode->pString = NULL;
}
//if the node had something to display, delete a surface for it
if( pTempNode->uiType == CRDT_NODE_DEFAULT )
{
DeleteVideoSurfaceFromIndex( pTempNode->uiVideoSurfaceImage );
pTempNode->uiVideoSurfaceImage = 0;
}
//Free the node
MemFree( pTempNode );
pTempNode = NULL;
return( TRUE );
}
//aaa
BOOLEAN AddCreditNode( UINT32 uiType, UINT32 uiFlags, STR16 pString )
{
CRDT_NODE *pNodeToAdd=NULL;
CRDT_NODE *pTemp=NULL;
UINT32 uiSizeOfString = ( wcslen( pString ) + 2 ) * 2;
UINT32 uiFontToUse;
UINT8 uiColorToUse;
UINT16 CRDT_TEXT_START_LOC = xResOffset + 10;
//if
if( uiType == CRDT_NODE_NONE)
{
Assert( 0 );
return( TRUE );
}
pNodeToAdd = (CRDT_NODE *) MemAlloc( sizeof( CRDT_NODE) );
if( pNodeToAdd == NULL )
{
return( FALSE );
}
memset( pNodeToAdd, 0, sizeof( CRDT_NODE) );
//Determine the font and the color to use
if( uiFlags & CRDT_FLAG__TITLE )
{
uiFontToUse = guiCreditScreenTitleFont;
uiColorToUse = gubCreditScreenTitleColor;
}
else
{
uiFontToUse = guiCreditScreenActiveFont;
uiColorToUse = gubCreditScreenActiveColor;
}
//
// Set some default data
//
//the type of the node
pNodeToAdd->uiType = uiType;
//any flags that are added
pNodeToAdd->uiFlags = uiFlags;
//the starting left position for the it
pNodeToAdd->sPosX = CRDT_TEXT_START_LOC;
//Allocate memory for the string
pNodeToAdd->pString = (CHAR16 *) MemAlloc( uiSizeOfString );
if( pNodeToAdd->pString == NULL )
return( FALSE );
//copy the string into the node
wcscpy( pNodeToAdd->pString, pString );
//Calculate the height of the string
pNodeToAdd->sHeightOfString = DisplayWrappedString( 0, 0, CRDT_WIDTH_OF_TEXT_AREA, 2, uiFontToUse, uiColorToUse, pNodeToAdd->pString, 0, FALSE, DONT_DISPLAY_TEXT ) + 1;
//starting y position on the screen
pNodeToAdd->sPosY = CRDT_START_POS_Y;
// pNodeToAdd->uiLastTime = GetJA2Clock();
//if the node can have something to display, Create a surface for it
if( pNodeToAdd->uiType == CRDT_NODE_DEFAULT )
{
VSURFACE_DESC vs_desc;
// Create a background video surface to blt the face onto
vs_desc.fCreateFlags = VSURFACE_CREATE_DEFAULT | VSURFACE_SYSTEM_MEM_USAGE;
vs_desc.usWidth = CRDT_WIDTH_OF_TEXT_AREA;
vs_desc.usHeight = pNodeToAdd->sHeightOfString;
vs_desc.ubBitDepth = 16;
if( AddVideoSurface( &vs_desc, &pNodeToAdd->uiVideoSurfaceImage) == 0 )
{
return( FALSE );
}
//Set transparency
SetVideoSurfaceTransparency( pNodeToAdd->uiVideoSurfaceImage, 0 );
//fill the surface with a transparent color
ColorFillVideoSurfaceArea(pNodeToAdd->uiVideoSurfaceImage, 0, 0, CRDT_WIDTH_OF_TEXT_AREA, pNodeToAdd->sHeightOfString, 0 );
//set the font dest buffer to be the surface
SetFontDestBuffer( pNodeToAdd->uiVideoSurfaceImage, 0, 0, CRDT_WIDTH_OF_TEXT_AREA, pNodeToAdd->sHeightOfString, FALSE );
//write the string onto the surface
DisplayWrappedString( 0, 1, CRDT_WIDTH_OF_TEXT_AREA, 2, uiFontToUse, uiColorToUse, pNodeToAdd->pString, 0, FALSE, gubCrdtJustification );
//reset the font dest buffer
SetFontDestBuffer(FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE);
}
//
// Insert the node into the list
//
//if its the first node to add
if( gCrdtRootNode == NULL )
{
//make the new node the root node
gCrdtRootNode = pNodeToAdd;
gCrdtRootNode->pNext = NULL;
gCrdtRootNode->pPrev = NULL;
}
else
{
pTemp = gCrdtRootNode;
while( pTemp->pNext != NULL )
{
pTemp = pTemp->pNext;
}
//Add the new node to the list
pTemp->pNext = pNodeToAdd;
//Assign the prev node
pNodeToAdd->pPrev = pTemp;
}
gCrdtLastAddedNode = pNodeToAdd;
return( TRUE );
}
void HandleCreditNodes()
{
CRDT_NODE *pCurrent=NULL;
CRDT_NODE *pTemp=NULL;
if( gCrdtRootNode == NULL )
return;
//if the screen is paused, exit
if( gfPauseCreditScreen )
return;
pCurrent = gCrdtRootNode;
if( !( GetJA2Clock() - guiCrdtLastTimeUpdatingNode > guiCrdtNodeScrollSpeed ) )
return;
//loop through all the nodes
while( pCurrent != NULL )
{
pTemp = pCurrent;
pCurrent = pCurrent->pNext;
//Handle the current node
HandleCurrentCreditNode( pTemp );
//if the node is to be deleted
if( pTemp->fDelete )
{
//delete the node
DeleteNode( pTemp );
}
}
guiCrdtLastTimeUpdatingNode = GetJA2Clock();
}
void HandleCurrentCreditNode( CRDT_NODE *pCurrent )
{
//switch on the type of node
switch( pCurrent->uiType )
{
case CRDT_NODE_DEFAULT:
HandleNode_Default( pCurrent );
break;
default:
Assert( 0 );
break;
}
}
void HandleNode_Default( CRDT_NODE *pCurrent )
{
//Display the Current Node
DisplayCreditNode( pCurrent );
//Save the old position
pCurrent->sOldPosX = pCurrent->sPosX;
pCurrent->sOldPosY = pCurrent->sPosY;
//Move the current node up
pCurrent->sPosY -= CRDT_SCROLL_PIXEL_AMOUNT;
//if the node is entirely off the screen
if( ( pCurrent->sPosY + pCurrent->sHeightOfString ) < CRDT_LINE_NODE_DISAPPEARS_AT )
{
//mark the node to be deleted this frame
pCurrent->fDelete = TRUE;
}
pCurrent->uiLastTime = GetJA2Clock();
}
BOOLEAN DisplayCreditNode( CRDT_NODE *pCurrent )
{
HVSURFACE hVSurface;
//Currently, we have no need to display a node that doesnt have a string
if( pCurrent->pString == NULL )
return( FALSE );
//if the node is new and we havent displayed it yet
if( pCurrent->uiLastTime == 0 )
{
}
//else we have to restore were the string was
else
{
//
//Restore the background before blitting the text back on
//
//if the surface is at the bottom of the screen
if( pCurrent->sOldPosY + pCurrent->sHeightOfString > CRDT_START_POS_Y )
{
INT16 sHeight = SCREEN_HEIGHT - pCurrent->sOldPosY;
//INT16 sHeight = 480 - pCurrent->sOldPosY;
RestoreExternBackgroundRect( pCurrent->sOldPosX, pCurrent->sOldPosY, CRDT_WIDTH_OF_TEXT_AREA, sHeight );
}
else if( pCurrent->sOldPosY > CRDT_LINE_NODE_DISAPPEARS_AT )
{
RestoreExternBackgroundRect( pCurrent->sOldPosX, pCurrent->sOldPosY, CRDT_WIDTH_OF_TEXT_AREA, pCurrent->sHeightOfString );
}
//if the surface is at the top of the screen
else
{
INT16 sHeight = pCurrent->sOldPosY + pCurrent->sHeightOfString;
RestoreExternBackgroundRect( pCurrent->sOldPosX, CRDT_LINE_NODE_DISAPPEARS_AT, CRDT_WIDTH_OF_TEXT_AREA, sHeight );
}
}
GetVideoSurface( &hVSurface, pCurrent->uiVideoSurfaceImage );
BltVideoSurfaceToVideoSurface( ghFrameBuffer, hVSurface, 0, pCurrent->sPosX, pCurrent->sPosY, VS_BLT_CLIPPED | VS_BLT_USECOLORKEY, NULL );
return( TRUE );
}
//return false from this function when there are no more items in the text file
BOOLEAN GetNextCreditFromTextFile()
{
CHAR16 zOriginalString[512];
CHAR16 zString[512];
CHAR16 zCodes[512];
STR16 pzNewCode=NULL;
UINT32 uiNodeType = 0;
UINT32 uiStartLoc = 0;
UINT32 uiFlags=0;
// 1.) MOD Credits
if (gfModCredits == TRUE)
{
if (FileExists(CRDT_NAME_OF_MOD_CREDIT_FILE))
{
uiStartLoc = CREDITS_LINESIZE * (guiCurrentCreditRecord);
if( !LoadEncryptedDataFromFile( CRDT_NAME_OF_MOD_CREDIT_FILE, zOriginalString, uiStartLoc, CREDITS_LINESIZE ) )
{
//there are no more credits
gfModCredits = FALSE;
guiCurrentCreditRecord = 0;
}
// We have ended the mod credits list
if (strcmp((char *)zOriginalString, "") == 0)
{
gfModCredits = FALSE;
guiCurrentCreditRecord = 0;
}
}
else
{
gfModCredits = FALSE;
guiCurrentCreditRecord = 0;
}
}
if (gfModCredits == FALSE)
{
switch(guiCurrentCreditRecord)
{
// 2.) 1.13 Credits
case 0:
wcscpy(zOriginalString, L"@T,C208,R134,D16,B40,S10,J1,};");
break;
case 1:
wcscpy(zOriginalString, pCreditsJA2113[0]);
break;
case 2:
wcscpy(zOriginalString, L"@};");
break;
case 3:
wcscpy(zOriginalString, pCreditsJA2113[1]);
break;
case 4:
wcscpy(zOriginalString, L"anv");
break;
case 5:
wcscpy(zOriginalString, L"BirdFlu");
break;
case 6:
wcscpy(zOriginalString, L"Buggler");
break;
case 7:
wcscpy(zOriginalString, L"Bugmonster");
break;
case 8:
wcscpy(zOriginalString, L"ChrisL");
break;
case 9:
wcscpy(zOriginalString, L"Flugente");
break;
case 10:
wcscpy(zOriginalString, L"haydent");
break;
case 11:
wcscpy(zOriginalString, L"Jazz");
break;
case 12:
wcscpy(zOriginalString, L"Kaiden");
break;
case 13:
wcscpy(zOriginalString, L"Kriplo");
break;
case 14:
wcscpy(zOriginalString, L"Lesh");
break;
case 15:
wcscpy(zOriginalString, L"Little Alien");
break;
case 16:
wcscpy(zOriginalString, L"Madd Mugsy");
break;
case 17:
wcscpy(zOriginalString, L"Overhaul");
break;
case 18:
wcscpy(zOriginalString, L"RoWa21 aka Wanne");
break;
case 19:
wcscpy(zOriginalString, L"Sandro");
break;
case 20:
wcscpy(zOriginalString, L"silversurfer");
break;
case 21:
wcscpy(zOriginalString, L"Space Viking");
break;
case 22:
wcscpy(zOriginalString, L"@};Zathras");
break;
case 23:
wcscpy(zOriginalString, pCreditsJA2113[2]);
break;
case 24:
wcscpy(zOriginalString, L"BulletSix");
break;
case 25:
wcscpy(zOriginalString, L"coolberg");
break;
case 26:
wcscpy(zOriginalString, L"Corpse");
break;
case 27:
wcscpy(zOriginalString, L"John Wright");
break;
case 28:
wcscpy(zOriginalString, L"Kaerar");
break;
case 29:
wcscpy(zOriginalString, L"Kazuya");
break;
case 30:
wcscpy(zOriginalString, L"Khor");
break;
case 31:
wcscpy(zOriginalString, L"Lisac");
break;
case 32:
wcscpy(zOriginalString, L"Madd Mugsy");
break;
case 33:
wcscpy(zOriginalString, L"Marlboro Man");
break;
case 34:
wcscpy(zOriginalString, L"PasHancock");
break;
case 35:
wcscpy(zOriginalString, L"Scorpion");
break;
case 36:
wcscpy(zOriginalString, L"smeagol");
break;
case 37:
wcscpy(zOriginalString, L"Starwalker");
break;
case 38:
wcscpy(zOriginalString, L"Tbird94lx");
break;
case 39:
wcscpy(zOriginalString, L"Terry Thorne");
break;
case 40:
wcscpy(zOriginalString, pCreditsJA2113[3]);
break;
case 41:
wcscpy(zOriginalString, pCreditsJA2113[4]);
break;
case 42:
wcscpy(zOriginalString, L"Madd Mugsy");
break;
case 43:
wcscpy(zOriginalString, L"Starwalker");
break;
case 44:
wcscpy(zOriginalString, L"@};Lisac");
break;
case 45:
wcscpy(zOriginalString, pCreditsJA2113[5]);
break;
case 46:
wcscpy(zOriginalString, L"BearPit");
break;
case 47:
wcscpy(zOriginalString, L"Captain J");
break;
case 48:
wcscpy(zOriginalString, L"DeFrog");
break;
case 49:
wcscpy(zOriginalString, L"DepressivesBrot");
break;
case 50:
wcscpy(zOriginalString, L"Dimitri");
break;
case 51:
wcscpy(zOriginalString, L"Farmer Toby");
break;
case 52:
wcscpy(zOriginalString, L"Headrock");
break;
case 53:
wcscpy(zOriginalString, L"inshy");
break;
case 54:
wcscpy(zOriginalString, L"JAPH");
break;
case 55:
wcscpy(zOriginalString, L"JMich");
break;
case 56:
wcscpy(zOriginalString, L"Jones");
break;
case 57:
wcscpy(zOriginalString, L"Judge");
break;
case 58:
wcscpy(zOriginalString, L"Kermi");
break;
case 59:
wcscpy(zOriginalString, L"Miro");
break;
case 60:
wcscpy(zOriginalString, L"Pulmu");
break;
case 61:
wcscpy(zOriginalString, L"Scheinworld");
break;
case 62:
wcscpy(zOriginalString, L"Scorpion");
break;
case 63:
wcscpy(zOriginalString, L"Sergeant Kolja");
break;
case 64:
wcscpy(zOriginalString, L"ShadoWarrior");
break;
case 65:
wcscpy(zOriginalString, L"Shanga");
break;
case 66:
wcscpy(zOriginalString, L"Snap");
break;
case 67:
wcscpy(zOriginalString, L"TheDrill");
break;
case 68:
wcscpy(zOriginalString, L"WarmSteel");
break;
case 69:
wcscpy(zOriginalString, L"Wil473");
break;
case 70:
wcscpy( zOriginalString, L"tais" );
break;
case 71:
wcscpy( zOriginalString, L"sevenfm" );
break;
case 72:
wcscpy(zOriginalString, pCreditsJA2113[6]);
break;
// Additional lines for free space
case 73:
wcscpy(zOriginalString, L"@T,B40,C208,{; ");
break;
case 74:
wcscpy(zOriginalString, L"@}; ");
break;
// 3.) Sir-Tech Credits
default:
//Get the current Credit record
uiStartLoc = CREDITS_LINESIZE * (guiCurrentCreditRecord-(74+1));
if( !LoadEncryptedDataFromFile( CRDT_NAME_OF_CREDIT_FILE, zOriginalString, uiStartLoc, CREDITS_LINESIZE ) )
{
//there are no more credits
return( FALSE );
}
}
}
//Increment to the next crdit record
guiCurrentCreditRecord++;
//if there are no codes in the string
if( zOriginalString[0] != CRDT_START_CODE )
{
//copy the string
wcscpy( zString, zOriginalString );
uiNodeType = CRDT_NODE_DEFAULT;
}
else
{
UINT32 uiSizeOfCodes = 0;
UINT32 uiSizeOfSubCode = 0;
STR16 pzEndCode = NULL;
UINT32 uiDistanceIntoCodes = 0;
//Retrive all the codes from the string
pzEndCode = wcsstr( zOriginalString, CRDT_END_CODE );
//Make a string for the codes
wcscpy( zCodes, zOriginalString );
//end the setence after the codes
zCodes[ pzEndCode - zOriginalString + 1 ] = '\0';
//Get the size of the codes
uiSizeOfCodes = pzEndCode - zOriginalString + 1;
//
//check to see if there is a string, or just codes
//
//if the string is the same size as the codes
if( wcslen( zOriginalString ) == uiSizeOfCodes )
{
//there is no string, just codes
uiNodeType = CRDT_NODE_NONE;
}
//else there is a string aswell
else
{
//copy the main string
wcscpy( zString, &zOriginalString[ uiSizeOfCodes ] );
uiNodeType = CRDT_NODE_DEFAULT;
}
//get rid of the start code delimeter
uiDistanceIntoCodes = 1;
uiFlags = 0;
//loop through the string of codes to get all the control codes out
while( uiDistanceIntoCodes < uiSizeOfCodes )
{
//Determine what kind of code it is, and handle it
uiFlags |= GetAndHandleCreditCodeFromCodeString( &zCodes[ uiDistanceIntoCodes ] );
//get the next code from the string of codes, returns NULL when done
pzNewCode = GetNextCreditCode( &zCodes[ uiDistanceIntoCodes ], &uiSizeOfSubCode );
//if we are done getting the sub codes
if( pzNewCode == NULL )
{
uiDistanceIntoCodes = uiSizeOfCodes;
}
else
{
//else increment by the size of the code
uiDistanceIntoCodes += uiSizeOfSubCode;
}
}
}
if( uiNodeType != CRDT_NODE_NONE )
{
//add the node to the list
AddCreditNode( uiNodeType, uiFlags, zString );
}
//if any processing of the flags need to be done
HandleCreditFlags( uiFlags );
return( TRUE );
}
//return any flags that need to be set in the node
UINT32 GetAndHandleCreditCodeFromCodeString( STR16 pzCode )
{
//if the code is to change the delay between strings
if( pzCode[0] == CRDT_DELAY_BN_STRINGS_CODE )
{
UINT32 uiNewDelay=0;
//Get the delay from the string
swscanf( &pzCode[1], L"%d%*s", &uiNewDelay );
guiGapBetweenCreditNodes = uiNewDelay;
return( CRDT_NODE_NONE );
}
//if the code is to change the delay between sections strings
else if( pzCode[0] == CRDT_DELAY_BN_SECTIONS_CODE )
{
UINT32 uiNewDelay=0;
//Get the delay from the string
swscanf( &pzCode[1], L"%d%*s", &uiNewDelay );
guiGapBetweenCreditSections = uiNewDelay;
return( CRDT_NODE_NONE );
}
else if( pzCode[0] == CRDT_SCROLL_SPEED )
{
UINT32 uiScrollSpeed=0;
//Get the delay from the string
swscanf( &pzCode[1], L"%d%*s", &uiScrollSpeed );
guiCrdtNodeScrollSpeed = uiScrollSpeed;
return( CRDT_NODE_NONE );
}
else if( pzCode[0] == CRDT_FONT_JUSTIFICATION )
{
UINT32 uiJustification=0;
//Get the delay from the string
swscanf( &pzCode[1], L"%d%*s", &uiJustification );
//get the justification
switch( uiJustification )
{
case 0:
gubCrdtJustification = LEFT_JUSTIFIED;
break;
case 1:
gubCrdtJustification = CENTER_JUSTIFIED;
break;
case 2:
gubCrdtJustification = RIGHT_JUSTIFIED;
break;
default:
Assert( 0 );
}
return( CRDT_NODE_NONE );
}
else if( pzCode[0] == CRDT_TITLE_FONT_COLOR )
{
UINT uiBuffer = 0;
swscanf( &pzCode[1], L"%d%*s", &uiBuffer );
gubCreditScreenTitleColor = (UINT8)uiBuffer;
return( CRDT_NODE_NONE );
}
else if( pzCode[0] == CRDT_ACTIVE_FONT_COLOR )
{
UINT uiBuffer = 0;
swscanf( &pzCode[1], L"%d%*s", &uiBuffer );
gubCreditScreenActiveColor = (UINT8)uiBuffer;
return( CRDT_NODE_NONE );
}
else if( pzCode[0] == CRDT_TITLE )
{
return( CRDT_FLAG__TITLE );
}
else if( pzCode[0] == CRDT_START_OF_SECTION )
{
return( CRDT_FLAG__START_SECTION );
}
else if( pzCode[0] == CRDT_END_OF_SECTION )
{
return( CRDT_FLAG__END_SECTION );
}
return( CRDT_NODE_NONE );
}
UINT32 CountNumberOfCreditNodes()
{
UINT32 uiNumNodes = 0;
CRDT_NODE *pTempNode = gCrdtRootNode;
while( pTempNode )
{
uiNumNodes++;
pTempNode = pTempNode->pNext;
}
return( uiNumNodes );
}
STR16 GetNextCreditCode( STR16 pString, UINT32 *pSizeOfCode )
{
STR16 pzNewCode=NULL;
UINT32 uiSizeOfCode = 0;
//get the new subcode out
pzNewCode = wcsstr( pString, CRDT_SEPARATION_CODE );
//if there is no separation code, then there must be an end code
if( pzNewCode == NULL )
{
//we are done
pzNewCode = NULL;
}
else
{
//get rid of separeation code
pzNewCode++;
//calc size of sub string
uiSizeOfCode = pzNewCode - pString;
}
*pSizeOfCode = uiSizeOfCode;
return( pzNewCode );
}
//Flags:
void HandleCreditFlags( UINT32 uiFlags )
{
if( uiFlags & CRDT_FLAG__TITLE )
{
}
if( uiFlags & CRDT_FLAG__START_SECTION )
{
guiGapTillReadNextCredit = guiGapBetweenCreditNodes;
}
if( uiFlags & CRDT_FLAG__END_SECTION )
{
guiGapTillReadNextCredit = guiGapBetweenCreditSections;
}
}
void SelectCreditFaceRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason )
{
if (iReason & MSYS_CALLBACK_REASON_INIT)
{
}
else if(iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
{
}
else if (iReason & MSYS_CALLBACK_REASON_RBUTTON_UP)
{
}
}
void SelectCreditFaceMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason )
{
if( iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
{
giCurrentlySelectedFace = -1;
}
else if( iReason & MSYS_CALLBACK_REASON_GAIN_MOUSE )
{
giCurrentlySelectedFace = MSYS_GetRegionUserData( pRegion,0 );
}
else if( iReason & MSYS_CALLBACK_REASON_MOVE )
{
}
}
void InitCreditEyeBlinking()
{
UINT8 ubCnt;
for( ubCnt=0; ubCnt<NUM_PEOPLE_IN_CREDITS; ubCnt++ )
{
gCreditFaces[ubCnt].uiLastBlinkTime = GetJA2Clock() + Random( gCreditFaces[ubCnt].sBlinkFreq * 2 );
}
}
void HandleCreditEyeBlinking()
{
HVOBJECT hPixHandle;
UINT8 ubCnt;
GetVideoObject(&hPixHandle, guiCreditFaces );
for( ubCnt=0; ubCnt<NUM_PEOPLE_IN_CREDITS; ubCnt++ )
{
if( ( GetJA2Clock() - gCreditFaces[ubCnt].uiLastBlinkTime ) > (UINT32)gCreditFaces[ubCnt].sBlinkFreq )
{
BltVideoObject( FRAME_BUFFER, hPixHandle, (UINT8)(ubCnt*3), gCreditFaces[ubCnt].sEyeX + xResOffset, gCreditFaces[ubCnt].sEyeY + yResOffset, VO_BLT_SRCTRANSPARENCY, NULL);
InvalidateRegion( gCreditFaces[ubCnt].sEyeX + xResOffset, gCreditFaces[ubCnt].sEyeY + yResOffset, gCreditFaces[ubCnt].sEyeX + CRDT_EYE_WIDTH + xResOffset, gCreditFaces[ubCnt].sEyeY + CRDT_EYE_HEIGHT + yResOffset );
gCreditFaces[ubCnt].uiLastBlinkTime = GetJA2Clock();
gCreditFaces[ubCnt].uiEyesClosedTime = GetJA2Clock() + CRDT_EYES_CLOSED_TIME + Random( CRDT_EYES_CLOSED_TIME );
}
else if( GetJA2Clock() > gCreditFaces[ubCnt].uiEyesClosedTime )
{
gCreditFaces[ubCnt].uiEyesClosedTime = 0;
RestoreExternBackgroundRect( gCreditFaces[ubCnt].sEyeX + xResOffset, gCreditFaces[ubCnt].sEyeY + yResOffset, CRDT_EYE_WIDTH, CRDT_EYE_HEIGHT );
}
}
}