Game client codebase including: - CharacterActionControl: Character and creature management - GlobalScript: Network, items, skills, quests, utilities - RYLClient: Main client application with GUI and event handlers - Engine: 3D rendering engine (RYLGL) - MemoryManager: Custom memory allocation - Library: Third-party dependencies (DirectX, boost, etc.) - Tools: Development utilities 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
535 lines
15 KiB
C++
535 lines
15 KiB
C++
//-----------------------------------------------------------------------------
|
|
// File: gfx.cpp
|
|
//
|
|
// Desc: Graphics routines
|
|
//
|
|
// Copyright (C) 1995-2001 Microsoft Corporation. All Rights Reserved.
|
|
//-----------------------------------------------------------------------------
|
|
#include "duel.h"
|
|
#include "gfx.h"
|
|
#include "diutil.h"
|
|
#include "ddutil.h"
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Globals
|
|
//-----------------------------------------------------------------------------
|
|
extern BOOL g_bFullscreen; // Window or fullscreen mode ?
|
|
extern HWND g_hwndMain; // Main window
|
|
extern DWORD g_dwKeys;
|
|
extern int g_nProgramState; // Current state of program
|
|
extern RECT g_rcWindow; // Client window rectangle
|
|
extern HINSTANCE g_hInst; // Application instance handle
|
|
|
|
|
|
LPDIRECTDRAW g_pDD = NULL; // DirectDraw interface
|
|
LPDIRECTDRAWPALETTE g_pArtPalette = NULL; // Game screen palette
|
|
LPDIRECTDRAWPALETTE g_pSplashPalette = NULL; // Splash screen palette
|
|
LPDIRECTDRAWSURFACE g_pddsFrontBuffer = NULL; // primary surface
|
|
LPDIRECTDRAWSURFACE g_pddsBackBuffer = NULL; // back buffer for animation
|
|
LPDIRECTDRAWSURFACE g_pddsShip[4]; // ship bitmaps
|
|
LPDIRECTDRAWSURFACE g_pddsNumbers; // Numbers bitmap
|
|
DWORD g_dwFillColor;
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: InitGraphics()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT InitGraphics()
|
|
{
|
|
DDCAPS ddcaps;
|
|
HRESULT hr;
|
|
DDSURFACEDESC ddsd;
|
|
DDSCAPS ddscaps;
|
|
|
|
// Create a window
|
|
g_hwndMain = CreateWindowEx( WS_EX_APPWINDOW, TEXT("DuelClass"),
|
|
TEXT("Duel"), WS_POPUP | WS_SYSMENU, 0, 0,
|
|
GetSystemMetrics(SM_CXSCREEN),
|
|
GetSystemMetrics(SM_CYSCREEN),
|
|
NULL, NULL, g_hInst, NULL );
|
|
if( NULL == g_hwndMain )
|
|
return E_FAIL;
|
|
|
|
UpdateWindow( g_hwndMain );
|
|
SetFocus( g_hwndMain );
|
|
|
|
// DDraw stuff begins here
|
|
if( FAILED( hr = DirectDrawCreate( NULL, &g_pDD, NULL ) ) )
|
|
{
|
|
ShowError(IDS_DDRAW_ERROR_DDC);
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Set access mode based on fullscreen/window
|
|
if( g_bFullscreen )
|
|
{
|
|
hr = g_pDD->SetCooperativeLevel( g_hwndMain,
|
|
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
|
|
}
|
|
else
|
|
{
|
|
hr = g_pDD->SetCooperativeLevel( g_hwndMain,
|
|
DDSCL_NORMAL);
|
|
}
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
ShowError(IDS_DDRAW_ERROR_SCL);
|
|
return E_FAIL;
|
|
}
|
|
|
|
if( g_bFullscreen )
|
|
{
|
|
// Set the mode to 640 by 480 by 8
|
|
if( FAILED( g_pDD->SetDisplayMode( 640, 480, 8 ) ) )
|
|
{
|
|
ShowError(IDS_DDRAW_ERROR_SDM);
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RECT rcWork;
|
|
RECT rc;
|
|
DWORD dwStyle;
|
|
|
|
// If we are still a WS_POPUP window we should convert to a
|
|
// normal app window so we look like a windows app.
|
|
dwStyle = GetWindowStyle(g_hwndMain);
|
|
dwStyle &= ~WS_POPUP;
|
|
dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX;
|
|
SetWindowLong( g_hwndMain, GWL_STYLE, dwStyle );
|
|
|
|
// Aet window size
|
|
SetRect( &rc, 0, 0, MAX_DEFWIN_X, MAX_DEFWIN_Y );
|
|
|
|
AdjustWindowRectEx( &rc, GetWindowStyle(g_hwndMain),
|
|
GetMenu(g_hwndMain) != NULL,
|
|
GetWindowExStyle(g_hwndMain) );
|
|
|
|
SetWindowPos( g_hwndMain, NULL, 0, 0, rc.right-rc.left,
|
|
rc.bottom-rc.top,
|
|
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
SetWindowPos( g_hwndMain, HWND_NOTOPMOST, 0, 0, 0, 0,
|
|
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
|
|
|
|
// Make sure our window does not hang outside of the work area
|
|
SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWork, 0 );
|
|
GetWindowRect( g_hwndMain, &rc );
|
|
if( rc.left < rcWork.left ) rc.left = rcWork.left;
|
|
if( rc.top < rcWork.top ) rc.top = rcWork.top;
|
|
SetWindowPos( g_hwndMain, NULL, rc.left, rc.top, 0, 0,
|
|
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
|
|
}
|
|
|
|
// Check the color key hardware capabilities
|
|
ddcaps.dwSize = sizeof( ddcaps );
|
|
memset( &ddsd, 0, sizeof( ddsd ) );
|
|
ddsd.dwSize = sizeof( ddsd );
|
|
|
|
if( g_bFullscreen )
|
|
{
|
|
// Create surfaces
|
|
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
|
|
DDSCAPS_FLIP |
|
|
DDSCAPS_COMPLEX;
|
|
ddsd.dwBackBufferCount = 1;
|
|
if( FAILED( hr = g_pDD->CreateSurface( &ddsd, &g_pddsFrontBuffer,
|
|
NULL ) ) )
|
|
{
|
|
ShowError(IDS_DDRAW_ERROR_CREATESURFACE);
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Get a pointer to the back buffer
|
|
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
|
|
if( FAILED( hr = g_pddsFrontBuffer->GetAttachedSurface( &ddscaps,
|
|
&g_pddsBackBuffer ) ) )
|
|
{
|
|
ShowError(IDS_DDRAW_ERROR_GAS);
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LPDIRECTDRAWCLIPPER pcClipper;
|
|
|
|
// Window case, create the primary surface
|
|
// and create a backbuffer in offscreen memory
|
|
ddsd.dwFlags = DDSD_CAPS;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
|
|
|
if( FAILED( g_pDD->CreateSurface( &ddsd, &g_pddsFrontBuffer, NULL ) ) )
|
|
{
|
|
ShowError(IDS_DDRAW_ERROR_CREATESURFACE);
|
|
return E_FAIL;
|
|
}
|
|
|
|
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
|
ddsd.dwWidth = MAX_DEFWIN_X;
|
|
ddsd.dwHeight = MAX_DEFWIN_Y;
|
|
if( FAILED( hr = g_pDD->CreateSurface( &ddsd, &g_pddsBackBuffer, NULL ) ) )
|
|
{
|
|
ShowError(IDS_DDRAW_ERROR_CREATESURFACE);
|
|
return E_FAIL;
|
|
}
|
|
|
|
if( FAILED( hr = g_pDD->CreateClipper( 0, &pcClipper, NULL) ) )
|
|
{
|
|
ShowError(IDS_DDRAW_ERROR_CC);
|
|
return E_FAIL;
|
|
}
|
|
|
|
if( FAILED( hr = pcClipper->SetHWnd( 0, g_hwndMain) ) )
|
|
{
|
|
pcClipper->Release();
|
|
ShowError(IDS_DDRAW_ERROR_SH);
|
|
return E_FAIL;
|
|
}
|
|
|
|
if( FAILED( hr = g_pddsFrontBuffer->SetClipper( pcClipper) ) )
|
|
{
|
|
pcClipper->Release();
|
|
ShowError(IDS_DDRAW_ERROR_SC);
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Done with clipper
|
|
pcClipper->Release();
|
|
}
|
|
|
|
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
|
|
|
ddsd.dwWidth = 320;
|
|
ddsd.dwHeight = 128;
|
|
|
|
for( DWORD i=0; i<4; i++ )
|
|
{
|
|
if( FAILED( hr = g_pDD->CreateSurface( &ddsd, &g_pddsShip[i], NULL ) ) )
|
|
{
|
|
ShowError(IDS_DDRAW_ERROR_CREATESURFACE);
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
ddsd.dwHeight = 16;
|
|
if( FAILED( hr = g_pDD->CreateSurface( &ddsd, &g_pddsNumbers, NULL ) ) )
|
|
{
|
|
ShowError(IDS_DDRAW_ERROR_CREATESURFACE);
|
|
return E_FAIL;
|
|
}
|
|
|
|
if( FAILED( RestoreSurfaces() ) )
|
|
{
|
|
ShowError(IDS_DDRAW_ERROR_RS);
|
|
return E_FAIL;
|
|
}
|
|
|
|
g_dwKeys = 0;
|
|
ShowWindow( g_hwndMain, SW_SHOW);
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: CleanupGraphics()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
VOID CleanupGraphics()
|
|
{
|
|
for( DWORD i=0; i<4; i++ )
|
|
if( g_pddsShip[i] )
|
|
g_pddsShip[i]->Release();
|
|
if( g_pddsNumbers )
|
|
g_pddsNumbers->Release();
|
|
if( g_pddsFrontBuffer )
|
|
g_pddsFrontBuffer->Release();
|
|
if( g_pArtPalette )
|
|
g_pArtPalette->Release();
|
|
if( g_pSplashPalette )
|
|
g_pSplashPalette->Release();
|
|
if( !g_bFullscreen && g_pddsBackBuffer )
|
|
g_pddsBackBuffer->Release();
|
|
if( g_pDD )
|
|
g_pDD->Release();
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: BltSplashScreen()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT BltSplashScreen( RECT* prc )
|
|
{
|
|
HRESULT hr;
|
|
HBITMAP hbm;
|
|
|
|
if( ( g_pddsFrontBuffer == NULL ) || ( g_pSplashPalette == NULL ) ||
|
|
( g_pddsBackBuffer == NULL ) )
|
|
return E_FAIL;
|
|
|
|
// Set the palette before loading the splash screen
|
|
g_pddsFrontBuffer->SetPalette( g_pSplashPalette );
|
|
|
|
hbm = (HBITMAP)LoadImage( GetModuleHandle( NULL ), TEXT("SPLASH"),
|
|
IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION );
|
|
if( NULL == hbm )
|
|
return E_FAIL;
|
|
|
|
// If the surface is lost, DDUtil_CopyBitmap will fail and the surface will
|
|
// be restored below.
|
|
hr = DDUtil_CopyBitmap( g_pddsBackBuffer, hbm, 0, 0, 0, 0 );
|
|
|
|
DeleteObject( hbm );
|
|
|
|
while( 1 )
|
|
{
|
|
hr = g_pddsFrontBuffer->Blt( &g_rcWindow, g_pddsBackBuffer,
|
|
prc, DDBLT_WAIT, NULL);
|
|
if( SUCCEEDED(hr) )
|
|
return S_OK;
|
|
if( hr == DDERR_SURFACELOST )
|
|
if( FAILED( RestoreSurfaces() ) )
|
|
return E_FAIL;
|
|
if( hr != DDERR_WASSTILLDRAWING )
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: BltNumber()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT BltNumber( CHAR* strScore, int x, int y )
|
|
{
|
|
while( *strScore )
|
|
{
|
|
RECT src;
|
|
src.left = ((*strScore++)-'0')*16;
|
|
src.top = 0;
|
|
src.right = src.left + 16;
|
|
src.bottom = src.top + 16;
|
|
|
|
BltObject( x, y, g_pddsNumbers, &src, DDBLTFAST_SRCCOLORKEY );
|
|
x += 16;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: BltObject()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT BltObject( int x, int y, LPDIRECTDRAWSURFACE pdds, RECT* prc,
|
|
DWORD flags )
|
|
{
|
|
if( NULL == pdds )
|
|
return E_FAIL;
|
|
|
|
while( 1 )
|
|
{
|
|
HRESULT hr = g_pddsBackBuffer->BltFast( x, y, pdds, prc, flags );
|
|
if( FAILED(hr) )
|
|
{
|
|
if( hr == DDERR_WASSTILLDRAWING )
|
|
continue;
|
|
|
|
if( hr == DDERR_SURFACELOST )
|
|
if( SUCCEEDED( RestoreSurfaces() ) )
|
|
continue;
|
|
return E_FAIL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: EraseScreen()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
VOID EraseScreen()
|
|
{
|
|
// Erase the background
|
|
DDBLTFX ddbltfx;
|
|
ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
|
|
ddbltfx.dwSize = sizeof(ddbltfx);
|
|
#ifdef NONAMELESSUNION
|
|
ddbltfx.u5.dwFillColor = g_dwFillColor;
|
|
#else
|
|
ddbltfx.dwFillColor = g_dwFillColor;
|
|
#endif
|
|
|
|
while( 1 )
|
|
{
|
|
HRESULT hr = g_pddsBackBuffer->Blt( NULL, NULL, NULL,
|
|
DDBLT_COLORFILL, &ddbltfx );
|
|
if( SUCCEEDED(hr) )
|
|
return;
|
|
|
|
if( hr == DDERR_SURFACELOST )
|
|
{
|
|
if( FAILED( RestoreSurfaces() ) )
|
|
return;
|
|
}
|
|
|
|
if( hr != DDERR_WASSTILLDRAWING )
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: FlipScreen()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
VOID FlipScreen()
|
|
{
|
|
// Flip the surfaces
|
|
if( g_bFullscreen )
|
|
{
|
|
while( 1 )
|
|
{
|
|
HRESULT hr = g_pddsFrontBuffer->Flip( NULL, 0 );
|
|
|
|
if( hr == DDERR_SURFACELOST )
|
|
{
|
|
if( FAILED( RestoreSurfaces() ) )
|
|
return;
|
|
}
|
|
if( hr != DDERR_WASSTILLDRAWING )
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_pddsFrontBuffer->Blt( &g_rcWindow, g_pddsBackBuffer, NULL,
|
|
DDBLT_WAIT, NULL );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: RestoreSurfaces()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT RestoreSurfaces()
|
|
{
|
|
HRESULT hr;
|
|
HBITMAP hbm;
|
|
|
|
if( FAILED( hr = g_pddsFrontBuffer->Restore() ) )
|
|
return hr;
|
|
if( FAILED( hr = g_pddsBackBuffer->Restore() ) )
|
|
return hr;
|
|
|
|
for( DWORD i=0; i<4; i++ )
|
|
if( FAILED( hr = g_pddsShip[i]->Restore() ) )
|
|
return hr;
|
|
|
|
// Create and set the palette for the splash bitmap
|
|
g_pSplashPalette = DDUtil_LoadPalette( g_pDD, TEXT("SPLASH") );
|
|
if( NULL == g_pSplashPalette )
|
|
return E_FAIL;
|
|
|
|
// Create and set the palette for the art bitmap
|
|
g_pArtPalette = DDUtil_LoadPalette( g_pDD, TEXT("Duel8") );
|
|
if( NULL == g_pArtPalette )
|
|
return E_FAIL;
|
|
|
|
// set the palette before loading the art
|
|
g_pddsFrontBuffer->SetPalette( g_pArtPalette );
|
|
|
|
hbm = (HBITMAP)LoadImage( GetModuleHandle(NULL), TEXT("Duel8"),
|
|
IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION );
|
|
if( NULL == hbm )
|
|
return E_FAIL;
|
|
|
|
if( FAILED( hr = DDUtil_CopyBitmap( g_pddsShip[0], hbm, 0, 0, 320, 128 ) ) )
|
|
{
|
|
DeleteObject( hbm );
|
|
return E_FAIL;
|
|
}
|
|
|
|
if( FAILED( hr = DDUtil_CopyBitmap( g_pddsShip[1], hbm, 0, 128, 320, 128 ) ) )
|
|
{
|
|
DeleteObject( hbm );
|
|
return E_FAIL;
|
|
}
|
|
|
|
if( FAILED( hr = DDUtil_CopyBitmap( g_pddsShip[2], hbm, 0, 256, 320, 128 ) ) )
|
|
{
|
|
DeleteObject( hbm );
|
|
return E_FAIL;
|
|
}
|
|
|
|
if( FAILED( hr = DDUtil_CopyBitmap( g_pddsShip[3], hbm, 0, 384, 320, 128 ) ) )
|
|
{
|
|
DeleteObject( hbm );
|
|
return E_FAIL;
|
|
}
|
|
|
|
if( FAILED( hr = DDUtil_CopyBitmap( g_pddsNumbers, hbm, 0, 512, 320, 16 ) ) )
|
|
{
|
|
DeleteObject( hbm );
|
|
return E_FAIL;
|
|
}
|
|
|
|
DeleteObject( hbm );
|
|
|
|
// set colorfill colors and colorkeys according to bitmap contents
|
|
g_dwFillColor = DDUtil_ColorMatch( g_pddsShip[0], CLR_INVALID );
|
|
|
|
DDUtil_SetColorKey( g_pddsShip[0], CLR_INVALID );
|
|
DDUtil_SetColorKey( g_pddsShip[1], CLR_INVALID );
|
|
DDUtil_SetColorKey( g_pddsShip[2], CLR_INVALID );
|
|
DDUtil_SetColorKey( g_pddsShip[3], CLR_INVALID );
|
|
DDUtil_SetColorKey( g_pddsNumbers, CLR_INVALID );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: SetGamePalette()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
VOID SetGamePalette()
|
|
{
|
|
if( g_pddsFrontBuffer )
|
|
g_pddsFrontBuffer->SetPalette( g_pArtPalette );
|
|
}
|
|
|
|
|
|
|
|
|