/***************************************************************************/ /* */ /* */ /* Raven 3D Engine */ /* Copyright (C) 1996 by Softdisk Publishing */ /* */ /* Original Design: */ /* John Carmack of id Software */ /* */ /* Enhancements by: */ /* Robert Morgan of Channel 7............................Main Engine Code */ /* Todd Lewis of Softdisk Publishing......Tools,Utilities,Special Effects */ /* John Bianca of Softdisk Publishing..............Low-level Optimization */ /* Carlos Hasan..........................................Music/Sound Code */ /* */ /* */ /***************************************************************************/ #include #include #include #include #include #include "d_global.h" #include "d_disk.h" #include "d_misc.h" #include "d_video.h" #include "d_ints.h" #include "d_font.h" #include "r_refdef.h" #include "protos.h" #include "audio.h" #include "svrdos4g.h" /**** TYPES ****/ typedef struct { int x, y; int w, h; } cursor_t; /**** CONSTANTS ****/ #define KBDELAY2 10 #define MENUS 6 #define MAXSAVEGAMES 10 cursor_t cursors[MENUS][15]= { // main menu 41, 114, 55, 20, // new 41, 138, 55, 20, // quit 134, 42, 127, 19, // load 134, 62, 127, 19, // save 134, 82, 127, 19, // options 134, 102, 127, 19, // info 142, 142, 62, 15, // quit/resume 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // char menu 41, 138, 55, 20, // quit 134, 32, 127, 18, // cyborg 134, 51, 127, 18, // lizard 134, 70, 127, 18, // moo 134, 89, 127, 18, // specimen 134, 108, 127, 18, // dominatrix 142, 142, 62, 15, // back 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // load 41, 138, 55, 20, // quit 137, 34, 7, 5, 137, 44, 7, 5, 137, 54, 7, 5, 137, 64, 7, 5, 137, 74, 7, 5, 137, 84, 7, 5, 137, 94, 7, 5, 137, 104, 7, 5, 137, 114, 7, 5, 137, 124, 7, 5, 142, 142, 62, 15, // back 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // save 41, 138, 55, 20, // quit 137, 34, 7, 5, 137, 44, 7, 5, 137, 54, 7, 5, 137, 64, 7, 5, 137, 74, 7, 5, 137, 84, 7, 5, 137, 94, 7, 5, 137, 104, 7, 5, 137, 114, 7, 5, 137, 124, 7, 5, 142, 142, 62, 15, // back 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // options 41, 114, 55, 20, 41, 138, 55, 20, 134, 32, 127, 15, 134, 46, 127, 15, 134, 60, 127, 15, 134, 74, 127, 15, 134, 88, 127, 15, 134, 101, 127, 15, 134, 115, 127, 15, 142, 142, 62, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // monster menu 41, 138, 55, 20, // quit 134, 30, 127, 15, // difficulty level 0 134, 45, 127, 15, 134, 60, 127, 15, 134, 75, 127, 15, 134, 90, 127, 15, 134, 117, 127, 15, 142, 142, 62, 15, // back 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; int menumax[MENUS]= // max cursor { 7, 7, 12, 12, 10, 8 }; /**** VARIABLES ****/ pic_t *menuscreen; int menulevel, menucursor, menucurloc, menumaincursor, identity, waitanim, saveposition; longint timedelay; boolean quitmenu, menuexecute, downlevel, goright, goleft, waiting; char savedir[MAXSAVEGAMES][21]; pic_t *waitpics[4]; extern SoundCard SC; /**** FUNCTIONS ****/ void VI_DrawMaskedPic2(int x, int y, pic_t *pic) /* Draws a formatted image to the screen, masked with zero */ { byte *dest, *source, *source2; int width, height, xcor; x -= pic->orgx; y -= pic->orgy; height=pic->height; source=&pic->data; while (y<0) { source+=pic->width; height--; y++; } while (height--) { if (y<200) { dest=ylookup[y]+x; source2=y*320+x+viewbuffer; xcor=x; width=pic->width; while (width--) { if (xcor>=0 && xcor<=319 && *source) *dest=*source; else *dest=*source2; xcor++; source++; source2++; dest++; } } y++; } } void MenuCommand(void); boolean ShowQuit(void (*kbdfunction)(void)) { longint animtime, droptime; int anim, y, i, lump; short mx, my; pic_t *pics[3]; char c; boolean result; byte *scr; INT_TimerHook(NULL); scr=(byte *)malloc(64000); if (scr==NULL) MS_Error("Error allocating ShowQuit buffer"); MouseHide(); memcpy(scr,viewbuffer,64000); memcpy(viewbuffer,screen,64000); MouseShow(); if (netmode) TimeUpdate(); lump=CA_GetNamedNum("quit"); for(i=0;i<3;i++) pics[i]=CA_CacheLump(lump+i); timedelay=timecount+KBDELAY2; Wait(KBDELAY2); if (netmode) TimeUpdate(); newascii=false; anim=0; MouseHide(); if (!SC.animation || netmode) { y=68; MouseShow(); } else y=-66; droptime=timecount; animtime=timecount; while (1) { if (y>=67 && MouseGetClick(&mx,&my) && my>=110 && my<=117) { if (mx>=130 && mx<=153) { c='y'; break; } else if (mx>=162 && mx<=186) { c='n'; break; } } if (netmode) TimeUpdate(); if (newascii && y>=67) { c=lastascii; break; } if (timecount>=droptime && y<67) { if (y>=0) memcpy(ylookup[y],viewbuffer+320*y,640); y+=2; droptime=timecount+1; VI_DrawMaskedPic2(111,y,pics[anim]); if (y>=67) MouseShow(); } if (timecount>=animtime) { anim++; anim%=3; animtime+=10; MouseHide(); VI_DrawMaskedPic2(111,y,pics[anim]); MouseShow(); } } if (c=='y' || c=='Y') result=true; else result=false; droptime=timecount; animtime=timecount; if (!SC.animation || netmode) y=200; MouseHide(); while (y<199) { if (timecount>=droptime) { if (y>=0) memcpy(ylookup[y],viewbuffer+320*y,640); y+=2; droptime=timecount+1; VI_DrawMaskedPic2(111,y,pics[anim]); } if (timecount>=animtime) { anim++; anim%=3; animtime+=10; VI_DrawMaskedPic2(111,y,pics[anim]); } } memcpy(screen,viewbuffer,64000); memcpy(viewbuffer,scr,64000); for(i=0;i<3;i++) CA_FreeLump(lump+i); MouseShow(); free(scr); timedelay=timecount+KBDELAY2; turnrate=0; moverate=0; fallrate=0; strafrate=0; ResetMouse(); INT_TimerHook(kbdfunction); if (netmode) TimeUpdate(); return result; } /******************************************************************************/ void ShowMenuSliders(int value,int range) { int a, c, d, i; MouseHide(); d=(value*49)/range; VI_WaitVBL(1); for(a=0;a255) SC.musicvol=255; SetVolumes(SC.musicvol,SC.sfxvol); ShowMenuSliders(SC.musicvol,255); } break; case 3: if (SC.sfxvol<255) { SC.sfxvol+=4; if (SC.sfxvol>255) SC.sfxvol=255; SetVolumes(SC.musicvol,SC.sfxvol); ShowMenuSliders(SC.sfxvol,255); } break; case 4: // violence SC.violence=false; MenuShowOptions(); break; case 5: // animation SC.animation=false; MenuShowOptions(); break; case 6: // ambient if (SC.ambientlight<4096) { SC.ambientlight+=64; if (SC.ambientlight>4096) SC.ambientlight=4096; ShowMenuSliders(SC.ambientlight,4096); changelight=SC.ambientlight; lighting=1; } break; case 7: // screensize if (SC.screensize) { SC.screensize--; ShowMenuSliders(10-SC.screensize,10); timedelay=timecount+KBDELAY2; goright=false; } break; case 8: // camera delay if (SC.camdelay<70) { SC.camdelay++; ShowMenuSliders(SC.camdelay,70); } break; } MouseShow(); } } void MenuCommand(void) { if (keyboard[SC_ESCAPE] && timecount>timedelay) { downlevel=true; timedelay=timecount+KBDELAY2; } if (keyboard[SC_UPARROW] && timecount>timedelay) { --menucursor; if (menucursor<0) menucursor=menumax[menulevel]-1; timedelay=timecount+KBDELAY2; } else if (keyboard[SC_DOWNARROW] && timecount>timedelay) { ++menucursor; if (menucursor==menumax[menulevel]) menucursor=0; timedelay=timecount+KBDELAY2; } if (keyboard[SC_RIGHTARROW] && timecount>timedelay) goright=true; else if (keyboard[SC_LEFTARROW] && timecount>timedelay) goleft=true; if (keyboard[SC_ENTER] && timecount>timedelay) { menuexecute=true; timedelay=timecount+KBDELAY2; } } void MenuStub(void) { } void MenuShowCursor(int menucursor) { int x, y, w, h, i; if (menucursor==-1 || menucursor==menucurloc) return; MouseHide(); VI_DrawMaskedPic(20,15,CA_CacheLump(CA_GetNamedNum("menumain")+menulevel)); menucurloc=menucursor; x=cursors[menulevel][menucurloc].x; y=cursors[menulevel][menucurloc].y; w=cursors[menulevel][menucurloc].w; h=cursors[menulevel][menucurloc].h; memset(ylookup[y]+x,133,w); memset(ylookup[y+h-1]+x,133,w); for(i=y;i0) menucursor=saveposition; else menucursor=1; } else menucursor=2; menucurloc=-1; MenuShowCursor(menucursor); } GetSavedName(int menucursor) { boolean done; int cursor, i; MouseHide(); cursor=20; while (savedir[menucursor][cursor-1]==' ' && cursor>0) --cursor; if (cursor==20) cursor=19; savedir[menucursor][cursor]='_'; done=false; unlock_region((void near *)MenuCommand,(char *)MenuStub - (char near *)MenuCommand); INT_TimerHook(NULL); lastascii=0; newascii=false; while (!done) { printx=148; printy=34+menucursor*10; for(i=0;i<6;i++) memset(ylookup[printy+i]+printx,0,100); FN_Printf(savedir[menucursor]); while (!newascii) // wait for a new key MenuShowCursor(menucursor+1); switch (lastascii) { case 27: done=true; break; case 13: done=true; break; case 8: if (cursor>0) { savedir[menucursor][cursor-1]='_'; memset(&savedir[menucursor][cursor],(int)' ',20-cursor); --cursor; } break; default: if (isalnum(lastascii) || lastascii==' ' || lastascii=='.' || lastascii=='-' || lastascii=='_' || lastascii=='!' || lastascii==',' || lastascii=='?' || lastascii=='"') { savedir[menucursor][cursor]=lastascii; if (cursor<19) ++cursor; savedir[menucursor][cursor]='_'; break; } } newascii=false; } savedir[menucursor][cursor]=' '; if (lastascii==27) ShowSaveDir(); else { downlevel=true; SaveDirectory(); SaveGame(menucursor); } timedelay=timecount+KBDELAY2; lock_region((void near *)MenuCommand,(char *)MenuStub - (char near *)MenuCommand); INT_TimerHook(MenuCommand); MouseShow(); } void Execute(int level,int cursor) { switch (level) { case 0: // main menu switch (cursor) { case 0: // new game if (!netmode) ShowMenuLevel(1); break; case 1: // quit if (ShowQuit(MenuCommand)) { quitgame=true; quitmenu=true; } break; case 2: // load if (!netmode) ShowMenuLevel(2); break; case 3: // save if (!netmode && gameloaded) ShowMenuLevel(3); break; case 4: // volume menu ShowMenuLevel(4); break; case 5: // info unlock_region((void near *)MenuCommand,(char *)MenuStub - (char near *)MenuCommand); INT_TimerHook(NULL); MouseHide(); ShowHelp(); MouseShow(); lock_region((void near *)MenuCommand,(char *)MenuStub - (char near *)MenuCommand); INT_TimerHook(MenuCommand); break; case 6: // resume quitmenu=true; break; } break; case 1: // char selection switch (cursor) { case 0: // quit if (ShowQuit(MenuCommand)) { quitgame=true; quitmenu=true; } break; case 1: case 2: case 3: case 4: case 5: identity=cursor-1; ShowMenuLevel(5); break; case 6: // resume downlevel=true; break; } break; case 2: // load menu switch (cursor) { case 0: // quit if (ShowQuit(MenuCommand)) { quitgame=true; quitmenu=true; } break; case 11: // back downlevel=true; break; default: MouseHide(); LoadGame(menucursor-1); quitmenu=true; MouseShow(); saveposition=cursor; break; } break; case 3: // save menu switch (cursor) { case 0: // quit if (ShowQuit(MenuCommand)) { quitgame=true; quitmenu=true; } break; case 11: // back downlevel=true; break; default: GetSavedName(menucursor-1); saveposition=cursor; break; } break; case 4: // option menu switch (cursor) { case 0: ShowMenuLevel(1); break; case 1: if (ShowQuit(MenuCommand)) { quitgame=true; quitmenu=true; } break; case 2: // music vol case 3: // sound vol case 4: // violence case 5: // animations case 6: // ambient light case 7: // screen size case 8: // camera delay break; case 9: downlevel=true; break; } break; case 5: // difficulty selection switch (cursor) { case 0: // quit if (ShowQuit(MenuCommand)) { quitgame=true; quitmenu=true; } break; case 1: case 2: case 3: case 4: case 5: case 6: timecount=0; frames=0; MouseHide(); #ifdef GAME1 newplayer(0,identity,6-cursor); #elif defined(GAME2) newplayer(8,identity,6-cursor); #elif defined(GAME3) newplayer(16,identity,6-cursor); #else newplayer(0,identity,6-cursor); #endif MouseShow(); quitmenu=true; break; case 7: ShowMenuLevel(1); break; } break; } } void MenuAnimate(void) { int lump; pic_t *frames[8]; int i, frame; longint waittime; if (netmode) return; memcpy(viewbuffer,screen,64000); lump=CA_GetNamedNum("menuanim"); for(i=0;i<8;i++) frames[i]=CA_CacheLump(lump+i); frame=-1; waittime=timecount; while (1) { if (timecount>=waittime) { ++frame; if (frame==8) break; VI_DrawMaskedPic2(20,15,frames[frame]); waittime+=7; } } for(i=0;i<8;i++) CA_FreeLump(lump+i); } void CheckMouse(void) { int i; short x, y; cursor_t *c; if (!MouseGetClick(&x,&y)) return; for(i=0;ix+c->w && x>c->x && yy+c->h && y>c->y) { menucursor=i; MenuShowCursor(menucursor); menuexecute=true; return; } } if (menulevel==4) { switch (menucursor) { case 2: if (y>=49 && y<=64 && x>=42 && x<=90) { SC.musicvol=((x-40)*256)/49; if (SC.musicvol>255) SC.musicvol=255; SetVolumes(SC.musicvol,SC.sfxvol); ShowMenuSliders(SC.musicvol,255); } break; case 3: if (y>=49 && y<=64 && x>=42 && x<=90) { SC.sfxvol=((x-40)*256)/49; if (SC.sfxvol>255) SC.sfxvol=255; SetVolumes(SC.musicvol,SC.sfxvol); ShowMenuSliders(SC.sfxvol,255); } break; case 4: case 5: if (y>=62 && y<=70) { if (x>=50 && x<=61) goleft=true; else if (x>=72 && x<=83) goright=true; } break; case 6: if (y>=49 && y<=64 && x>=42 && x<=90) { SC.ambientlight=((x-40)*4096)/49; if (SC.ambientlight>4096) SC.ambientlight=4096; ShowMenuSliders(SC.ambientlight,4096); changelight=SC.ambientlight; lighting=1; } break; case 7: if (y>=49 && y<=64 && x>=42 && x<=90) { SC.screensize=9-(((x-40)*10)/49); if (SC.screensize>9) SC.screensize=9; else if (SC.screensize<0) SC.screensize=0; ShowMenuSliders(10-SC.screensize,10); } break; case 8: if (y>=49 && y<=64 && x>=42 && x<=90) { SC.camdelay=((x-40)*70)/49; if (SC.camdelay>70) SC.camdelay=70; ShowMenuSliders(SC.camdelay,70); } break; } } } void ShowMenu(int n) { byte *scr; timedelay=timecount+KBDELAY2; lock_region((void near *)MenuCommand,(char *)MenuStub - (char near *)MenuCommand); INT_TimerHook(MenuCommand); scr=(byte *)malloc(64000); if (scr==NULL) MS_Error("ShowMenu: Out of Memory!"); memcpy(scr,screen,64000); if (SC.animation) MenuAnimate(); MouseShow(); ShowMenuLevel(n); quitmenu=false; do { MenuShowCursor(menucursor); CheckMouse(); if (menuexecute) { Execute(menulevel,menucursor); menuexecute=false; } if (downlevel) { if (menulevel==0) quitmenu=true; else ShowMenuLevel(0); downlevel=false; } if (goright) { MenuRight(); goright=false; } if (goleft) { MenuLeft(); goleft=false; } if (netmode) TimeUpdate(); } while (!quitmenu); MouseHide(); memcpy(screen,scr,64000); free(scr); if (gameloaded) { if (SC.vrhelmet==0) { while (currentViewSizeSC.screensize) ChangeViewSize(false); } } dSaveSetup(&SC,"SETUP.CFG"); turnrate=0; moverate=0; fallrate=0; strafrate=0; ResetMouse(); } /**************************************************************************/ void ShowHelp(void) { byte *s; s=(byte *)malloc(64000); if (s==NULL) MS_Error("Error Allocating in ShowHelp"); memcpy(s,screen,64000); VI_FillPalette(0,0,0); memset(screen,0,64000); loadscreen("INFO1"); VI_SetPalette(colors); newascii=false; for(;;) { Wait(10); if (netmode) TimeUpdate(); if (newascii) break; } VI_FillPalette(0,0,0); memset(screen,0,64000); #ifdef DEMO loadscreen("INFO2"); VI_SetPalette(colors); newascii=false; for(;;) { Wait(10); if (netmode) TimeUpdate(); if (newascii) break; } VI_FillPalette(0,0,0); memset(screen,0,64000); loadscreen("INFO3"); VI_SetPalette(colors); newascii=false; for(;;) { Wait(10); if (netmode) TimeUpdate(); if (newascii) break; } memset(screen,0,64000); VI_FillPalette(0,0,0); #endif VI_SetPalette(CA_CacheLump(CA_GetNamedNum("palette"))); memcpy(screen,s,64000); free(s); } /**************************************************************************/ boolean CheckPause() { if (netmode) { NetGetData(); if (!gamepause) return !netpaused; else return newascii; } return newascii; } void ShowPause(void) { longint animtime, droptime; int anim, y, i; int lump; pic_t *pics[4]; INT_TimerHook(NULL); memcpy(viewbuffer,screen,64000); lump=CA_GetNamedNum("pause"); for(i=0;i<4;i++) pics[i]=CA_CacheLump(lump+i); timedelay=timecount+KBDELAY2; Wait(KBDELAY2); anim=0; if (!SC.animation) y=72; else y=-56; droptime=timecount; animtime=timecount; newascii=false; while (!CheckPause()) { if (timecount>=droptime && y<72) { if (y>=0) memcpy(ylookup[y],viewbuffer+320*y,640); y+=2; droptime=timecount+1; } if (timecount>=animtime) { anim++; anim&=3; animtime+=10; } VI_DrawMaskedPic2(106,y,pics[anim]); } if (!SC.animation) y=200; droptime=timecount; animtime=timecount; while (y<199) { if (timecount>=droptime) { if (y>=0) memcpy(ylookup[y],viewbuffer+320*y,640); y+=2; droptime=timecount+1; } if (timecount>=animtime) { anim++; anim&=3; animtime+=10; } VI_DrawMaskedPic2(106,y,pics[anim]); } memcpy(screen,viewbuffer,64000); for (i=0;i<4;i++) CA_FreeLump(lump+i); } /*****************************************************************************/ void StartWait(void) { int i, lump; memcpy(viewbuffer,screen,64000); lump=CA_GetNamedNum("wait"); for(i=0;i<4;i++) waitpics[i]=CA_CacheLump(lump+i); waitanim=0; VI_DrawMaskedPic2(106,72,waitpics[0]); timedelay=timecount+10; waiting=true; } void UpdateWait(void) { if (timecount>timedelay) { ++waitanim; waitanim&=3; VI_DrawMaskedPic2(106,72,waitpics[waitanim]); timedelay=timecount+10; } } void EndWait(void) { int lump, i; lump=CA_GetNamedNum("wait"); for(i=0;i<4;i++) CA_FreeLump(lump+i); memcpy(screen,viewbuffer,64000); waiting=false; }