Enable the Save Game menu (exits game after save)

This commit is contained in:
Lephenixnoir 2021-09-18 19:03:21 +02:00
parent 7b4e50b1c5
commit db04c99446
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
8 changed files with 572 additions and 63 deletions

1
README
View File

@ -31,6 +31,7 @@ Technical support TODO:
-> Built-in overclocking?
-> SDL2 debug version support?
-> Darken background in menu (some code does that somewhere?)
-> Rate-limit
CGDoom used to be compiled with the mini-SDK. However, it's become quite
difficult to get a copy of that. Instead, this port is built with a modified

View File

@ -270,6 +270,7 @@ void D_DoomLoop (void)
M_Ticker (); //Menu ticker
G_Ticker (); //Game ticker
if (fuck) break; //Quick exit after save game
gametic++;

View File

@ -460,7 +460,10 @@ void G_Ticker (void)
break;
case ga_savegame:
G_DoSaveGame ();
break;
/* After saving the game, the storage memory is shuffled, we need to
leave and we need to do it quickly */
I_Quit();
return;
case ga_playdemo:
G_DoPlayDemo ();
break;
@ -933,14 +936,60 @@ void G_DoLoadGame (void)
//
void G_SaveGame( int slot, char* description )
{
(void)slot;
(void)description;
savegameslot = slot;
CGDstrcpy (savedescription, description);
sendsave = true;
}
void G_DoSaveGame (void)
{
}
char name[50];
char name2[VERSIONSIZE];
char* description;
int length;
int i;
sprintf(name, SAVEGAMENAME "%d.dsg", savegameslot);
description = savedescription;
save_p = savebuffer = screens[1]+0x4000;
memcpy (save_p, description, SAVESTRINGSIZE);
save_p += SAVESTRINGSIZE;
memset (name2,0,sizeof(name2));
sprintf (name2,"version %i",VERSION);
memcpy (save_p, name2, VERSIONSIZE);
save_p += VERSIONSIZE;
*save_p++ = gameskill;
*save_p++ = gameepisode;
*save_p++ = gamemap;
for (i=0 ; i<MAXPLAYERS ; i++)
*save_p++ = playeringame[i];
*save_p++ = leveltime>>16;
*save_p++ = leveltime>>8;
*save_p++ = leveltime;
P_ArchivePlayers ();
P_ArchiveWorld ();
P_ArchiveThinkers ();
P_ArchiveSpecials ();
*save_p++ = 0x1d; // consistancy marker
length = save_p - savebuffer;
if (length > SAVEGAMESIZE)
I_Error ("Savegame buffer overrun");
M_WriteFile (name, savebuffer, length);
gameaction = ga_nothing;
savedescription[0] = 0;
static char msg[32];
sprintf(msg, GGSAVED " (%d kB)", length >> 10);
players[consoleplayer].message = msg;
}
//
// G_InitNew

View File

@ -276,25 +276,31 @@ void I_StartTic (void)
// Special keys
//---
/* This variable is set in m_menu.c while typing save file names */
extern int saveStringEnter;
UpdateKeyboardState();
/* Capture events for special keys */
if (KeyWasJustPressed(SKEY_CHEAT))
CGCheat();
if (KeyWasJustPressed(SKEY_DECVP))
R_SetViewSizeChange(-1);
if (KeyWasJustPressed(SKEY_INCVP))
R_SetViewSizeChange(1);
if (KeyWasJustPressed(SKEY_NOCLIP))
CGSwitchClip();
if (KeyWasJustPressed(SKEY_GAMMA))
CGCycleGamma();
if (KeyWasJustPressed(SKEY_FREEMEM))
CGFreeMem();
if (KeyWasJustPressed(SKEY_FPSCOUNTER))
fpscounteractive = !fpscounteractive;
if (KeyWasJustPressed(SKEY_FRAMESKIP))
CGRefreshSwitch();
if(!saveStringEnter)
{
/* Capture events for special keys */
if(KeyWasJustPressed(SKEY_CHEAT))
CGCheat();
if(KeyWasJustPressed(SKEY_DECVP))
R_SetViewSizeChange(-1);
if(KeyWasJustPressed(SKEY_INCVP))
R_SetViewSizeChange(1);
if(KeyWasJustPressed(SKEY_NOCLIP))
CGSwitchClip();
if(KeyWasJustPressed(SKEY_GAMMA))
CGCycleGamma();
if(KeyWasJustPressed(SKEY_FREEMEM))
CGFreeMem();
if(KeyWasJustPressed(SKEY_FPSCOUNTER))
fpscounteractive = !fpscounteractive;
if(KeyWasJustPressed(SKEY_FRAMESKIP))
CGRefreshSwitch();
}
//---
// Profiler
@ -303,7 +309,7 @@ void I_StartTic (void)
/* Number of ticks left before reporting results */
static int profiler_ticks = -1;
if (KeyWasJustPressed(SKEY_PROFILER)) {
if (!saveStringEnter && KeyWasJustPressed(SKEY_PROFILER)) {
prof_t *counters = (prof_t *)&CGD_Perf;
for(int i = 0; i < sizeof CGD_Perf / sizeof (prof_t); i++) {
counters[i] = prof_make();
@ -322,13 +328,25 @@ void I_StartTic (void)
// Normal keys
//---
static int keys[] = {
/* Sets of keys depending on input mode. Each set must only consist of keys
that don't overlap */
static const int base_keys[] = {
KEY_LEFTARROW, KEY_RIGHTARROW, KEY_UPARROW, KEY_DOWNARROW,
KEY_RCTRL, KEY_TAB, KEY_PAUSE, KEY_SLEFTARROW, KEY_SRIGHTARROW,
KEY_ESCAPE, KEY_ENTER,
' ', '1', '2', '3', '4', '5', '6', '7',
0
};
static const int input_keys[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
KEY_BACKSPACE, KEY_ESCAPE, KEY_ENTER,
0
};
const int *keys = base_keys;
if(saveStringEnter)
keys = input_keys;
/* Emit events for all changes */
for(int i = 0; keys[i]; i++)

View File

@ -111,7 +111,7 @@ int saveStringEnter;
int saveSlot; // which slot to save in
int saveCharIndex; // which char we're editing
// old save description before edit
//char saveOldString[SAVESTRINGSIZE];
char saveOldString[SAVESTRINGSIZE];
boolean inhelpscreens;
boolean menuactive;
@ -120,7 +120,7 @@ boolean menuactive;
#define LINEHEIGHT 16
extern boolean sendpause;
//char savegamestrings[10][SAVESTRINGSIZE];
char savegamestrings[10][SAVESTRINGSIZE];
char endstring[160];
@ -205,8 +205,8 @@ void M_DrawNewGame(void);
void M_DrawEpisode(void);
void M_DrawOptions(void);
//void M_DrawSound(void);
//void M_DrawLoad(void);
//void M_DrawSave(void);
void M_DrawLoad(void);
void M_DrawSave(void);
void M_DrawSaveLoadBorder(int x,int y);
void M_SetupNextMenu(menu_t *menudef);
@ -410,7 +410,7 @@ enum
load6,
load_end
} load_e;
/*
menuitem_t LoadMenu[]=
{
{1,"", M_LoadSelect,'1'},
@ -453,38 +453,40 @@ menu_t SaveDef =
80,54,
0
};
*/
//
// M_ReadSaveStrings
// read the strings from the savegame files
//
/*
void M_ReadSaveStrings(void)
{
FILE* handle;
int count;
int i;
char name[256];
int fd;
int i, j;
char name[64];
uint16_t fc_path[64];
for (i = 0;i < load_end;i++)
{
sprintf(name,SAVEGAMENAME"%d.dsg",i);
handle = fopen (name, "r");
if (handle == NULL)
{
strcpy(&savegamestrings[i][0],EMPTYSTRING);
LoadMenu[i].status = 0;
continue;
}
//count = read (handle, &savegamestrings[i], SAVESTRINGSIZE);
//fread ( dest, size elements, count elements, FILE handle );
count= fread (&savegamestrings[i], SAVESTRINGSIZE, 1, handle);
fclose (handle);
LoadMenu[i].status = 1;
sprintf(name, SAVEGAMENAME "%d.dsg", i);
memcpy(fc_path, u"\\\\fls0\\", 14);
for (j = 0; name[j]; j++)
fc_path[j+7] = name[j];
fc_path[j+7] = 0x0000;
fd = Bfile_OpenFile_OS(fc_path, READ, 0);
if(fd < 0) {
CGDstrcpy(savegamestrings[i], EMPTYSTRING);
LoadMenu[i].status = 0;
}
else {
Bfile_ReadFile_OS(fd, savegamestrings[i], SAVESTRINGSIZE, -1);
LoadMenu[i].status = 1;
Bfile_CloseFile_OS(fd);
}
}
I_ReinitAfterError();
}
@ -503,19 +505,7 @@ void M_DrawLoad(void)
}
}
*/
void M_LoadGame(int choice)
{
(void)choice;
M_StartMessage(NOTIMP, NULL, true);
}
void M_SaveGame(int choice)
{
(void)choice;
M_StartMessage(NOTIMP, NULL, true);
}
//
// Draw border for the savegame description
@ -536,6 +526,106 @@ void M_DrawSaveLoadBorder(int x,int y)
}
//
// User wants to load this game
//
void M_LoadSelect(int choice)
{
(void)choice;
/* char name[256];
if (M_CheckParm("-cdrom"))
sprintf(name,"c:\\doomdata\\"SAVEGAMENAME"%d.dsg",choice);
else
sprintf(name,SAVEGAMENAME"%d.dsg",choice);
G_LoadGame (name);
M_ClearMenus (); */
}
//
// Selected from DOOM menu
//
void M_LoadGame(int choice)
{
if (netgame)
{
M_StartMessage(LOADNET,NULL,false);
return;
}
M_SetupNextMenu(&LoadDef);
M_ReadSaveStrings();
}
//
// M_SaveGame & Cie.
//
void M_DrawSave(void)
{
int i;
V_DrawPatchDirect (72,28,0,W_CacheLumpNamePatch("M_SAVEG",PU_CACHE));
for (i = 0;i < load_end; i++)
{
M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
}
if (saveStringEnter)
{
i = M_StringWidth(savegamestrings[saveSlot]);
M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*saveSlot,"_");
}
}
//
// M_Responder calls this when user is finished
//
void M_DoSave(int slot)
{
G_SaveGame (slot,savegamestrings[slot]);
M_ClearMenus ();
// PICK QUICKSAVE SLOT YET?
if (quickSaveSlot == -2)
quickSaveSlot = slot;
}
//
// User wants to save. Start string input for M_Responder
//
void M_SaveSelect(int choice)
{
// we are going to be intercepting all chars
saveStringEnter = 1;
saveSlot = choice;
CGDstrcpy(saveOldString,savegamestrings[choice]);
if (!strcmp(savegamestrings[choice],EMPTYSTRING))
savegamestrings[choice][0] = 0;
saveCharIndex = strlen(savegamestrings[choice]);
}
//
// Selected from DOOM menu
//
void M_SaveGame(int choice)
{
(void)choice;
if (!usergame)
{
M_StartMessage(SAVEDEAD,NULL,false);
return;
}
if (gamestate != GS_LEVEL)
return;
M_SetupNextMenu(&SaveDef);
M_ReadSaveStrings();
}
//
// Read This Menus
@ -995,6 +1085,48 @@ boolean M_Responder (event_t* ev)
if (ch == -1)
return false;
// Save Game string input
if (saveStringEnter)
{
switch(ch)
{
case KEY_BACKSPACE:
if (saveCharIndex > 0)
{
saveCharIndex--;
savegamestrings[saveSlot][saveCharIndex] = 0;
}
break;
case KEY_ESCAPE:
saveStringEnter = 0;
CGDstrcpy(&savegamestrings[saveSlot][0],saveOldString);
break;
case KEY_ENTER:
saveStringEnter = 0;
if (savegamestrings[saveSlot][0])
M_DoSave(saveSlot);
break;
default:
ch = (ch >= 'a' && ch <= 'z') ? (ch & ~0x20) : ch;
if (ch != 32)
if (ch-HU_FONTSTART < 0 || ch-HU_FONTSTART >= HU_FONTSIZE)
break;
if (ch >= 32 && ch <= 127 &&
saveCharIndex < SAVESTRINGSIZE-1 &&
M_StringWidth(savegamestrings[saveSlot]) <
(SAVESTRINGSIZE-2)*8)
{
savegamestrings[saveSlot][saveCharIndex++] = ch;
savegamestrings[saveSlot][saveCharIndex] = 0;
}
break;
}
return true;
}
// Take care of any messages that need input
if (messageToPrint)
{

View File

@ -90,6 +90,37 @@ int M_DrawText ( int x, int y, boolean direct, char* string )
//
// M_WriteFile
//
boolean M_WriteFile(char const *name, void *source, int length)
{
uint16_t fc_path[100] = u"\\\\fls0\\";
size_t size = length;
int j = 7;
int rc, fd;
for (int i = 0; name[i]; i++)
fc_path[j++] = name[i];
fc_path[j++] = 0x0000;
Bfile_DeleteEntry(fc_path);
rc = Bfile_CreateEntry_OS(fc_path, CREATEMODE_FILE, &size);
if (rc < 0) {
/* Displaying the error message destroys the save data, so quit */
I_Error("Bfile_CreateEntry_OS(%s, %d bytes): %d", name, length, rc);
return false;
}
fd = Bfile_OpenFile_OS(fc_path, WRITE, 0);
if (fd < 0) {
I_Error("Bfile_OpenFile_OS(%s): %d", name, fd);
return false;
}
Bfile_WriteFile_OS(fd, source, length);
Bfile_CloseFile_OS(fd);
return true;
}
//
// DEFAULTS
//
@ -118,4 +149,4 @@ extern int screenblocks;
extern int showMessages;
int numdefaults;
char* defaultfile;
char* defaultfile;

View File

@ -71,6 +71,253 @@ void P_ArchivePlayers (void)
}
//
// P_UnArchivePlayers
//
void P_UnArchivePlayers (void)
{
int i;
int j;
for (i=0 ; i<MAXPLAYERS ; i++)
{
if (!playeringame[i])
continue;
PADSAVEP();
memcpy (&players[i],save_p, sizeof(player_t));
save_p += sizeof(player_t);
// will be set when unarc thinker
players[i].mo = NULL;
players[i].message = NULL;
players[i].attacker = NULL;
for (j=0 ; j<NUMPSPRITES ; j++)
{
if (players[i]. psprites[j].state)
{
players[i]. psprites[j].state
= (state_t *)&states[ (int)players[i].psprites[j].state ];
}
}
}
}
//
// P_ArchiveWorld
//
void P_ArchiveWorld (void)
{
int i;
int j;
sector_t* sec;
line_t* li;
side_t* si;
short* put;
put = (short *)save_p;
// do sectors
for (i=0, sec = sectors ; i<numsectors ; i++,sec++)
{
*put++ = sec->floorheight >> FRACBITS;
*put++ = sec->ceilingheight >> FRACBITS;
*put++ = sec->floorpic;
*put++ = sec->ceilingpic;
*put++ = sec->lightlevel;
*put++ = sec->special; // needed?
*put++ = sec->tag; // needed?
}
// do lines
for (i=0, li = lines ; i<numlines ; i++,li++)
{
*put++ = li->flags;
*put++ = li->special;
*put++ = li->tag;
for (j=0 ; j<2 ; j++)
{
if (li->sidenum[j] == -1)
continue;
si = &sides[li->sidenum[j]];
*put++ = si->textureoffset >> FRACBITS;
*put++ = si->rowoffset >> FRACBITS;
*put++ = si->toptexture;
*put++ = si->bottomtexture;
*put++ = si->midtexture;
}
}
save_p = (byte *)put;
}
//
// P_UnArchiveWorld
//
void P_UnArchiveWorld (void)
{
int i;
int j;
sector_t* sec;
line_t* li;
side_t* si;
short* get;
get = (short *)save_p;
// do sectors
for (i=0, sec = sectors ; i<numsectors ; i++,sec++)
{
sec->floorheight = *get++ << FRACBITS;
sec->ceilingheight = *get++ << FRACBITS;
sec->floorpic = *get++;
sec->ceilingpic = *get++;
sec->lightlevel = *get++;
sec->special = *get++; // needed?
sec->tag = *get++; // needed?
sec->specialdata = 0;
sec->soundtarget = 0;
}
// do lines
for (i=0, li = lines ; i<numlines ; i++,li++)
{
li->flags = *get++;
li->special = *get++;
li->tag = *get++;
for (j=0 ; j<2 ; j++)
{
if (li->sidenum[j] == -1)
continue;
si = &sides[li->sidenum[j]];
si->textureoffset = *get++ << FRACBITS;
si->rowoffset = *get++ << FRACBITS;
si->toptexture = *get++;
si->bottomtexture = *get++;
si->midtexture = *get++;
}
}
save_p = (byte *)get;
}
//
// Thinkers
//
typedef enum
{
tc_end,
tc_mobj
} thinkerclass_t;
//
// P_ArchiveThinkers
//
void P_ArchiveThinkers (void)
{
thinker_t* th;
mobj_t* mobj;
// save off the current thinkers
for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
{
if (th->function == TP_MobjThinker)
{
*save_p++ = tc_mobj;
PADSAVEP();
mobj = (mobj_t *)save_p;
memcpy (mobj, th, sizeof(*mobj));
save_p += sizeof(*mobj);
mobj->state = (state_t *)(mobj->state - states);
if (mobj->player)
mobj->player = (player_t *)((mobj->player-players) + 1);
continue;
}
// I_Error would overwrite VRAM, thus screens[0], thus the save buffer
// I_Error ("P_ArchiveThinkers: Unknown thinker function");
}
// add a terminating marker
*save_p++ = tc_end;
}
//
// P_UnArchiveThinkers
//
void P_UnArchiveThinkers (void)
{
byte tclass;
thinker_t* currentthinker;
thinker_t* next;
mobj_t* mobj;
// remove all the current thinkers
currentthinker = thinkercap.next;
while (currentthinker != &thinkercap)
{
next = currentthinker->next;
if (currentthinker->function == TP_MobjThinker)
P_RemoveMobj ((mobj_t *)currentthinker);
else
Z_Free (currentthinker);
currentthinker = next;
}
P_InitThinkers ();
// read in saved thinkers
while (1)
{
tclass = *save_p++;
switch (tclass)
{
case tc_end:
return; // end of list
case tc_mobj:
PADSAVEP();
mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL);
memcpy (mobj, save_p, sizeof(*mobj));
save_p += sizeof(*mobj);
mobj->state = (state_t *)&states[(int)mobj->state];
mobj->target = NULL;
if (mobj->player)
{
mobj->player = &players[(int)mobj->player-1];
mobj->player->mo = mobj;
}
P_SetThingPosition (mobj);
mobj->info = (mobjinfo_t *)&mobjinfo[mobj->type];
mobj->floorz = mobj->subsector->sector->floorheight;
mobj->ceilingz = mobj->subsector->sector->ceilingheight;
mobj->thinker.function = TP_MobjThinker;
P_AddThinker (&mobj->thinker, mobj);
break;
default:
// I_Error would overwrite VRAM, thus screens[0], thus the save buffer
// I_Error ("Unknown tclass %i in savegame",tclass);
}
}
}
//
// P_ArchiveSpecials
@ -325,7 +572,8 @@ void P_UnArchiveSpecials (void)
break;
default:
I_Error ("P_UnarchiveSpecials:Unknown tclass %i in savegame",tclass);
// I_Error would overwrite VRAM, thus screens[0], thus the save buffer
// I_Error ("P_UnarchiveSpecials:Unknown tclass %i in savegame",tclass);
}
}

View File

@ -120,6 +120,35 @@ static int DoomKeyToKeycode(int key)
case SKEY_FRAMESKIP: return KEYCODE_VARS;
case SKEY_PROFILER: return KEYCODE_RIGHTP;
/* Alphabetic keys */
case 'A': return KEYCODE_XOT;
case 'B': return KEYCODE_LOG;
case 'C': return KEYCODE_LN;
case 'D': return KEYCODE_SIN;
case 'E': return KEYCODE_COS;
case 'F': return KEYCODE_TAN;
case 'G': return KEYCODE_FRAC;
case 'H': return KEYCODE_FD;
case 'I': return KEYCODE_LEFTP;
case 'J': return KEYCODE_RIGHTP;
case 'K': return KEYCODE_COMMA;
case 'L': return KEYCODE_ARROW;
case 'M': return KEYCODE_7;
case 'N': return KEYCODE_8;
case 'O': return KEYCODE_9;
case 'P': return KEYCODE_4;
case 'Q': return KEYCODE_5;
case 'R': return KEYCODE_6;
case 'S': return KEYCODE_MUL;
case 'T': return KEYCODE_DIV;
case 'U': return KEYCODE_1;
case 'V': return KEYCODE_2;
case 'W': return KEYCODE_3;
case 'X': return KEYCODE_PLUS;
case 'Y': return KEYCODE_MINUS;
case 'Z': return KEYCODE_0;
case KEY_BACKSPACE: return KEYCODE_DEL;
default: return -1;
}
}