diff --git a/README b/README index 9bb8da4..09a339c 100644 --- a/README +++ b/README @@ -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 diff --git a/cgdoom/d_main.c b/cgdoom/d_main.c index 6093a27..5cd0394 100644 --- a/cgdoom/d_main.c +++ b/cgdoom/d_main.c @@ -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++; diff --git a/cgdoom/g_game.c b/cgdoom/g_game.c index 0808302..b017502 100644 --- a/cgdoom/g_game.c +++ b/cgdoom/g_game.c @@ -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>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 diff --git a/cgdoom/i_system.c b/cgdoom/i_system.c index e4c9f48..0e90d6b 100644 --- a/cgdoom/i_system.c +++ b/cgdoom/i_system.c @@ -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++) diff --git a/cgdoom/m_menu.c b/cgdoom/m_menu.c index 27664ab..af47c56 100644 --- a/cgdoom/m_menu.c +++ b/cgdoom/m_menu.c @@ -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) { diff --git a/cgdoom/m_misc.c b/cgdoom/m_misc.c index 0685212..a0b0a1a 100644 --- a/cgdoom/m_misc.c +++ b/cgdoom/m_misc.c @@ -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; \ No newline at end of file +char* defaultfile; diff --git a/cgdoom/p_saveg.c b/cgdoom/p_saveg.c index 561fb6f..be09c60 100644 --- a/cgdoom/p_saveg.c +++ b/cgdoom/p_saveg.c @@ -71,6 +71,253 @@ void P_ArchivePlayers (void) } +// +// P_UnArchivePlayers +// +void P_UnArchivePlayers (void) +{ + int i; + int j; + + for (i=0 ; ifloorheight >> 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 ; iflags; + *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 ; ifloorheight = *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 ; iflags = *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); } } diff --git a/src-cg/keyboard.c b/src-cg/keyboard.c index bb8629b..18d4593 100644 --- a/src-cg/keyboard.c +++ b/src-cg/keyboard.c @@ -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; } }