Files
Catacomb3D/ID_US_2.C
2026-03-12 19:22:23 +01:00

1819 lines
40 KiB
C

/* Catacomb 3-D Source Code
* Copyright (C) 1993-2014 Flat Rock Software
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
//
// ID Engine
// ID_US.c - User Manager - User interface
// v1.1d1
// By Jason Blochowiak
// Hacked up for Catacomb 3D
//
#include "ID_HEADS.H"
#pragma hdrstop
#pragma warn -pia
// Special imports
extern boolean showscorebox;
#ifdef KEEN
extern boolean oldshooting;
extern ScanCode firescan;
#else
ScanCode firescan;
#endif
// Global variables
boolean ingame,abortgame,loadedgame;
GameDiff restartgame = gd_Continue;
// Internal variables
static boolean GameIsDirty,
QuitToDos,
CtlPanelDone;
// Forward reference prototypes
static void USL_SetupCard(void);
// Control panel data
#define CtlPanelSX 74
#define CtlPanelSY 48
#define CtlPanelEX 234
#define CtlPanelEY 150
#define CtlPanelW (CtlPanelEX - CtlPanelSX)
#define CtlPanelH (CtlPanelEY - CtlPanelSY)
#define TileBase 92
// DEBUG - CGA
#define BackColor 0
#define HiliteColor (BackColor ^ 12)
#define NohiliteColor (BackColor ^ 4)
typedef enum
{
uc_None,
uc_Return,
uc_Abort,
uc_Quit,
uc_Loaded,
uc_SEasy,
uc_SNormal,
uc_SHard,
} UComm;
typedef enum
{
uii_Bad,
uii_Button,uii_RadioButton,uii_Folder
} UIType;
typedef enum
{
ui_Normal = 0,
ui_Pushed = 1,
ui_Selected = 2,
ui_Disabled = 4,
ui_Separated = 8
} UIFlags;
#define UISelectFlags (ui_Pushed | ui_Selected | ui_Disabled)
typedef enum
{
uic_SetupCard,uic_DrawCard,uic_TouchupCard,
uic_DrawIcon,uic_Draw,uic_Hit
} UserCall;
typedef struct UserItem
{
UIType type;
UIFlags flags;
ScanCode hotkey;
char *text;
UComm comm;
void far *child; // Should be (UserItemGroup *)
word x,y;
} UserItem;
typedef struct UserItemGroup
{
word x,y;
graphicnums title;
ScanCode hotkey;
UserItem far *items;
boolean (*custom)(UserCall,struct UserItem far *); // Custom routine
word cursor;
struct UserItemGroup far *parent;
} UserItemGroup;
static char *BottomS1,*BottomS2,*BottomS3;
static UComm Communication;
static ScanCode *KeyMaps[] =
{
&KbdDefs[0].button0,
&KbdDefs[0].button1,
&firescan,
&KbdDefs[0].upleft,
&KbdDefs[0].up,
&KbdDefs[0].upright,
&KbdDefs[0].right,
&KbdDefs[0].downright,
&KbdDefs[0].down,
&KbdDefs[0].downleft,
&KbdDefs[0].left
};
// Custom routine prototypes
static boolean USL_ConfigCustom(UserCall call,struct UserItem far *item),
USL_KeyCustom(UserCall call,struct UserItem far *item),
USL_KeySCustom(UserCall call,struct UserItem far *item),
USL_Joy1Custom(UserCall call,struct UserItem far *item),
USL_Joy2Custom(UserCall call,struct UserItem far *item),
USL_LoadCustom(UserCall call,struct UserItem far *item),
USL_SaveCustom(UserCall call,struct UserItem far *item),
USL_ScoreCustom(UserCall call,struct UserItem far *item),
USL_CompCustom(UserCall call,struct UserItem far *item),
#ifdef KEEN
USL_TwoCustom(UserCall call,struct UserItem far *item),
#endif
USL_PongCustom(UserCall call,struct UserItem far *item);
#define DefButton(key,text) uii_Button,ui_Normal,key,text
#define DefRButton(key,text) uii_RadioButton,ui_Normal,key,text
#define DefFolder(key,text,child) uii_Folder,ui_Normal,key,text,uc_None,child
#define CustomGroup(title,key,custom) 0,0,title,key,0,custom
UserItem far holder[] =
{
{DefButton(sc_None,"DEBUG")},
{uii_Bad}
};
UserItemGroup far holdergroup = {0,0,CP_MAINMENUPIC,sc_None,holder};
// Sound menu
UserItem far soundi[] =
{
{DefRButton(sc_N,"NO SOUND EFFECTS")},
{DefRButton(sc_P,"PC SPEAKER")},
{DefRButton(sc_A,"ADLIB/SOUNDBLASTER")},
{uii_Bad}
};
UserItemGroup far soundgroup = {8,0,CP_SOUNDMENUPIC,sc_None,soundi};
// Music menu
UserItem far musici[] =
{
{DefRButton(sc_N,"NO MUSIC")},
{DefRButton(sc_A,"ADLIB/SOUNDBLASTER")},
{uii_Bad}
};
UserItemGroup far musicgroup = {8,0,CP_MUSICMENUPIC,sc_None,musici};
// New game menu
UserItem far newgamei[] =
{
{DefButton(sc_E,"BEGIN EASY GAME"),uc_SEasy},
{DefButton(sc_N,"BEGIN NORMAL GAME"),uc_SNormal},
{DefButton(sc_H,"BEGIN HARD GAME"),uc_SHard},
{uii_Bad}
};
UserItemGroup far newgamegroup = {8,0,CP_NEWGAMEMENUPIC,sc_None,newgamei,0,1};
// Load/Save game menu
UserItem far loadsavegamei[] =
{
{uii_Button,ui_Normal,sc_None},
{uii_Button,ui_Normal,sc_None},
{uii_Button,ui_Normal,sc_None},
{uii_Button,ui_Normal,sc_None},
{uii_Button,ui_Normal,sc_None},
{uii_Button,ui_Normal,sc_None},
{uii_Bad}
};
UserItemGroup far loadgamegroup = {4,3,CP_LOADMENUPIC,sc_None,loadsavegamei,USL_LoadCustom};
UserItemGroup far savegamegroup = {4,3,CP_SAVEMENUPIC,sc_None,loadsavegamei,USL_SaveCustom};
// Options menu
UserItemGroup far scoregroup = {0,0,0,sc_None,0,USL_ScoreCustom};
UserItemGroup far compgroup = {0,0,0,sc_None,0,USL_CompCustom};
#ifdef KEEN
UserItemGroup far twogroup = {0,0,0,sc_None,0,USL_TwoCustom};
#endif
UserItem far optionsi[] =
{
{DefFolder(sc_S,"",&scoregroup)},
{DefFolder(sc_C,"",&compgroup)},
#ifdef KEEN
{DefFolder(sc_T,"",&twogroup)},
#endif
{uii_Bad}
};
UserItemGroup far optionsgroup = {8,0,CP_OPTIONSMENUPIC,sc_None,optionsi};
// Keyboard menu
UserItem far keyi[] =
{
{DefButton(sc_None,"UP & LEFT")},
{DefButton(sc_None,"UP")},
{DefButton(sc_None,"UP & RIGHT")},
{DefButton(sc_None,"RIGHT")},
{DefButton(sc_None,"DOWN & RIGHT")},
{DefButton(sc_None,"DOWN")},
{DefButton(sc_None,"DOWN & LEFT")},
{DefButton(sc_None,"LEFT")},
{uii_Bad}
};
UserItemGroup far keygroup = {0,0,CP_KEYMOVEMENTPIC,sc_None,keyi,USL_KeyCustom};
UserItem far keybi[] =
{
#ifdef KEEN
{DefButton(sc_J,"JUMP")},
{DefButton(sc_P,"POGO")},
{DefButton(sc_F,"FIRE")},
#endif
#ifdef CAT3D
{DefButton(sc_J,"FIRE")},
{DefButton(sc_P,"STRAFE")},
#endif
#ifdef CPD
{DefButton(sc_J,"SHOOT")},
{DefButton(sc_P,"BOMB")},
#endif
{uii_Bad}
};
UserItemGroup far keybgroup = {0,0,CP_KEYBUTTONPIC,sc_None,keybi,USL_KeyCustom};
UserItem far keysi[] =
{
{DefFolder(sc_M,"MOVEMENT",&keygroup)},
{DefFolder(sc_B,"BUTTONS",&keybgroup)},
{uii_Bad}
};
UserItemGroup far keysgroup = {8,0,CP_KEYBOARDMENUPIC,sc_None,keysi,USL_KeySCustom};
// Joystick #1 & #2
UserItemGroup far joy1group = {CustomGroup(CP_JOYSTICKMENUPIC,sc_None,USL_Joy1Custom)};
UserItemGroup far joy2group = {CustomGroup(CP_JOYSTICKMENUPIC,sc_None,USL_Joy2Custom)};
// Config menu
UserItem far configi[] =
{
{DefFolder(sc_S,"SOUND",&soundgroup)},
{DefFolder(sc_M,"MUSIC",&musicgroup)},
{uii_Folder,ui_Separated,sc_K,"USE KEYBOARD",uc_None,&keysgroup},
{DefFolder(sc_None,"USE JOYSTICK #1",&joy1group)},
{DefFolder(sc_None,"USE JOYSTICK #2",&joy2group)},
{uii_Bad}
};
UserItemGroup far configgroup = {8,0,CP_CONFIGMENUPIC,sc_None,configi,USL_ConfigCustom};
// Main menu
UserItemGroup far ponggroup = {0,0,0,sc_None,0,USL_PongCustom};
UserItem far rooti[] =
{
{DefFolder(sc_N,"NEW GAME",&newgamegroup)},
{DefFolder(sc_L,"LOAD GAME",&loadgamegroup)},
{DefFolder(sc_S,"SAVE GAME",&savegamegroup)},
{DefFolder(sc_C,"CONFIGURE",&configgroup)},
{DefButton(sc_R,nil),uc_Return}, // Return to Game/Demo
{DefButton(sc_E,"END GAME"),uc_Abort},
{DefFolder(sc_B,"SKULL 'N' BONES",&ponggroup)},
{DefButton(sc_Q,"QUIT"),uc_Quit},
{uii_Bad}
};
UserItemGroup far rootgroup = {32,4,CP_MAINMENUPIC,sc_None,rooti};
#undef DefButton
#undef DefFolder
#define MaxCards 7
word cstackptr;
UserItemGroup far *cardstack[MaxCards],
far *topcard;
// Card stack code
static void
USL_SetupStack(void)
{
cstackptr = 0;
cardstack[0] = topcard = &rootgroup;
}
static void
USL_PopCard(void)
{
if (!cstackptr)
return;
topcard = cardstack[--cstackptr];
}
static void
USL_PushCard(UserItemGroup far *card)
{
if (cstackptr == MaxCards - 1)
return;
topcard = cardstack[++cstackptr] = card;
}
static void
USL_DrawItemIcon(UserItem far *item)
{
word flags,tile;
if (topcard->custom && topcard->custom(uic_DrawIcon,item))
return;
flags = item->flags;
if (flags & ui_Disabled)
tile = TileBase + ((flags & ui_Selected)? 5 : 4);
else if ((item->type == uii_RadioButton) && (!(flags & ui_Pushed)))
tile = TileBase + ((flags & ui_Selected)? 3 : 2);
else
tile = TileBase + ((flags & ui_Selected)? 1 : 0);
VWB_DrawTile8(item->x,item->y,tile);
}
static void
USL_DrawItem(UserItem far *item)
{
if (topcard->custom && topcard->custom(uic_Draw,item))
return;
VWB_Bar(CtlPanelSX + 1,item->y,
CtlPanelEX - CtlPanelSX - 1,8,BackColor); // Clear out background
USL_DrawItemIcon(item);
if ((item->flags & ui_Selected) && !(item->flags & ui_Disabled))
fontcolor = HiliteColor;
else
fontcolor = NohiliteColor;
px = item->x + 8;
py = item->y + 1;
USL_DrawString(item->text);
fontcolor = F_BLACK;
}
#define MyLine(y) VWB_Hlin(CtlPanelSX + 3,CtlPanelEX - 3,y,12);
static void
USL_DrawBottom(void)
{
word w,h;
fontcolor = NohiliteColor;
px = CtlPanelSX + 4;
py = CtlPanelEY - 15;
USL_DrawString(BottomS1);
USL_MeasureString(BottomS2,&w,&h);
px = CtlPanelEX - 4 - w;
USL_DrawString(BottomS2);
USL_MeasureString(BottomS3,&w,&h);
px = CtlPanelSX + ((CtlPanelEX - CtlPanelSX - w) / 2);
py += h + 1;
USL_DrawString(BottomS3);
fontcolor = F_WHITE;
MyLine(CtlPanelEY - 17);
}
static void
USL_DrawCtlPanelContents(void)
{
int x,y;
UserItem far *item;
if (topcard->custom && topcard->custom(uic_DrawCard,nil))
return;
if (topcard->title)
{
// Draw the title
MyLine(CtlPanelSY + 7);
VWB_DrawPic(CtlPanelSX + 6,CtlPanelSY,topcard->title);
}
USL_DrawBottom();
if (!topcard->items)
return;
x = topcard->x + CtlPanelSX;
if (x % 8)
x += 8 - (x % 8);
y = topcard->y + CtlPanelSY + 12;
for (item = topcard->items;item->type != uii_Bad;item++)
{
if (item->flags & ui_Separated)
y += 8;
item->x = x;
item->y = y;
USL_DrawItem(item);
y += 8;
}
if (topcard->custom)
topcard->custom(uic_TouchupCard,nil);
}
static void
USL_DrawCtlPanel(void)
{
if (topcard->items || topcard->title)
{
// Draw the backdrop
VWB_DrawPic(0,0,CP_MENUSCREENPIC);
// Draw the contents
USL_DrawCtlPanelContents();
}
// Refresh the screen
VW_UpdateScreen();
}
static void
USL_DialogSetup(word w,word h,word *x,word *y)
{
VWB_DrawMPic(CtlPanelSX,CtlPanelSY,CP_MENUMASKPICM);
*x = CtlPanelSX + ((CtlPanelW - w) / 2);
*y = CtlPanelSY + ((CtlPanelH - h) / 2);
VWB_Bar(*x,*y,w + 1,h + 1,BackColor);
VWB_Hlin(*x - 1,*x + w + 1,*y - 1,NohiliteColor);
VWB_Hlin(*x - 1,*x + w + 1,*y + h + 1,NohiliteColor);
VWB_Vlin(*y - 1,*y + h + 1,*x - 1,NohiliteColor);
VWB_Vlin(*y - 1,*y + h + 1,*x + w + 1,NohiliteColor);
}
static void
USL_ShowLoadSave(char *s,char *name)
{
word x,y,
w,h,
tw,sw;
char msg[MaxGameName + 4];
strcpy(msg,"'");
strcat(msg,name);
strcat(msg,"'");
USL_MeasureString(s,&sw,&h);
USL_MeasureString(msg,&w,&h);
tw = ((sw > w)? sw : w) + 6;
USL_DialogSetup(tw,(h * 2) + 2,&x,&y);
py = y + 2;
px = x + ((tw - sw) / 2);
USL_DrawString(s);
py += h;
px = x + ((tw - w) / 2);
USL_DrawString(msg);
VW_UpdateScreen();
IN_UserInput(100, true);
}
static boolean
USL_CtlDialog(char *s1,char *s2,char *s3)
{
word w,h,sh,
w1,w2,w3,
x,y;
ScanCode c;
CursorInfo cursorinfo;
USL_MeasureString(s1,&w1,&h);
USL_MeasureString(s2,&w2,&h);
if (s3)
USL_MeasureString(s3,&w3,&h);
else
w3 = 0;
w = (w1 > w2)? ((w1 > w3)? w1 : w3) : ((w2 > w3)? w2 : w3);
w += 7;
sh = h;
h *= s3? 5 : 4;
USL_DialogSetup(w,h,&x,&y);
fontcolor = HiliteColor;
px = x + ((w - w1) / 2);
py = y + sh + 1;
USL_DrawString(s1);
py += (sh * 2) - 1;
VWB_Hlin(x + 3,x + w - 3,py,NohiliteColor);
py += 2;
fontcolor = NohiliteColor;
px = x + ((w - w2) / 2);
USL_DrawString(s2);
py += sh;
if (s3)
{
px = x + ((w - w3) / 2);
USL_DrawString(s3);
}
VW_UpdateScreen();
IN_ClearKeysDown();
do
{
IN_ReadCursor(&cursorinfo);
if (cursorinfo.button0)
c = sc_Y;
else if (cursorinfo.button1)
c = sc_Escape;
else
c = LastScan;
} while (c == sc_None);
do
{
IN_ReadCursor(&cursorinfo);
} while (cursorinfo.button0 || cursorinfo.button1);
IN_ClearKeysDown();
USL_DrawCtlPanel();
return(c == sc_Y);
}
static boolean
USL_ConfirmComm(UComm comm)
{
boolean confirm,dialog;
char *s1,*s2,*s3;
if (!comm)
Quit("USL_ConfirmComm() - empty comm");
confirm = true;
dialog = false;
s3 = "ESC TO BACK OUT";
switch (comm)
{
case uc_Abort:
s1 = "REALLY END CURRENT GAME?";
s2 = "PRESS Y TO END IT";
if (ingame && GameIsDirty)
dialog = true;
break;
case uc_Quit:
s1 = "REALLY QUIT?";
s2 = "PRESS Y TO QUIT";
dialog = true;
break;
case uc_Loaded:
s1 = "YOU'RE IN A GAME";
s2 = "PRESS Y TO LOAD GAME";
if (ingame && GameIsDirty)
dialog = true;
break;
case uc_SEasy:
case uc_SNormal:
case uc_SHard:
s1 = "YOU'RE IN A GAME";
s2 = "PRESS Y FOR NEW GAME";
if (ingame && GameIsDirty)
dialog = true;
break;
}
confirm = dialog? USL_CtlDialog(s1,s2,s3) : true;
if (confirm)
{
Communication = comm;
CtlPanelDone = true;
}
return(confirm);
}
///////////////////////////////////////////////////////////////////////////
//
// USL_HandleError() - Handles telling the user that there's been an error
//
///////////////////////////////////////////////////////////////////////////
static void
USL_HandleError(int num)
{
char buf[64];
strcpy(buf,"Error: ");
if (num < 0)
strcat(buf,"Unknown");
else if (num == ENOMEM)
strcat(buf,"Disk is Full");
else if (num == EINVFMT)
strcat(buf,"File is Incomplete");
else
strcat(buf,sys_errlist[num]);
VW_HideCursor();
USL_CtlDialog(buf,"PRESS ANY KEY",nil);
VW_UpdateScreen();
IN_ClearKeysDown();
IN_Ack();
VW_ShowCursor();
VW_UpdateScreen();
}
// Custom routines
#if 0
static boolean
USL_GenericCustom(UserCall call,UserItem far *item)
{
boolean result;
result = false;
switch (call)
{
}
return(result);
}
#endif
static void
USL_SetOptionsText(void)
{
optionsi[0].text = showscorebox? "SCORE BOX (ON)" : "SCORE BOX (OFF)";
optionsi[1].text = compatability? "SVGA COMPATIBILITY (ON)" : "SVGA COMPATIBILITY (OFF)";
#ifdef KEEN
optionsi[2].text = oldshooting? "TWO-BUTTON FIRING (ON)" : "TWO-BUTTON FIRING (OFF)";
keybi[2].flags &= ~ui_Disabled;
if (oldshooting)
keybi[2].flags |= ui_Disabled;
#endif
}
#pragma argsused
static boolean
USL_ScoreCustom(UserCall call,UserItem far *item)
{
if (call != uic_SetupCard)
return(false);
showscorebox ^= true;
USL_CtlDialog(showscorebox? "Score box now on" : "Score box now off",
"Press any key",nil);
USL_SetOptionsText();
return(true);
}
#pragma argsused
static boolean
USL_CompCustom(UserCall call,UserItem far *item)
{
if (call != uic_SetupCard)
return(false);
compatability ^= true;
USL_CtlDialog(compatability? "SVGA compatibility now on" : "SVGA compatibility now off",
"Press any key",nil);
USL_SetOptionsText();
return(true);
}
#ifdef KEEN
#pragma argsused
static boolean
USL_TwoCustom(UserCall call,UserItem far *item)
{
if (call != uic_SetupCard)
return(false);
oldshooting ^= true;
USL_CtlDialog(oldshooting? "Two-button firing now on" : "Two-button firing now off",
"Press any key",nil);
USL_SetOptionsText();
return(true);
}
#endif
static boolean
USL_ConfigCustom(UserCall call,UserItem far *item)
{
static char *CtlNames[] = {"KEYBOARD","KEYBOARD","JOYSTICK #1","JOYSTICK #2","MOUSE"};
char *s;
word w,h,
tw;
if (call == uic_TouchupCard)
{
s = "CONTROL: ";
USL_MeasureString(s,&w,&h);
tw = w;
USL_MeasureString(CtlNames[Controls[0]],&w,&h);
tw += w;
py = CtlPanelEY - 18 - h;
px = CtlPanelSX + ((CtlPanelW - tw) / 2);
fontcolor = NohiliteColor;
USL_DrawString(s);
USL_DrawString(CtlNames[Controls[0]]);
}
item++; // Shut the compiler up
return(false);
}
static void
USL_CKSetKey(UserItem far *item,word i)
{
boolean on;
word j;
ScanCode scan;
longword time;
CursorInfo cursorinfo;
on = false;
time = 0;
LastScan = sc_None;
fontcolor = HiliteColor;
do
{
if (TimeCount >= time)
{
on ^= true;
VWB_Bar(item->x + 90,item->y,40,8,fontcolor ^ BackColor);
VWB_Bar(item->x + 90 + 1,item->y + 1,40 - 2,8 - 2,BackColor);
if (on)
VWB_DrawTile8(item->x + 90 + 16,item->y,TileBase + 8);
VW_UpdateScreen();
time = TimeCount + (TickBase / 2);
}
IN_ReadCursor(&cursorinfo);
while (cursorinfo.button0 || cursorinfo.button1)
{
IN_ReadCursor(&cursorinfo);
LastScan = sc_Escape;
}
asm pushf
asm cli
if (LastScan == sc_LShift)
LastScan = sc_None;
asm popf
} while (!(scan = LastScan));
if (scan != sc_Escape)
{
for (j = 0,on = false;j < 11;j++)
{
if (j == i)
continue;
if (*(KeyMaps[j]) == scan)
{
on = true;
break;
}
}
if (on)
USL_CtlDialog("Key already used","Press a key",nil);
else
*(KeyMaps[i]) = scan;
}
IN_ClearKeysDown();
}
#pragma argsused
static boolean
USL_KeySCustom(UserCall call,UserItem far *item)
{
if (call == uic_SetupCard)
Controls[0] = ctrl_Keyboard;
return(false);
}
#pragma argsused
static boolean
USL_KeyCustom(UserCall call,UserItem far *item)
{
boolean result;
word i;
result = false;
i = (topcard == &keygroup)? (3 + (item - keyi)) : (item - keybi);
switch (call)
{
case uic_SetupCard:
Controls[0] = ctrl_Keyboard;
break;
case uic_Draw:
VWB_Bar(CtlPanelSX + 1,item->y,
CtlPanelEX - CtlPanelSX - 1,8,BackColor); // Clear out background
USL_DrawItemIcon(item);
fontcolor = (item->flags & ui_Selected)? HiliteColor : NohiliteColor;
px = item->x + 8;
py = item->y + 1;
USL_DrawString(item->text);
VWB_Bar(item->x + 90,item->y,40,8,fontcolor ^ BackColor);
VWB_Bar(item->x + 90 + 1,item->y + 1,40 - 2,8 - 2,BackColor);
px = item->x + 90 + 6;
py = item->y + 1;
USL_DrawString(IN_GetScanName(*KeyMaps[i]));
result = true;
break;
case uic_Hit:
USL_KeyCustom(uic_Draw,item);
USL_CKSetKey(item,i);
USL_DrawCtlPanel();
result = true;
break;
}
return(result);
}
static void
USL_CJDraw(char *s1,char *s2)
{
word w,h;
USL_MeasureString(s1,&w,&h);
px = CtlPanelSX + ((CtlPanelW - w) / 2);
py = CtlPanelEY - 34;
VWB_Bar(CtlPanelSX + 1,py,CtlPanelW - 2,h * 2,BackColor);
fontcolor = HiliteColor;
USL_DrawString(s1);
py += h;
USL_MeasureString(s2,&w,&h);
px = CtlPanelSX + ((CtlPanelW - w) / 2);
USL_DrawString(s2);
}
static boolean
USL_CJGet(word joy,word button,word x,word y,word *xaxis,word *yaxis)
{
boolean on;
longword time;
while (IN_GetJoyButtonsDB(joy))
if (LastScan == sc_Escape)
return(false);
on = false;
time = 0;
while (!(IN_GetJoyButtonsDB(joy) & (1 << button)))
{
if (TimeCount >= time)
{
on ^= true;
time = TimeCount + (TickBase / 2);
VWB_DrawTile8(x,y,TileBase + on);
VW_UpdateScreen();
}
if (LastScan == sc_Escape)
return(false);
}
IN_GetJoyAbs(joy,xaxis,yaxis);
return(true);
}
static boolean
USL_ConfigJoystick(word joy)
{
word x,y,
minx,miny,
maxx,maxy;
BottomS1 = BottomS2 = "";
BottomS3 = "Esc to back out";
USL_DrawCtlPanel();
x = CtlPanelSX + 60;
y = CtlPanelSY + 19;
VWB_DrawPic(x,y,CP_JOYSTICKPIC);
USL_CJDraw("Move Joystick to upper left","and press button #1");
VWB_DrawTile8(x + 24,y + 8,TileBase + 6);
VWB_DrawTile8(x + 8,y + 8,TileBase + 1);
VWB_DrawTile8(x + 8,y + 24,TileBase + 0);
VW_UpdateScreen();
if (!USL_CJGet(joy,0,x + 8,y + 8,&minx,&miny))
return(false);
USL_CJDraw("Move Joystick to lower right","and press button #2");
VWB_DrawTile8(x + 24,y + 8,TileBase - 25);
VWB_DrawTile8(x + 40,y + 24,TileBase + 7);
VWB_DrawTile8(x + 8,y + 8,TileBase + 0);
VWB_DrawTile8(x + 8,y + 24,TileBase + 1);
VW_UpdateScreen();
if (!USL_CJGet(joy,1,x + 8,y + 24,&maxx,&maxy))
return(false);
while (IN_GetJoyButtonsDB(joy))
;
IN_SetupJoy(joy,minx,maxx,miny,maxy);
return(true);
}
#pragma argsused
static boolean
USL_Joy1Custom(UserCall call,UserItem far *item)
{
if (call == uic_SetupCard)
{
if (USL_ConfigJoystick(0))
{
Controls[0] = ctrl_Joystick1;
USL_CtlDialog("USING JOYSTICK #1","PRESS ANY KEY",nil);
}
return(true);
}
else
return(false);
}
#pragma argsused
static boolean
USL_Joy2Custom(UserCall call,UserItem far *item)
{
if (call == uic_SetupCard)
{
if (USL_ConfigJoystick(1))
{
Controls[0] = ctrl_Joystick2;
USL_CtlDialog("USING JOYSTICK #2","PRESS ANY KEY",nil);
}
return(true);
}
else
return(false);
}
static void
USL_DrawFileIcon(UserItem far *item)
{
word color;
item->y = topcard->y + CtlPanelSY + 12;
item->y += (item - loadsavegamei) * 11;
fontcolor = (item->flags & ui_Selected)? HiliteColor : NohiliteColor;
color = fontcolor ^ BackColor; // Blech!
VWB_Hlin(item->x,item->x + (CtlPanelW - 12),item->y,color);
VWB_Hlin(item->x,item->x + (CtlPanelW - 12),item->y + 9,color);
VWB_Vlin(item->y,item->y + 9,item->x,color);
VWB_Vlin(item->y,item->y + 9,item->x + (CtlPanelW - 12),color);
}
static void
USL_DoLoadGame(UserItem far *item)
{
char *filename;
word n,
err;
int file;
SaveGame *game;
if (!USL_ConfirmComm(uc_Loaded))
return;
n = item - loadsavegamei;
game = &Games[n];
USL_ShowLoadSave("Loading",game->name);
err = 0;
filename = USL_GiveSaveName(n);
if ((file = open(filename,O_BINARY | O_RDONLY)) != -1)
{
if (read(file,game,sizeof(*game)) == sizeof(*game))
{
if (USL_LoadGame)
if (!USL_LoadGame(file))
USL_HandleError(err = errno);
}
else
USL_HandleError(err = errno);
close(file);
}
else
USL_HandleError(err = errno);
if (err)
{
abortgame = true;
Communication = uc_None;
CtlPanelDone = false;
}
else
loadedgame = true;
game->present = true;
if (loadedgame)
Paused = true;
USL_DrawCtlPanel();
}
static boolean
USL_LoadCustom(UserCall call,UserItem far *item)
{
boolean result;
word i;
result = false;
switch (call)
{
case uic_SetupCard:
for (i = 0;i < MaxSaveGames;i++)
{
if (Games[i].present)
loadsavegamei[i].flags &= ~ui_Disabled;
else
loadsavegamei[i].flags |= ui_Disabled;
}
break;
case uic_DrawIcon:
USL_DrawFileIcon(item);
result = true;
break;
case uic_Draw:
USL_DrawFileIcon(item);
VWB_Bar(item->x + 1,item->y + 2,CtlPanelW - 12 - 2,7,BackColor);
i = item - loadsavegamei;
if (Games[i].present)
px = item->x + 2;
else
px = item->x + 60;
py = item->y + 2;
USL_DrawString(Games[i].present? Games[i].name : "Empty");
result = true;
break;
case uic_Hit:
USL_DoLoadGame(item);
result = true;
break;
}
return(result);
}
static void
USL_DoSaveGame(UserItem far *item)
{
boolean ok;
char *filename;
word n,err;
int file;
SaveGame *game;
BottomS1 = "Type name";
BottomS2 = "Enter accepts";
USL_DrawCtlPanel();
n = item - loadsavegamei;
game = &Games[n];
fontcolor = HiliteColor;
VWB_Bar(item->x + 1,item->y + 2,CtlPanelW - 12 - 2,7,BackColor);
game->oldtest = &PrintX;
ok = US_LineInput(item->x + 2,item->y + 2,
game->name,game->present? game->name : nil,
true,MaxGameName,
CtlPanelW - 22);
if (!strlen(game->name))
strcpy(game->name,"Untitled");
if (ok)
{
USL_ShowLoadSave("Saving",game->name);
filename = USL_GiveSaveName(n);
err = 0;
file = open(filename,O_CREAT | O_BINARY | O_WRONLY,
S_IREAD | S_IWRITE | S_IFREG);
if (file != -1)
{
if (write(file,game,sizeof(*game)) == sizeof(*game))
{
if (USL_SaveGame)
ok = USL_SaveGame(file);
if (!ok)
USL_HandleError(err = errno);
}
else
USL_HandleError(err = ((errno == ENOENT)? ENOMEM : errno));
close(file);
}
else
USL_HandleError(err = ((errno == ENOENT)? ENOMEM : errno));
if (err)
{
remove(filename);
ok = false;
}
}
if (!game->present)
game->present = ok;
if (ok)
GameIsDirty = false;
USL_SetupCard();
}
static boolean
USL_SaveCustom(UserCall call,UserItem far *item)
{
word i;
switch (call)
{
case uic_SetupCard:
for (i = 0;i < MaxSaveGames;i++)
loadsavegamei[i].flags &= ~ui_Disabled;
return(false);
case uic_Hit:
USL_DoSaveGame(item);
return(true);
// break;
}
return(USL_LoadCustom(call,item));
}
#define PaddleMinX (CtlPanelSX + 3)
#define PaddleMaxX (CtlPanelEX - 15)
#define BallMinX (CtlPanelSX + 2)
#define BallMinY (CtlPanelSY + 12 + 2)
#define BallMaxX (CtlPanelEX - 6)
#define BallMaxY (CtlPanelEY - 13)
#define CPaddleY (BallMinY + 4)
#define KPaddleY (BallMaxY - 2)
void
USL_DrawPongScore(word k,word c)
{
fontcolor = HiliteColor;
PrintY = py = CtlPanelSY + 4;
px = CtlPanelSX + 6;
VWB_Bar(px,py,42,6,BackColor);
USL_DrawString("YOU:");
PrintX = px;
US_PrintUnsigned(k);
px = CtlPanelSX + 108;
VWB_Bar(px,py,50,6,BackColor);
USL_DrawString("COMP:");
PrintX = px;
US_PrintUnsigned(c);
}
void
USL_PlayPong(void)
{
boolean ball,killball,revdir,done,lastscore;
word cycle,
x,y,
kx,cx,
rx,
bx,by,
kscore,cscore,
speedup;
int bdx,bdy;
longword balltime,waittime;
CursorInfo cursorinfo;
kx = cx = PaddleMinX + ((PaddleMaxX - PaddleMinX) / 2);
bx = by = bdx = bdy = 0;
kscore = cscore = 0;
USL_DrawPongScore(0,0);
cycle = 0;
revdir = false;
killball = true;
done = false;
lastscore = false;
do
{
waittime = TimeCount;
IN_ReadCursor(&cursorinfo);
if (((cursorinfo.x < 0) || IN_KeyDown(sc_LeftArrow)) && (kx > PaddleMinX))
kx -= 2;
else if (((cursorinfo.x > 0) || IN_KeyDown(sc_RightArrow)) && (kx < PaddleMaxX))
kx += 2;
if (killball)
{
ball = false;
balltime = TimeCount + TickBase;
speedup = 10;
killball = false;
}
if (ball && (cycle++ % 3))
{
x = (bx >> 2);
if (!(x & 1))
x += (US_RndT() & 1);
if ((cx + 6 < x) && (cx < PaddleMaxX))
cx += 1;
else if ((cx + 6 > x) && (cx > PaddleMinX))
cx -= 1;
}
VWB_Bar(BallMinX,BallMinY - 1,
BallMaxX - BallMinX + 5,BallMaxY - BallMinY + 7,
BackColor);
VWB_DrawSprite(cx,CPaddleY,PADDLESPR);
VWB_DrawSprite(kx,KPaddleY,PADDLESPR);
if (ball)
{
if
(
(((bx + bdx) >> 2) > BallMaxX)
|| (((bx + bdx) >> 2) < BallMinX)
)
{
SD_PlaySound(BALLBOUNCESND);
bdx = -bdx;
}
bx += bdx;
if (((by + bdy) >> 2) > BallMaxY)
{
killball = true;
lastscore = false;
cscore++;
SD_PlaySound(COMPSCOREDSND);
USL_DrawPongScore(kscore,cscore);
if (cscore == 21)
{
USL_CtlDialog("You lost!","Press any key",nil);
done = true;
continue;
}
}
else if (((by + bdy) >> 2) < BallMinY)
{
killball = true;
lastscore = true;
kscore++;
SD_PlaySound(KEENSCOREDSND);
USL_DrawPongScore(kscore,cscore);
if (kscore == 21)
{
USL_CtlDialog("You won!","Press any key",nil);
done = true;
continue;
}
}
by += bdy;
x = bx >> 2;
y = by >> 2;
if (!killball)
{
if
(
(bdy < 0)
&& ((y >= CPaddleY) && (y < CPaddleY + 3))
&& ((x >= (cx - 5)) && (x < (cx + 11)))
)
{
rx = cx;
revdir = true;
SD_PlaySound(COMPPADDLESND);
}
else if
(
(bdy > 0)
&& ((y >= (KPaddleY - 3)) && (y < KPaddleY))
&& ((x >= (kx - 5)) && (x < (kx + 11)))
)
{
if (((bdy >> 2) < 3) && !(--speedup))
{
bdy++;
speedup = 10;
}
rx = kx;
revdir = true;
SD_PlaySound(KEENPADDLESND);
}
if (revdir)
{
bdy = -bdy;
bdx = ((x + 5 - rx) >> 1) - (1 << 2);
if (!bdx)
bdx--;
revdir = false;
}
}
VWB_DrawSprite(x,y,(x & 1)? BALL1PIXELTOTHERIGHTSPR : BALLSPR);
}
else if (TimeCount >= balltime)
{
ball = true;
bdx = 1 - (US_RndT() % 3);
bdy = 2;
if (lastscore)
bdy = -bdy;
bx = (BallMinX + ((BallMaxX - BallMinX) / 2)) << 2;
by = (BallMinY + ((BallMaxY - BallMinY) / 2)) << 2;
}
VW_UpdateScreen();
while (waittime == TimeCount)
; // DEBUG - do adaptiveness
} while ((LastScan != sc_Escape) && !done);
IN_ClearKeysDown();
}
#pragma argsused
static boolean
USL_PongCustom(UserCall call,struct UserItem far *item)
{
if (call != uic_SetupCard)
return(false);
VWB_DrawPic(0,0,CP_MENUSCREENPIC);
VWB_DrawPic(CtlPanelSX + 56,CtlPanelSY,CP_PADDLEWARPIC);
VWB_Hlin(CtlPanelSX + 3,CtlPanelEX - 3,CtlPanelSY + 12,HiliteColor ^ BackColor);
VWB_Hlin(CtlPanelSX + 3,CtlPanelEX - 3,CtlPanelEY - 7,HiliteColor ^ BackColor);
USL_PlayPong();
return(true);
}
// Flag management stuff
static void
USL_ClearFlags(UserItemGroup far *node)
{
UserItem far *i;
if (!node->items)
return;
for (i = node->items;i->type != uii_Bad;i++)
{
i->flags &= ~UISelectFlags;
if (i->child)
USL_ClearFlags((UserItemGroup far *)i->child);
}
}
static int
USL_FindPushedItem(UserItemGroup far *group)
{
word i;
UserItem far *item;
for (item = group->items,i = 0;item->type != uii_Bad;item++,i++)
if (item->flags & ui_Pushed)
return(i);
return(-1);
}
static void
USL_SelectItem(UserItemGroup far *group,word index,boolean draw)
{
UserItem far *item;
if (index != group->cursor)
{
item = &group->items[group->cursor];
item->flags &= ~ui_Selected;
if (draw)
USL_DrawItem(item);
}
group->cursor = index;
item = &group->items[group->cursor];
group->items[group->cursor].flags |= ui_Selected;
if (draw)
USL_DrawItem(item);
}
static void
USL_PushItem(UserItemGroup far *group,word index,boolean draw)
{
word i;
UserItem far *item;
USL_SelectItem(group,index,draw);
for (item = group->items,i = 0;item->type != uii_Bad;item++,i++)
{
if (item->type != uii_RadioButton)
continue;
if (i == index)
{
item->flags |= ui_Pushed;
if (draw)
USL_DrawItem(item);
}
else if (item->flags & ui_Pushed)
{
item->flags &= ~ui_Pushed;
if (draw)
USL_DrawItem(item);
}
}
}
static void
USL_NextItem(void)
{
if (topcard->items[topcard->cursor + 1].type == uii_Bad)
return;
USL_SelectItem(topcard,topcard->cursor + 1,true);
}
static void
USL_PrevItem(void)
{
if (!topcard->cursor)
return;
USL_SelectItem(topcard,topcard->cursor - 1,true);
}
static void
USL_SetupCard(void)
{
BottomS1 = "Arrows move";
BottomS2 = "Enter selects";
BottomS3 = cstackptr? "ESC to back out" : "ESC to quit";
USL_SelectItem(topcard,topcard->cursor,false);
USL_DrawCtlPanel(); // Contents?
}
static void
USL_DownLevel(UserItemGroup far *group)
{
if (!group)
Quit("USL_DownLevel() - nil card");
USL_PushCard(group);
if (group->custom && group->custom(uic_SetupCard,nil))
USL_PopCard();
USL_SetupCard();
}
static void
USL_UpLevel(void)
{
if (!cstackptr)
{
USL_ConfirmComm(uc_Quit);
return;
}
if (topcard->items)
topcard->items[topcard->cursor].flags &= ~ui_Selected;
USL_PopCard();
USL_SetupCard();
}
static void
USL_DoItem(void)
{
// DEBUG - finish this routine
UserItem far *item;
item = &topcard->items[topcard->cursor];
if (item->flags & ui_Disabled)
SD_PlaySound(NOWAYSND);
else
{
switch (item->type)
{
case uii_Button:
if (!(topcard->custom && topcard->custom(uic_Hit,item)))
USL_ConfirmComm(item->comm);
break;
case uii_RadioButton:
USL_PushItem(topcard,topcard->cursor,true);
break;
case uii_Folder:
USL_DownLevel(item->child);
break;
}
}
}
static void
USL_SetControlValues(void)
{
USL_PushItem(&soundgroup,SoundMode,false);
USL_PushItem(&musicgroup,MusicMode,false);
if (!AdLibPresent)
{
soundi[2].flags |= ui_Disabled; // AdLib sound effects
musici[1].flags |= ui_Disabled; // AdLib music
}
if (!JoysPresent[0])
configi[3].flags |= ui_Disabled;
if (!JoysPresent[1])
configi[4].flags |= ui_Disabled;
rooti[4].text = ingame? "RETURN TO GAME" : "RETURN TO DEMO";
if (!ingame)
{
rooti[2].flags |= ui_Disabled; // Save Game
rooti[5].flags |= ui_Disabled; // End Game
}
rootgroup.cursor = ingame? 4 : 0;
USL_SetOptionsText();
// DEBUG - write the rest of this
}
///////////////////////////////////////////////////////////////////////////
//
// USL_SetUpCtlPanel() - Sets the states of the UserItems to reflect the
// values of all the appropriate variables
//
///////////////////////////////////////////////////////////////////////////
static void
USL_SetUpCtlPanel(void)
{
int i;
// Cache in all of the stuff for the control panel
CA_UpLevel();
for (i = CONTROLS_LUMP_START;i <= CONTROLS_LUMP_END;i++)
CA_MarkGrChunk(i);
for (i = PADDLE_LUMP_START;i <= PADDLE_LUMP_END;i++)
CA_MarkGrChunk(i);
CA_MarkGrChunk(STARTFONT+1); // Little font
CA_MarkGrChunk(CP_MENUMASKPICM); // Mask for dialogs
CA_CacheMarks("Control Panel");
CA_LoadAllSounds();
// Do some other setup
fontnumber = 1;
US_SetPrintRoutines(VW_MeasurePropString,VWB_DrawPropString);
fontcolor = F_BLACK;
VW_Bar (0,0,320,200,3); // CAT3D patch
RF_FixOfs();
VW_InitDoubleBuffer();
Communication = uc_None;
USL_ClearFlags(&rootgroup);
USL_SetControlValues();
USL_SetupStack();
USL_SetupCard();
if (ingame)
GameIsDirty = true;
IN_ClearKeysDown();
}
static void
USL_HandleComm(UComm comm)
{
switch (comm)
{
case uc_Loaded:
case uc_Return:
break;
case uc_Abort:
abortgame = true;
break;
case uc_Quit:
QuitToDos = true;
break;
case uc_SEasy:
restartgame = gd_Easy;
break;
case uc_SNormal:
restartgame = gd_Normal;
break;
case uc_SHard:
restartgame = gd_Hard;
break;
default:
Quit("USL_HandleComm() - unknown");
break;
}
}
static void
USL_GetControlValues(void)
{
int i;
// DEBUG - write the rest of this
i = USL_FindPushedItem(&soundgroup);
if (i != SoundMode)
SD_SetSoundMode(i);
i = USL_FindPushedItem(&musicgroup);
if (i != MusicMode)
SD_SetMusicMode(i);
}
///////////////////////////////////////////////////////////////////////////
//
// USL_TearDownCtlPanel() - Given the state of the control panel, sets the
// modes and values as appropriate
//
///////////////////////////////////////////////////////////////////////////
static void
USL_TearDownCtlPanel(void)
{
USL_GetControlValues();
if (Communication)
USL_HandleComm(Communication);
fontnumber = 0; // Normal font
fontcolor = F_BLACK;
if (restartgame && USL_ResetGame)
USL_ResetGame();
else if (QuitToDos)
{
if (tedlevel)
TEDDeath();
else
{
US_CenterWindow(20,3);
fontcolor = F_SECONDCOLOR;
US_PrintCentered("Quitting...");
fontcolor = F_BLACK;
VW_UpdateScreen();
Quit(nil);
}
}
IN_ClearKeysDown();
SD_WaitSoundDone();
VW_Bar (0,0,320,200,3); // CAT3D patch
CA_DownLevel();
CA_LoadAllSounds();
}
///////////////////////////////////////////////////////////////////////////
//
// US_ControlPanel() - This is the main routine for the control panel
//
///////////////////////////////////////////////////////////////////////////
#define MoveMin 40
void
US_ControlPanel(void)
{
extern void HelpScreens(void);
boolean resetitem,on;
word i;
int ydelta;
longword flashtime;
UserItem far *item;
CursorInfo cursorinfo;
#if 0
// DEBUG!!!
{
USL_SetUpCtlPanel();
Communication = uc_Loaded;
CtlPanelDone = true;
loadedgame = true;
USL_TearDownCtlPanel();
return;
}
#endif
if ((LastScan < sc_F1) || (LastScan > sc_F10))
IN_ClearKeysDown();
USL_SetUpCtlPanel();
USL_DrawCtlPanel();
ydelta = 0;
for (CtlPanelDone = false,resetitem = on = true;!CtlPanelDone;)
{
item = &(topcard->items[topcard->cursor]);
if (resetitem)
{
flashtime = TimeCount + (TickBase / 2);
resetitem = false;
}
if (TimeCount >= flashtime)
{
on ^= true;
resetitem = true;
if (!on)
item->flags &= ~ui_Selected;
USL_DrawItemIcon(item);
item->flags |= ui_Selected;
}
VW_UpdateScreen();
if (LastScan)
{
switch (LastScan)
{
case sc_UpArrow:
USL_PrevItem();
resetitem = true;
break;
case sc_DownArrow:
USL_NextItem();
resetitem = true;
break;
case sc_Return:
USL_DoItem();
resetitem = true;
break;
case sc_Escape:
USL_UpLevel();
resetitem = true;
break;
#ifndef KEEN6
case sc_F1:
HelpScreens();
USL_DrawCtlPanel();
resetitem = true;
break;
#endif
}
if
(
(!resetitem)
&& (
(LastScan == KbdDefs[0].button0)
|| (LastScan == KbdDefs[0].button1)
)
)
{
USL_DoItem();
resetitem = true;
}
if (!resetitem)
{
for (item = topcard->items,i = 0;item->type != uii_Bad;item++,i++)
{
if (item->hotkey == LastScan)
{
USL_SelectItem(topcard,i,true);
resetitem = true;
break;
}
}
}
IN_ClearKeysDown();
}
else
{
IN_ReadCursor(&cursorinfo);
ydelta += cursorinfo.y;
if (cursorinfo.button0)
{
do
{
IN_ReadCursor(&cursorinfo);
} while (cursorinfo.button0);
USL_DoItem();
resetitem = true;
}
else if (cursorinfo.button1)
{
do
{
IN_ReadCursor(&cursorinfo);
} while (cursorinfo.button1);
USL_UpLevel();
resetitem = true;
}
else if (ydelta < -MoveMin)
{
ydelta += MoveMin;
USL_PrevItem();
resetitem = true;
}
else if (ydelta > MoveMin)
{
ydelta -= MoveMin;
USL_NextItem();
resetitem = true;
}
}
}
USL_TearDownCtlPanel();
}