// remove.c

// Egoboo, Copyright (C) 2000 Aaron Bishop

#include "egoboo.h"

// Egoboo, Copyright (C) 2000 Aaron Bishop
/* The following is a description of how we are going to split this file into
** several files.  The first step is to mark which functions go into which
** files.  To do this, a simple one line comment will be used.  The first three
** characters on the line will be '//!'.  This is then followed by the name of
** the file to put the following lines into.  The indicated file will be used
** until the next marker is found.  The utility that will do the split will
** simply append the given file until a new marker is found.  If a file is
** given that has not been seen before, the utility will create a new file.
**
** Note that note every function will have a tag.  For example, the directory
** functions are grouped together, so only one tag is used.
**
** A special file name of ! will indicate the section should not be put into
** any file.  Functions that are commented out will use this feature.  Also,
** the first line of this file has this special marker to skip this comment.
**
** The following is a list of currently used file names with a short
** description to indicate what goes in that file.
**
** (The sections marked with * will be for ports)
**
** script.c     - Scripting functions (mostly for AI)
** camera.c     - Camera movement
** char.c       - Character logic
** config.c     - Configuration files
** win-files.c  - Directory / File management (*)
** game.c       - Game logic
** input.c      - Input (* mouse, keyboard, joystick)
** menu.c       - Menuing
** network.c    - Network (*)
** sound.c      - Sound and music (*)
** passage.c    - All passage functions
** particle.c   - Particle engine
** enchant.c    - Enchantments
** graphic.c    - Platform independent graphics functions
** module.c     - Work with modules
**
** (Hyphenated names belong to ports)
*/
#include "full.h"

// SDL specific declarations
SDL_Joystick *sdljoya = NULL;
SDL_Joystick *sdljoyb = NULL;
Uint8 *sdlkeybuffer = NULL;
#define SDLKEYDOWN(k) (sdlkeybuffer[k])

// OPENGL specific declarations
GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0};  /* White diffuse light. */
GLfloat light_position[] = {10.0, 10.0, 30.0, 1.0};  /* nonInfinite light location. */
int win_id;
static GLuint texName;

//------------------------------------------------------------------------------
//Functions I Bothered to List--------------------------------------------------
//------------------------------------------------------------------------------
//
void find_all_players();
void let_character_think(int character);
void change_character(unsigned short cnt, unsigned short profile, unsigned char skin,
     unsigned char leavewhich);
/* PORT
extern "C" { int WaveLoadFile(char *, UINT *, DWORD *, WAVEFORMATEX **, BYTE **); }
*/
void spawn_poof(unsigned short character, unsigned short profile);
void debug_message(char *text);
void kill_character(unsigned short character, unsigned short killer);
unsigned short change_armor(unsigned short character, unsigned short skin);
void draw_trim_box(int left, int top, int right, int bottom);
void reset_character_alpha(unsigned short character);
void export_one_character_profile(char *szSaveName, unsigned short character);
void export_one_character_skin(char *szSaveName, unsigned short character);
void export_one_character_name(char *szSaveName, unsigned short character);
void drop_all_items(unsigned short character);
void drop_keys(unsigned short character);
void copy_file_to_all_players(char *source, char *dest);
void copy_file_to_host(char *source, char *dest);
void copy_directory_to_host(char *source, char *dest);
void disenchant_character(unsigned short cnt);
void give_experience(int character, int amount, unsigned char xptype);
int spawn_one_character(float x, float y, float z, int profile, unsigned char team,
unsigned char skin, unsigned short facing, char *name, int override);

#ifdef _MACOS
#define FILENAME(x) os_cvrt_filename(x,':')
#endif
#ifdef _LINUX
#define FILENAME(x) x
#endif
#ifdef _WIN32
#define FILENAME(x) os_cvrt_filename(x,'\\')
#endif

//---------------------------------------------------------------------------------------------
//__inline int __get_level(unsigned char x, unsigned char y, unsigned int fan)
//{
    // ZZ> This function returns the height of a point within a mesh fan, fast
//    int z0, z1, z2, z3;         // Height of each fan corner
//    int zleft, zright,zdone;    // Weighted height of each side


//    x = (x&127)>>4;             // 8 divisions
//    y = (y&127)>>4;             // 8 divisions
//    z0 = meshvrtz[meshvrtstart[fan]+0];
//    z1 = meshvrtz[meshvrtstart[fan]+1];
//    z2 = meshvrtz[meshvrtstart[fan]+2];
//    z3 = meshvrtz[meshvrtstart[fan]+3];
//    switch(y)
//    {
//        // Fully top
//        case 0:
//            zleft = z0<<3;
//            zright = z1<<3;
//            break;
//        case 1:
//            zleft = (z0<<3)-z0+z3;
//            zright = (z1<<3)-z1+z2;
//            break;
//        case 2:
//            z0 = z0<<1;
//            z3 = z3<<1;
//            zleft = z0+z0+z0+z3;
//            z1 = z1<<1;
//            z2 = z2<<1;
//            zright = z1+z1+z1+z2;
//            break;
//        case 3:
//            zleft = (z0<<2)+z0+z3+z3+z3;
//            zright = (z1<<2)+z1+z2+z2+z2;
//            break;
//        case 4:
//            zleft = (z0<<2)+(z3<<2);
//            zright = (z1<<2)+(z2<<2);
//            break;
//        case 5:
//            zleft = z0+z0+z0+(z3<<2)+z3;
//            zright = z1+z1+z1+(z2<<2)+z2;
//            break;
//        case 6:
//            z0 = z0<<1;
//            z3 = z3<<1;
//            zleft = z0+z3+z3+z3;
//            z1 = z1<<1;
//            z2 = z2<<1;
//            zright = z1+z2+z2+z2;
//            break;
//        case 7:
//            zleft = z0+(z3<<3)-z3;
//            zright = z1+(z2<<3)-z2;
//            break;
//        // Fully bottom done in next fan as fully top
//    }


//    switch(y)
//    {
//        // Fully left
//        case 0:
//            zdone = zleft<<3;
//            break;
//        case 1:
//            zdone = (zleft<<3)-zleft+zright;
//            break;
//        case 2:
//            zleft = zleft<<1;
//            zright = zright<<1;
//            zdone = zleft+zleft+zleft+zright;
//            break;
//        case 3:
//            zdone = (zleft<<2)+zleft+zright+zright+zright;
//            break;
//        case 4:
//            zdone = (zleft<<2)+(zright<<2);
//            break;
//        case 5:
//            zdone = zleft+zleft+zleft+(zright<<2)+zright;
//            break;
//        case 6:
//            zleft = zleft<<1;
//            zright = zright<<1;
//            zdone = zleft+zright+zright+zright;
//            break;
//        case 7:
//            zdone = zleft+(zright<<3)-zright;
//            break;
//        // Fully right done in next fan as fully left
//    }

//    return ((zdone>>6)+RAISE);
//}

//--------------------------------------------------------------------------------------------
/*PORT
void directx_setup_error(HWND hWnd, HRESULT ddrval, char *szerrortext)
{
    // ZZ> This function displays an error message
    // Steinbach's Guideline for Systems Programming:
    //   Never test for an error condition you don't know how to handle.
    char                buf[256];
    sprintf(buf, "%d... %s\n", (ddrval&65535), szerrortext);
    MessageBox(hWnd, buf, "ERROR", MB_OK);
    release_grfx();
    DestroyWindow(hWnd);
}
*/

//--------------------------------------------------------------------------------------------
/*PORT
void clear_surface(LPDIRECTDRAWSURFACE lpDDS)
{
    // ZZ> This function clears a surface to black
    DDBLTFX bltfx;
    ZeroMemory(&bltfx, sizeof(bltfx)); // Sets dwFillColor to 0 as well
    bltfx.dwSize = sizeof(bltfx);
    lpDDS->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &bltfx);
}
*/

//--------------------------------------------------------------------------------------------
/*PORT
DWORD transform_vertices(DWORD number, D3DLVERTEX v[], D3DTLVERTEX vt[])
{
    // ZZ> This function projects a bunch of vertices onto the screen
    //     and returns FALSE if any made it
    D3DTRANSFORMDATA Data;
    DWORD Offscreen;


    Data.dwSize = sizeof(Data);
    Data.lpIn = v;
    Data.dwInSize = sizeof(v[0]);
    Data.lpOut = vt;
    Data.dwOutSize = sizeof(vt[0]);
    Data.lpHOut = NULL;
    Data.dwClip = 0;
    Data.dwClipIntersection = 0;
    Data.dwClipUnion = 0;
    lpD3DVViewport->TransformVertices(number, &Data, D3DTRANSFORM_UNCLIPPED, &Offscreen);
    return Offscreen;
}
*/

//--------------------------------------------------------------------------------------------
/*PORT
void render_background(unsigned short texture)
{
    // ZZ> This function draws the large background
    D3DTLVERTEX vtlist[4];
    DWORD light;
    float size;
    unsigned short rotate;
    float sinsize, cossize;
    D3DVALUE x, y, z, rhw, u, v;


    // Flat shade this
    if(shading != D3DSHADE_FLAT)
        lpD3DDDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_FLAT);


    // Choose texture and matrix
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, txTexture[texture].GetHandle());



    // Figure out the screen coordinates of its corners
    x = scrx/2.0;
    y = scry/2.0;
    z = .99999;
    rhw = 1.0;
    u = waterlayeru[1];
    v = waterlayerv[1];
    rotate=16384+8192-camturnleftrightshort;
    rotate = rotate>>2;
    size = x + y + 1;
    sinsize = turntosin[rotate]*size;
    cossize = turntosin[(rotate+4096)&16383]*size;

    light = (0xffffffff);

    vtlist[0].dvSX = x + cossize;
    vtlist[0].dvSY = y - sinsize;
    vtlist[0].dvSZ = z;
    vtlist[0].dvRHW = rhw;
    vtlist[0].dcColor = light;
    vtlist[0].dcSpecular = 0;
    vtlist[0].dvTU = 0+u;
    vtlist[0].dvTV = 0+v;

    vtlist[1].dvSX = x + sinsize;
    vtlist[1].dvSY = y + cossize;
    vtlist[1].dvSZ = z;
    vtlist[1].dvRHW = rhw;
    vtlist[1].dcColor = light;
    vtlist[1].dcSpecular = 0;
    vtlist[1].dvTU = backgroundrepeat+u;
    vtlist[1].dvTV = 0+v;

    vtlist[2].dvSX = x - cossize;
    vtlist[2].dvSY = y + sinsize;
    vtlist[2].dvSZ = z;
    vtlist[2].dvRHW = rhw;
    vtlist[2].dcColor = light;
    vtlist[2].dcSpecular = 0;
    vtlist[2].dvTU = backgroundrepeat+u;
    vtlist[2].dvTV = backgroundrepeat+v;

    vtlist[3].dvSX = x - sinsize;
    vtlist[3].dvSY = y - cossize;
    vtlist[3].dvSZ = z;
    vtlist[3].dvRHW = rhw;
    vtlist[3].dcColor = light;
    vtlist[3].dcSpecular = 0;
    vtlist[3].dvTU = 0+u;
    vtlist[3].dvTV = backgroundrepeat+v;

    // Go on and draw it
    lpD3DDDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, D3DVT_TLVERTEX, (LPVOID)vtlist, 4, NULL);

    // Return to normal shading
    if(shading != D3DSHADE_FLAT)
        lpD3DDDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, shading);
}
*/

//--------------------------------------------------------------------------------------------
/*PORT
void render_foreground_overlay(unsigned short texture)
{
    // ZZ> This function draws the large transparent overlay
    D3DTLVERTEX vtlist[4];
    DWORD light;
    float size;
    unsigned short rotate;
    float sinsize, cossize;
    D3DVALUE x, y, z, rhw, u, v;


    // Flat shade this
    if(shading != D3DSHADE_FLAT)
        lpD3DDDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_FLAT);


    // Choose texture and matrix
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, txTexture[texture].GetHandle());



    // Figure out the screen coordinates of its corners
    x = scrx/2.0;
    y = scry/2.0;
    z = 0;
    rhw = 1.0;
    u = waterlayeru[0];
    v = waterlayerv[0];
    rotate=16384+8192-camturnleftrightshort;
    rotate = rotate>>2;
    size = x + y + 1;
    sinsize = turntosin[rotate]*size;
    cossize = turntosin[(rotate+4096)&16383]*size;

    light = (0x00ffffff);
    light |= (waterlayeralpha[0]<<24);

    vtlist[0].dvSX = x + cossize;
    vtlist[0].dvSY = y - sinsize;
    vtlist[0].dvSZ = z;
    vtlist[0].dvRHW = rhw;
    vtlist[0].dcColor = light;
    vtlist[0].dcSpecular = 0;
    vtlist[0].dvTU = 0+u;
    vtlist[0].dvTV = 0+v;

    vtlist[1].dvSX = x + sinsize;
    vtlist[1].dvSY = y + cossize;
    vtlist[1].dvSZ = z;
    vtlist[1].dvRHW = rhw;
    vtlist[1].dcColor = light;
    vtlist[1].dcSpecular = 0;
    vtlist[1].dvTU = foregroundrepeat+u;
    vtlist[1].dvTV = 0+v;

    vtlist[2].dvSX = x - cossize;
    vtlist[2].dvSY = y + sinsize;
    vtlist[2].dvSZ = z;
    vtlist[2].dvRHW = rhw;
    vtlist[2].dcColor = light;
    vtlist[2].dcSpecular = 0;
    vtlist[2].dvTU = foregroundrepeat+u;
    vtlist[2].dvTV = foregroundrepeat+v;

    vtlist[3].dvSX = x - sinsize;
    vtlist[3].dvSY = y - cossize;
    vtlist[3].dvSZ = z;
    vtlist[3].dvRHW = rhw;
    vtlist[3].dcColor = light;
    vtlist[3].dcSpecular = 0;
    vtlist[3].dvTU = 0+u;
    vtlist[3].dvTV = foregroundrepeat+v;


    // Go on and draw it
    lpD3DDDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, D3DVT_TLVERTEX, (LPVOID)vtlist, 4, NULL);


    // Return to normal shading
    if(shading != D3DSHADE_FLAT)
        lpD3DDDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, shading);
}
*/

//--------------------------------------------------------------------------------------------
/*PORT
long FAR PASCAL window_refresh( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    // ZZ> This function gets called whenever we get a Windows message
    switch(message)
    {
        case WM_ACTIVATEAPP:
            // Start up
            appactive = wParam;
            break;
        case WM_SETCURSOR:
            // Make sure the hardware cursor stays off
            SetCursor(NULL);
            return TRUE;
        case WM_DESTROY:
            // Shut down
            quit_game();
//            CoUninitialize();
            break;
   }
   return DefWindowProc(hWnd, message, wParam, lParam);
}
*/

//--------------------------------------------------------------------------------------------
/*PORT
BOOL PASCAL enumcallback(GUID FAR* lpGUID, LPSTR lpDriverDesc, LPSTR lpDriverName, LPVOID lpContext)
{
    // BB> This is the callback routine for enumerating the 3D cards
    //     so we can see if the user has a Voodoo or not
    LPDIRECTDRAW lpDD;

    if(DirectDrawCreate(lpGUID, &lpDD, NULL) != DD_OK)
        return(1);                  // SKIP BAD ONES
    if(lpGUID!=NULL)                // Pick this guy first
    {
        enum_id=lpGUID;
        enum_nonnull=1;
        sprintf(enum_desc,"%s",lpDriverDesc);
        particletrans = 0x40000000;  //  Improve smoke for Voodoo
        antialiastrans = 0x60000000;  // Improve antialiasing for Voodoo
        lpDD->Release();
    }
    else
    {
        if(!enum_nonnull)           // If we don't have anything else
        {
        	enum_id=lpGUID;
        	sprintf(enum_desc,"%s",lpDriverDesc);
        	lpDD->Release();
        }
    }
    return(1);                      // Go onto next one
}
*/

//--------------------------------------------------------------------------------------------
/*PORT
BOOL FAR PASCAL InitJoystickInput(LPCDIDEVICEINSTANCE pdinst,
                                  LPVOID pvRef)
{
    // ZZ> This function turns on up to two joysticks
    LPDIRECTINPUT pdi = lpDI;
    LPDIRECTINPUTDEVICE pdev;


    // Create the DirectInput joystick device
    if(pdi->CreateDevice(pdinst->guidInstance, &pdev, NULL) != DI_OK)
    {
        return DIENUM_CONTINUE;
    }

    // Do important stuff
    if(pdev->SetDataFormat(&c_dfDIJoystick) != DI_OK)
    {
        pdev->Release();
        return DIENUM_CONTINUE;
    }

    // Do more important stuff
    if(pdev->SetCooperativeLevel(hGlobalWindow, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND) != DI_OK)
    {
        pdev->Release();
        return DIENUM_CONTINUE;
    }




    // Set joystick range on X axis
    DIPROPRANGE diprg;
    diprg.diph.dwSize       = sizeof(diprg);
    diprg.diph.dwHeaderSize = sizeof(diprg.diph);
    diprg.diph.dwObj        = DIJOFS_X;
    diprg.diph.dwHow        = DIPH_BYOFFSET;
    diprg.lMin              = -1000;
    diprg.lMax              = +1000;
    if(pdev->SetProperty(DIPROP_RANGE, &diprg.diph) != DI_OK)
    {
        pdev->Release();
        return FALSE;
    }
    // Set dead zone to 10%
    DIPROPDWORD dipdw;
    dipdw.diph.dwSize       = sizeof(dipdw);
    dipdw.diph.dwHeaderSize = sizeof(dipdw.diph);
    dipdw.diph.dwObj        = DIJOFS_X;
    dipdw.diph.dwHow        = DIPH_BYOFFSET;
    dipdw.dwData            = 1000;
    if(pdev->SetProperty(DIPROP_DEADZONE, &dipdw.diph) != DI_OK)
    {
        pdev->Release();
        return FALSE;
    }


    // Set joystick range on Y axis
    diprg.diph.dwSize       = sizeof(diprg);
    diprg.diph.dwHeaderSize = sizeof(diprg.diph);
    diprg.diph.dwObj        = DIJOFS_Y;
    diprg.diph.dwHow        = DIPH_BYOFFSET;
    diprg.lMin              = -1000;
    diprg.lMax              = +1000;
    if(pdev->SetProperty(DIPROP_RANGE, &diprg.diph) != DI_OK)
    {
        pdev->Release();
        return FALSE;
    }
    // Set dead zone to 10%
    dipdw.diph.dwSize       = sizeof(dipdw);
    dipdw.diph.dwHeaderSize = sizeof(dipdw.diph);
    dipdw.diph.dwObj        = DIJOFS_Y;
    dipdw.diph.dwHow        = DIPH_BYOFFSET;
    dipdw.dwData            = 1000;
    if(pdev->SetProperty(DIPROP_DEADZONE, &dipdw.diph) != DI_OK)
    {
        pdev->Release();
        return FALSE;
    }


    // Make it simple to access
    numjoy++;
    if(numjoy==1)
    {
        lpDIDJoyA = pdev;
        joyaon = TRUE;
    }
    if(numjoy==2)
    {
        lpDIDJoyB = pdev;
        joybon = TRUE;
    }


    return TRUE;
}
*/

//--------------------------------------------------------------------------------------------
/*PORT
BOOL FAR PASCAL ConnectionsCallback(
     LPCGUID lpguidSP, LPVOID lpConnection, DWORD dwConnectionSize,
     LPCDPNAME lpName, DWORD dwFlags, LPVOID lpContext)
{
    // ZZ> This is a callback
    HWND     hWnd = (HWND) lpContext;
    LPVOID   lpConnectionBuffer;
    char cTmp;
    int cnt;


    if(numservice < MAXSERVICE)
    {
        // make space for connection 
        lpConnectionBuffer = GlobalAllocPtr(GHND, dwConnectionSize);
        if (lpConnectionBuffer != NULL)
        {
            // Store connection data for later
            memcpy(lpConnectionBuffer, lpConnection, dwConnectionSize);


            // Save that pointer
            netlpconnectionbuffer[numservice] = lpConnectionBuffer;


            // Copy the name
            cnt = 0;
            cTmp = lpName->lpszShortNameA[cnt];
            while(cnt < NETNAMESIZE-1 && cTmp != 0 && cTmp != ' ')
            {
                netservicename[numservice][cnt] = cTmp;
                cnt++;
                cTmp = lpName->lpszShortNameA[cnt];
            }
            netservicename[numservice][cnt] = 0;
            if(globalnetworkerr)  fprintf(globalnetworkerr, "    %2d. %s\n", numservice, netservicename[numservice]);


            // Make it official
            numservice++;
        }
    }
    else
    {
        // Say we didn't have room
        if(globalnetworkerr)  fprintf(globalnetworkerr, "    ERROR:  Too many...\n");
    }
    return TRUE;
}

*/

//--------------------------------------------------------------------------------------------
/*PORT
static BOOL setup_directx(HINSTANCE hInstance, int nCmdShow)
{
    // ZZ> This function creates a window and sets up DirectX
    DSBUFFERDESC        dsbd;
    D3DFINDDEVICERESULT result;
    D3DVIEWPORT         viewport;
    HWND                hWnd;
    WNDCLASS            wc;
    DDSURFACEDESC       ddsd;
    HRESULT             ddrval;
    HRESULT             dsrval;
    int                 goodsound = FALSE;


    // Set up and register window class
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = window_refresh;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = NULL;
    wc.lpszMenuName = NAME;
    wc.lpszClassName = NAME;
    RegisterClass(&wc);

    
    // Create a window
    hWnd = CreateWindowEx(
    	WS_EX_TOPMOST,
	    NAME,
    	TITLE,
    	WS_POPUP,
    	0, 0,
    	GetSystemMetrics(SM_CXSCREEN),
	    GetSystemMetrics(SM_CYSCREEN),
    	NULL,
    	NULL,
    	hInstance,
    	NULL);
    if(!hWnd)
    {
        return FALSE;
    }
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);


    // Save the pointer for later
    hGlobalWindow = hWnd;


    // Get memory for the mesh
    if(!get_mesh_memory())
    {
        directx_setup_error(hWnd, 0, "Reduce the maximum number of vertices!!!  See SETUP.TXT");
        return FALSE;
    }


    // BB> Find if the user has a Voodoo
	DirectDrawEnumerate(enumcallback,NULL);
    // Create the main DirectDraw object
    ddrval = DirectDrawCreate(enum_id, &lpDD, NULL);
    if(ddrval != DD_OK) { directx_setup_error(hWnd, ddrval, "DirectDraw failed BIG.  See SETUP.TXT");  return FALSE; }


    // Get exclusive mode
    ddrval = lpDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
    if(ddrval != DD_OK) { directx_setup_error(hWnd, ddrval, "DirectDraw isn't cooperating.  See SETUP.TXT");  return FALSE; }


    // Set the display mode
    ddrval = lpDD->SetDisplayMode(scrx, scry, scrd);
    if(ddrval != DD_OK) { directx_setup_error(hWnd, ddrval, "Display not set correctly.  See SETUP.TXT");  return FALSE; }


    // Create a primary surface
    ZeroMemory(&ddsd, sizeof(ddsd));  ddsd.dwSize = sizeof(ddsd);
    ddsd.dwFlags = DDSD_CAPS;
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
    ddrval = lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL);
    if(ddrval != DD_OK) { directx_setup_error(hWnd, ddrval, "Primary surface not created.  See SETUP.TXT");  return FALSE; }



    // Attach a back buffer to it...
    ZeroMemory(&ddsd, sizeof(ddsd));  ddsd.dwSize = sizeof(ddsd);
    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
    ddsd.dwWidth = scrx;
    ddsd.dwHeight = scry;
    if(videoacceleratoron)
        ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY;
    else
        ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER | DDSCAPS_3DDEVICE | DDSCAPS_SYSTEMMEMORY;
    ddrval = lpDD->CreateSurface(&ddsd, &lpDDSBack, NULL);
    if(ddrval != DD_OK) { directx_setup_error(hWnd, ddrval, "Backbuffer not created.  See SETUP.TXT");  return FALSE; }
    if(videoacceleratoron)
    {
        ddrval = lpDDSPrimary->AddAttachedSurface(lpDDSBack);
        if(ddrval != DD_OK) { directx_setup_error(hWnd, ddrval, "Backbuffer not attached.  See SETUP.TXT");  return FALSE; }
    }


    // Set the palette if in an indexed color mode
    if(scrd == 8)
    {
        lpDDPPalette = DDLoadPalette(lpDD, NULL); //basicdat\\bestpal.pal
        ddrval = lpDDSPrimary->SetPalette(lpDDPPalette);
        if(ddrval != DD_OK) { directx_setup_error(hWnd, ddrval, "Primary palette error.  See SETUP.TXT");  return FALSE; }
        ddrval = lpDDSBack->SetPalette(lpDDPPalette);
        if(ddrval != DD_OK) { directx_setup_error(hWnd, ddrval, "Back palette error");  return FALSE; }
    }


    // ZB> ...And attach a z-buffer to that
    ZeroMemory(&ddsd, sizeof(ddsd));  ddsd.dwSize = sizeof(ddsd);
    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_ZBUFFERBITDEPTH;
    ddsd.dwWidth = scrx;
    ddsd.dwHeight = scry;
    ddsd.dwZBufferBitDepth = scrz;
    if(videoacceleratoron)
      ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
    else
      ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_SYSTEMMEMORY;
    ddrval = lpDD->CreateSurface(&ddsd, &lpDDSZbuffer, NULL);
    if(ddrval != DD_OK) { directx_setup_error(hWnd, ddrval, "Zbuffer not created.  See SETUP.TXT");  return FALSE; }
    ddrval = lpDDSBack->AddAttachedSurface(lpDDSZbuffer);
    if(ddrval != DD_OK) { directx_setup_error(hWnd, ddrval, "Zbuffer not attached.  See SETUP.TXT");  return FALSE; }


    // Get a Direct3D object
    ddrval = lpDD->QueryInterface(IID_IDirect3D2, (LPVOID *)&lpD3D);
    if(ddrval != S_OK) { directx_setup_error(hWnd, ddrval, "Direct3D failed BIG.  See SETUP.TXT");  return FALSE; }


    // Determine what rendering device to use
    switch(deviceguid)
    {
        case GID_HAL:
            result.guid = IID_IDirect3DHALDevice;
            break;
        case GID_RAMP:
            result.guid = IID_IDirect3DRampDevice;
            break;
        case GID_MMX:
            result.guid = IID_IDirect3DMMXDevice;
            break;
        case GID_RGB:
            result.guid = IID_IDirect3DRGBDevice;
            break;
    }

    // Create the D3D device
    ddrval = lpD3D->CreateDevice(result.guid, lpDDSBack, &lpD3DDDevice);
    if(ddrval != DD_OK) { directx_setup_error(hWnd, ddrval, "Direct3D device not created.  See SETUP.TXT");  return FALSE; }


    // Create a viewport
    ZeroMemory(&viewport, sizeof(viewport));
    viewport.dwSize   = sizeof(viewport);
    viewport.dwWidth  = scrx;
    viewport.dwHeight = scry;
    viewport.dvScaleX = (float) scry;
    viewport.dvScaleY = (float) scry;
    viewport.dvMaxX   = D3DVAL(1.0);
    viewport.dvMaxY   = D3DVAL(1.0);
    ddrval = lpD3D->CreateViewport(&lpD3DVViewport, NULL);
    if(ddrval != D3D_OK) { directx_setup_error(hWnd, ddrval, "Viewport not created.  See SETUP.TXT");  return FALSE; }
    ddrval = lpD3DDDevice->AddViewport(lpD3DVViewport);
    if(ddrval != D3D_OK) { directx_setup_error(hWnd, ddrval, "Viewport not added.  See SETUP.TXT");  return FALSE; }
    ddrval = lpD3DVViewport->SetViewport(&viewport);
    if(ddrval != D3D_OK) { directx_setup_error(hWnd, ddrval, "Viewport not set.  See SETUP.TXT");  return FALSE; }
    ddrval = lpD3DDDevice->SetCurrentViewport(lpD3DVViewport);
    if(ddrval != D3D_OK) { directx_setup_error(hWnd, ddrval, "Viewport not current.  See SETUP.TXT");  return FALSE; }


    // Make a material if we're in RAMP
    if(deviceguid == GID_RAMP)
    {
        D3DMATERIALHANDLE hMat;
        ddrval = lpD3D->CreateMaterial(&lpD3DMMaterial, NULL);
        if(ddrval != DD_OK) { directx_setup_error(hWnd, ddrval, "Material interface error.  See SETUP.TXT");  return FALSE; }
        memset(&D3DMBackMaterial, 0, sizeof(D3DMATERIAL));
        D3DMBackMaterial.dwSize = sizeof(D3DMATERIAL);
        D3DMBackMaterial.dcvDiffuse.r = 1;
        D3DMBackMaterial.dcvDiffuse.g = 1;
        D3DMBackMaterial.dcvDiffuse.b = 1;
        D3DMBackMaterial.dcvAmbient.r = 0;
        D3DMBackMaterial.dcvAmbient.g = 0;
        D3DMBackMaterial.dcvAmbient.b = 0;
        D3DMBackMaterial.dcvSpecular.r = 0;
        D3DMBackMaterial.dcvSpecular.g = 0;
        D3DMBackMaterial.dcvSpecular.b = 0;
        D3DMBackMaterial.dvPower = 0;
        D3DMBackMaterial.dwRampSize = 16;
        ddrval = lpD3DMMaterial->SetMaterial(&D3DMBackMaterial);
        if(ddrval != D3D_OK) { directx_setup_error(hWnd, ddrval, "Material not set.  See SETUP.TXT");  return FALSE; }
        ddrval = lpD3DMMaterial->GetHandle(lpD3DDDevice, &hMat);
        if(ddrval != D3D_OK) { directx_setup_error(hWnd, ddrval, "Material handle unavailable.  See SETUP.TXT");  return FALSE; }
		ddrval = lpD3DDDevice->SetLightState(D3DLIGHTSTATE_MATERIAL, hMat);
        if(ddrval != D3D_OK) { directx_setup_error(hWnd, ddrval, "Material light not set.  See SETUP.TXT");  return FALSE; }
    }




	// Initialize and set the matrices
    mWorld = IdentityMatrix();
    mViewSave = ViewMatrix(D3DVECTOR(0,0,0), D3DVECTOR(0,0,-1), D3DVECTOR(0,1,0), 0);
//    make_camera_matrix();
    mProjection = ProjectionMatrix(.001f, 2000.0f, (float)(FOV*PI/180)); // 60 degree FOV
//old    mProjection = MatrixMult(Translate(0, 0, -.99999f), mProjection); // Fix Z value...
//    mProjection = MatrixMult(ScaleXYZ(1, -1, 10000), mProjection);  // ...'cause it needs it
//better    mProjection = MatrixMult(Translate(0, 0, -.999999f), mProjection); // Fix Z value...
//    mProjection = MatrixMult(ScaleXYZ(1, -1, 100000), mProjection);  // ...'cause it needs it
//works    mProjection = MatrixMult(Translate(0, 0, -.99999859), mProjection); // Fix Z value...
//    mProjection = MatrixMult(ScaleXYZ(1, -1, 500000), mProjection);  // ...'cause it needs it
//    mProjection = MatrixMult(ScaleXYZ(1, -1, 100000), mProjection);  // ...'cause it needs it


    mProjection = MatrixMult(Translate(0, 0, -.999996), mProjection); // Fix Z value...
    mProjection = MatrixMult(ScaleXYZ(-1, -1, 100000), mProjection);  // HUK // ...'cause it needs it
    lpD3DDDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mView);
    lpD3DDDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mProjection);


    // ZB> Set the render states
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_ZENABLE,TRUE);
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE,TRUE);
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_ZFUNC,D3DCMP_LESSEQUAL);


    // Set the render states
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_ANTIALIAS,antialias);
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP);
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_FILLMODE,fillmode);
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_CULLMODE,D3DCULL_CCW);
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_SPECULARENABLE,TRUE);
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_ZVISIBLE,FALSE);
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_SUBPIXEL,TRUE);
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_MONOENABLE,FALSE);
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE,shading);
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_COLORKEYENABLE, TRUE);


    // Set the player render options
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_TEXTUREPERSPECTIVE,perspective);
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMAG,filter);
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMIN,filter);
    lpD3DDDevice->SetRenderState(D3DRENDERSTATE_DITHERENABLE,dither);
    if(deviceguid == GID_RAMP || deviceguid == GID_RGB)
    {
        lpD3DDDevice->SetRenderState(D3DRENDERSTATE_MONOENABLE, TRUE);
    }


    // Turn that sound on...
    if(soundon)
    {
        // Turn it on
        dsrval = DirectSoundCreate(NULL, &lpDirectSound, NULL);
        if(dsrval != DS_OK) { soundon = 0; }
    }
    if(soundon)
    {
        // Set the cooperativity level...  Need 22kHz, 8 bit, stereo sounds
        dsrval = lpDirectSound->SetCooperativeLevel(hWnd, DSSCL_PRIORITY);
        if(dsrval != DS_OK)
        {
            dsrval = lpDirectSound->SetCooperativeLevel(hWnd, DSSCL_NORMAL);
            if(dsrval != DS_OK)
            {
                soundon = 0;
            }
        }
        else
        {
            goodsound = TRUE;
        }
    }
    if(soundon)
    {
        // Create a primary sound buffer
        memset(&dsbd, 0, sizeof(DSBUFFERDESC));
        dsbd.dwSize = sizeof(DSBUFFERDESC);
        dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;// | DSBCAPS_GETCURRENTPOSITION2;
        dsbd.dwBufferBytes = 0;
        dsbd.lpwfxFormat = NULL;
        dsrval = lpDirectSound->CreateSoundBuffer(&dsbd, &lpDSPrimaryBuffer, NULL);
        if(dsrval != DS_OK) { soundon = -5; }
    }
    if(soundon)
    {
        if(goodsound)
        {
            // Make it do good sounds
            WAVEFORMATEX wf;
            memset(&wf, 0, sizeof(WAVEFORMATEX)); 
            wf.wFormatTag = WAVE_FORMAT_PCM; 
            wf.nChannels = 2; 
            wf.nSamplesPerSec = 22050; 
            wf.nBlockAlign = 4; 
            wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign; 
            wf.wBitsPerSample = 16; 
            lpDSPrimaryBuffer->SetFormat(&wf);
        }
        // Start playing silence
        lpDSPrimaryBuffer->Play(0, 0, 0);
    }


    // Create the DirectInput object
    ddrval = DirectInputCreate(hInstance, DIRECTINPUT_VERSION, &lpDI, NULL);
    if(ddrval != DI_OK) { directx_setup_error(hWnd, ddrval, "DirectInput failed BIG.  See SETUP.TXT");  return FALSE; }


    // Create a mouse interface
    if(mouseon)
    {
        // Turn it on
        ddrval = lpDI->CreateDevice(GUID_SysMouse, &lpDIDMouse, NULL);
        if(ddrval != DI_OK) { mouseon = 0;  directx_setup_error(hWnd, 0, "Mouse not turned on!!!");}
    }
    if(mouseon)
    {
        // Data format
        ddrval = lpDIDMouse->SetDataFormat(&c_dfDIMouse);
        if(ddrval != DI_OK) { mouseon = 0;  directx_setup_error(hWnd, 0, "Mouse not formatted!!!");}
    }
    if(mouseon)
    {
        // Cooperativity levels
        ddrval = lpDIDMouse->SetCooperativeLevel(hWnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND);
        if(ddrval != DI_OK) { mouseon = 0;  directx_setup_error(hWnd, 0, "Mouse not cooperating!!!");}
    }


    // Create a keyboard interface
    if(keyon)
    {
        // Turn it on
        ddrval = lpDI->CreateDevice(GUID_SysKeyboard, &lpDIDKey, NULL);
        if(ddrval != DI_OK) { keyon = 0;  directx_setup_error(hWnd, 0, "Keyboard not turned on!!!");}
    }
    if(keyon)
    {
        // Data format
        ddrval = lpDIDKey->SetDataFormat(&c_dfDIKeyboard);
        if(ddrval != DI_OK) { keyon = 0;  directx_setup_error(hWnd, 0, "Keyboard not formatted!!!");}
    }
    if(keyon)
    {
        // Cooperativity levels
        ddrval = lpDIDKey->SetCooperativeLevel(hWnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
        if(ddrval != DI_OK) { keyon = 0;  directx_setup_error(hWnd, 0, "Keyboard not cooperating!!!");}
    }


    // Enumerate joysticks ( yeah )
    lpDI->EnumDevices(DIDEVTYPE_JOYSTICK, InitJoystickInput, lpDI, DIEDFL_ATTACHEDONLY);


    // Silly stuff for trapezoidal projection
    rotmeshtopside = ((float)scrx/scry)*ROTMESHTOPSIDE/(1.33333);
    rotmeshbottomside = ((float)scrx/scry)*ROTMESHBOTTOMSIDE/(1.33333);
    rotmeshup = ((float)scrx/scry)*ROTMESHUP/(1.33333);
    rotmeshdown = ((float)scrx/scry)*ROTMESHDOWN/(1.33333);


    // Turn on networking ( or simulate it )
    setup_network();


    // Clear the surfaces to black
    SetCursor(NULL);
    clear_surface(lpDDSPrimary);
    clear_surface(lpDDSBack);
    return TRUE;
}
*/

//--------------------------------------------------------------------------------------------
/*PORT
BOOL FAR PASCAL SessionsCallback(
    LPCDPSESSIONDESC2 lpSessionDesc, LPDWORD lpdwTimeOut,
    DWORD dwFlags, LPVOID lpContext)
{
    // ZZ> This is a callback
    LPGUID lpGuid;
    char cTmp;
    int cnt;


    // Determine if the enumeration has timed out.
    if (dwFlags & DPESC_TIMEDOUT)  return FALSE;



    if(numsession < MAXSESSION)
    {
        // Make space for the session instance GUID.
        lpGuid = (LPGUID) GlobalAllocPtr(GHND, sizeof(GUID));
        if(lpGuid != NULL)
        {
            // Copy the name
            cnt = 0;
            cTmp = lpSessionDesc->lpszSessionNameA[cnt];
            while(cnt < NETNAMESIZE-1 && cTmp != 0)
            {
                if(cTmp == '_')  cTmp = ' ';
                netsessionname[numsession][cnt] = cTmp;
                cnt++;
                cTmp = lpSessionDesc->lpszSessionNameA[cnt];
            }
            netsessionname[numsession][cnt] = 0;
            if(globalnetworkerr)  fprintf(globalnetworkerr, "    %s\n", netsessionname[numsession]);


            // Store the pointer to the GUID in the list.
            *lpGuid = lpSessionDesc->guidInstance;
            netlpsessionguid[numsession] = lpGuid;


            // Make it official
            numsession++;
        }
    }
    return TRUE;
}
*/
//--------------------------------------------------------------------------------------------
/*PORT
BOOL FAR PASCAL PlayersCallback(
    DPID dpId, DWORD dwPlayerType, LPCDPNAME lpName, DWORD dwFlags, LPVOID lpContext)
{
    // ZZ> This is a callback
    char cTmp;
    int cnt;


    if(numplayer < MAXNETPLAYER)
    {
        // Copy the ID
        netplayerid[numplayer] = dpId;


        // Copy the name
        cnt = 0;
        cTmp = lpName->lpszShortNameA[cnt];
        while(cnt < NETNAMESIZE-1 && cTmp != 0 && cTmp != '\'')
        {
            netplayername[numplayer][cnt] = cTmp;
            cnt++;
            cTmp = lpName->lpszShortNameA[cnt];
        }
        netplayername[numplayer][cnt] = 0;
//        if(globalnetworkerr)  fprintf(globalnetworkerr, "    %s\n", netplayername[numplayer]);


        // Make it official
        numplayer++;
        return TRUE;
    }
    return FALSE;
}
*/
