From 70db526cec515b06642f44349e62bf4676955e56 Mon Sep 17 00:00:00 2001 From: Arsinikk Date: Wed, 6 Aug 2025 23:03:25 -0500 Subject: [PATCH 1/6] Add NOMONSTERS skill flag --- prboom2/src/dsda/skill_info.c | 3 +++ prboom2/src/dsda/skill_info.h | 1 + prboom2/src/dsda/wad_stats.c | 6 +++++- prboom2/src/hexen/a_action.c | 5 +++-- prboom2/src/hexen/p_things.c | 5 +++-- prboom2/src/p_mobj.c | 6 +++--- 6 files changed, 18 insertions(+), 8 deletions(-) diff --git a/prboom2/src/dsda/skill_info.c b/prboom2/src/dsda/skill_info.c index c56f138c9..b7dcb52ef 100644 --- a/prboom2/src/dsda/skill_info.c +++ b/prboom2/src/dsda/skill_info.c @@ -288,6 +288,9 @@ void dsda_RefreshGameSkill(void) { if (respawnparm && !skill_info.respawn_time) skill_info.respawn_time = 12; + if (nomonsters) + skill_info.flags |= SI_NO_MONSTERS; + if (fastparm) skill_info.flags |= SI_FAST_MONSTERS; diff --git a/prboom2/src/dsda/skill_info.h b/prboom2/src/dsda/skill_info.h index fd9cc38c3..3f8965f6a 100644 --- a/prboom2/src/dsda/skill_info.h +++ b/prboom2/src/dsda/skill_info.h @@ -31,6 +31,7 @@ #define SI_EASY_BOSS_BRAIN 0x0100 #define SI_MUST_CONFIRM 0x0200 #define SI_AUTO_USE_HEALTH 0x0400 +#define SI_NO_MONSTERS 0x1000 typedef uint16_t skill_info_flags_t; diff --git a/prboom2/src/dsda/wad_stats.c b/prboom2/src/dsda/wad_stats.c index 91be79a8b..b95227063 100644 --- a/prboom2/src/dsda/wad_stats.c +++ b/prboom2/src/dsda/wad_stats.c @@ -268,6 +268,7 @@ void dsda_WadStatsExitMap(int missed_monsters) { int skill; int nightmare_skill; int best_normal_skill; + int nomo_flag; if (!current_map_stats || demoplayback) return; @@ -275,7 +276,10 @@ void dsda_WadStatsExitMap(int missed_monsters) { nightmare_skill = num_skills; best_normal_skill = num_skills - 1; - if (!nomonsters) { + // Get conditions for recording wad stats + nomo_flag = skill_info.flags & SI_NO_MONSTERS; + + if (!nomo_flag) { skill = gameskill + 1; if (skill > current_map_stats->best_skill) { if (current_map_stats->best_skill < best_normal_skill) { diff --git a/prboom2/src/hexen/a_action.c b/prboom2/src/hexen/a_action.c index 954aa991c..a570994f8 100644 --- a/prboom2/src/hexen/a_action.c +++ b/prboom2/src/hexen/a_action.c @@ -26,6 +26,7 @@ #include "p_enemy.h" #include "p_tick.h" +#include "dsda/skill_info.h" #include "hexen/p_things.h" #include "a_action.h" @@ -118,7 +119,7 @@ void A_PotteryExplode(mobj_t * actor) S_StartMobjSound(mo, hexen_sfx_pottery_explode); if (actor->special_args[0]) { // Spawn an item - if (!nomonsters + if (!(skill_info.flags & SI_NO_MONSTERS) || !(mobjinfo[TranslateThingType[actor->special_args[0]]]. flags & MF_COUNTKILL)) { // Only spawn monsters if not -nomonsters @@ -831,7 +832,7 @@ void A_SoAExplode(mobj_t * actor) { // Spawn an item // TODO: should this be on or off? #if 0 // Checks are not present in version 1.1 - if (!nomonsters + if (!(skill_info.flags & SI_NO_MONSTERS)) || !(mobjinfo[TranslateThingType[actor->special_args[0]]]. flags & MF_COUNTKILL)) #endif diff --git a/prboom2/src/hexen/p_things.c b/prboom2/src/hexen/p_things.c index 3e7aac98f..6cbca2769 100644 --- a/prboom2/src/hexen/p_things.c +++ b/prboom2/src/hexen/p_things.c @@ -23,6 +23,7 @@ #include "p_inter.h" #include "p_tick.h" +#include "dsda/skill_info.h" #include "hexen/a_action.h" #include "p_things.h" @@ -159,7 +160,7 @@ dboolean EV_ThingProjectile(byte * args, dboolean gravity) searcher = -1; tid = args[0]; moType = TranslateThingType[args[1]]; - if (nomonsters && (mobjinfo[moType].flags & MF_COUNTKILL)) + if ((skill_info.flags & SI_NO_MONSTERS) && (mobjinfo[moType].flags & MF_COUNTKILL)) { // Don't spawn monsters if -nomonsters return false; } @@ -209,7 +210,7 @@ dboolean EV_ThingSpawn(byte * args, dboolean fog) searcher = -1; tid = args[0]; moType = TranslateThingType[args[1]]; - if (nomonsters && (mobjinfo[moType].flags & MF_COUNTKILL)) + if ((skill_info.flags & SI_NO_MONSTERS) && (mobjinfo[moType].flags & MF_COUNTKILL)) { // Don't spawn monsters if -nomonsters return false; } diff --git a/prboom2/src/p_mobj.c b/prboom2/src/p_mobj.c index b7d73975b..8318690a5 100644 --- a/prboom2/src/p_mobj.c +++ b/prboom2/src/p_mobj.c @@ -1529,7 +1529,7 @@ dboolean P_SpawnProjectile(short thing_id, mobj_t *source, int spawn_num, angle_ is_monster = (type == MT_SKULL || (mobjinfo[type].flags & MF_COUNTKILL)); - if (nomonsters && is_monster) + if ((skill_info.flags & SI_NO_MONSTERS) && is_monster) return false; dsda_ResetThingIDSearch(&search); @@ -1630,7 +1630,7 @@ dboolean P_SpawnThing(short thing_id, mobj_t *source, int spawn_num, if (type == num_mobj_types) return false; - if (nomonsters && (type == MT_SKULL || (mobjinfo[type].flags & MF_COUNTKILL))) + if ((skill_info.flags & SI_NO_MONSTERS) && (type == MT_SKULL || (mobjinfo[type].flags & MF_COUNTKILL))) return false; dsda_ResetThingIDSearch(&search); @@ -2539,7 +2539,7 @@ mobj_t* P_SpawnMapThing (const mapthing_t* mthing, int index) // don't spawn any monsters if -nomonsters - if (nomonsters && (i == MT_SKULL || (mobjinfo[i].flags & MF_COUNTKILL))) + if ((skill_info.flags & SI_NO_MONSTERS) && (i == MT_SKULL || (mobjinfo[i].flags & MF_COUNTKILL))) return NULL; // spawn it From be974cadb5b194988b61eabfc9ba912741105fd5 Mon Sep 17 00:00:00 2001 From: Arsinikk Date: Thu, 7 Aug 2025 00:38:25 -0500 Subject: [PATCH 2/6] Menu Pre-Setup --- prboom2/src/m_menu.c | 198 +++++++++++++++++++++++++++++-------------- prboom2/src/m_menu.h | 3 + 2 files changed, 136 insertions(+), 65 deletions(-) diff --git a/prboom2/src/m_menu.c b/prboom2/src/m_menu.c index 7bc1ec2bf..c1be2f476 100644 --- a/prboom2/src/m_menu.c +++ b/prboom2/src/m_menu.c @@ -135,10 +135,10 @@ #define S_CREDIT 0x00200000 // killough 10/98: credit #define S_THERMO 0x00400000 // Slider for choosing a value #define S_CHOICE 0x00800000 // this item has several values -// #define S_ 0x01000000 +#define S_DISABLED 0x01000000 #define S_NAME 0x02000000 #define S_RESET_Y 0x04000000 -// #define S_ 0x08000000 +#define S_FUNC 0x08000000 // #define S_ 0x10000000 // #define S_ 0x20000000 #define S_STR 0x40000000 // need to refactor things... @@ -150,9 +150,9 @@ * S_HASDEFPTR = the set of items whose var field points to default array */ -#define S_SHOWDESC (S_LABEL|S_TITLE|S_YESNO|S_CRITEM|S_COLOR|S_PREV|S_NEXT|S_INPUT|S_WEAP|S_NUM|S_FILE|S_CREDIT|S_CHOICE|S_THERMO|S_NAME) +#define S_SHOWDESC (S_LABEL|S_TITLE|S_YESNO|S_CRITEM|S_COLOR|S_PREV|S_NEXT|S_INPUT|S_WEAP|S_NUM|S_FILE|S_CREDIT|S_CHOICE|S_FUNC|S_THERMO|S_NAME) -#define S_SHOWSET (S_YESNO|S_CRITEM|S_COLOR|S_INPUT|S_WEAP|S_NUM|S_FILE|S_CHOICE|S_THERMO|S_NAME) +#define S_SHOWSET (S_YESNO|S_CRITEM|S_COLOR|S_INPUT|S_WEAP|S_NUM|S_FILE|S_CHOICE|S_FUNC|S_THERMO|S_NAME) #define S_STRING (S_FILE|S_NAME) @@ -757,6 +757,7 @@ void M_ChooseSkill(int choice) message = s_NIGHTMARE; // Ty 03/27/98 - externalized M_StartMessage(message, M_VerifySkill, true); + M_SetupNextMenu(&ReadDef1); // Clear in-menu variables when "no" or "ESC" return; } @@ -1656,6 +1657,22 @@ static void M_SetSetupMenuItemOn (const int x) } } +static dboolean M_ItemSelected(const setup_menu_t *s) +{ + int flags = s->m_flags; + + if (s == current_setup_menu + set_menu_itemon && whichSkull && !(flags & S_NOSELECT)) + return true; + + return false; +} + +static void M_BlinkingArrowRight(const setup_menu_t *s) +{ + if (M_ItemSelected(s) && !setup_select) + strcat(menu_buffer, " <"); +} + static void M_UpdateSetupMenu(setup_menu_t *new_setup_menu) { current_setup_menu = new_setup_menu; @@ -1797,6 +1814,48 @@ static int entry_index; static char entry_string_index[ENTRY_STRING_BFR_SIZE]; // points to new strings while editing static int choice_value; +///////////////////////////// +// +// M_ItemDisabled +// +// Disable certain menu options based on various conditions: +// StrictMode, Complevel, and more! +// +// + +static dboolean M_ItemDisabled(const setup_menu_t* s) +{ + // Strict Mode + if (dsda_StrictMode() && dsda_IsStrictConfig(s->config_id)) + return true; + + return false; +} + +///////////////////////////// +// +// Menu Text Colors +// +// + +static int GetItemColor(int flags) +{ + return (flags & S_TITLE && flags & S_DISABLED) ? cr_title + CR_DARKEN : + flags & S_DISABLED ? cr_label + CR_DARKEN : + flags & (S_SELECT|S_TC_SEL) ? cr_label_edit : + flags & S_HILITE ? cr_label_highlight : + flags & (S_TITLE|S_NEXT|S_PREV) ? cr_title : + cr_label; // killough 10/98 +} + +static int GetOptionColor(int flags) +{ + return flags & S_DISABLED ? cr_value + CR_DARKEN : + flags & S_SELECT ? cr_value_edit : + flags & S_HILITE ? cr_value_highlight : + cr_value; +} + ///////////////////////////// // // phares 4/18/98: @@ -1810,31 +1869,42 @@ static int choice_value; static void M_DrawItem(const setup_menu_t* s, int y) { int x = s->m_x; + char text[66]; int flags = s->m_flags; char *p, *t; int w = 0; - int color = - dsda_StrictMode() && dsda_IsStrictConfig(s->config_id) ? cr_label + CR_DARKEN : - flags & (S_SELECT|S_TC_SEL) ? cr_label_edit : - flags & S_HILITE ? cr_label_highlight : - flags & (S_TITLE|S_NEXT|S_PREV) ? cr_title : - cr_label; // killough 10/98 + int color; + + if (M_ItemDisabled(s)) + flags |= S_DISABLED; + + color = GetItemColor(flags); + + // Add ". . ." to function + sprintf(text, "%s%s", s->m_text, (flags & S_FUNC) ? ". . ." : ""); /* killough 10/98: * Enhance to support multiline text separated by newlines. * This supports multiline items on horizontally-crowded menus. */ - for (p = t = Z_Strdup(s->m_text); (p = strtok(p,"\n")); y += 8, p = NULL) + for (p = t = Z_Strdup(text); (p = strtok(p,"\n")); y += 8, p = NULL) { /* killough 10/98: support left-justification: */ - if (flags & S_CENTER) - w = M_GetPixelWidth(p) / 2; - else if (!(flags & S_LEFTJUST)) - w = M_GetPixelWidth(p) + 4; - M_DrawString(x - w, y ,color, p); - // print a blinking "arrow" next to the currently highlighted menu item - if (s == current_setup_menu + set_menu_itemon && whichSkull && !(flags & S_NOSELECT)) - M_DrawString(x - w - 8, y, color, ">"); + w = M_GetPixelWidth(p); + + if (!(flags & S_LEFTJUST)) + x -= (w + 4); + + M_DrawString(x, y, color, p); + + // print a blinking left "arrow" before highlighted menu item + if (M_ItemSelected(s)) + M_DrawString(x - 8, y, color, ">"); + + // print a blinking right "arrow" after highlighted function + if (flags & S_FUNC) + if (M_ItemSelected(s) && !setup_select) + M_DrawString(x + w, y, color, " <"); } Z_Free(t); } @@ -1865,19 +1935,17 @@ static void M_DrawSetting(const setup_menu_t* s, int y) // Determine color of the text. This may or may not be used later, // depending on whether the item is a text string or not. - color = - dsda_StrictMode() && dsda_IsStrictConfig(s->config_id) ? cr_value + CR_DARKEN : - flags & S_SELECT ? cr_value_edit : - flags & S_HILITE ? cr_value_highlight : - cr_value; + if (M_ItemDisabled(s)) + flags |= S_DISABLED; + + color = GetOptionColor(flags); // Is the item a YES/NO item? if (flags & S_YESNO) { strcpy(menu_buffer, dsda_IntConfig(s->config_id) ? "YES" : "NO"); - if (s == current_setup_menu + set_menu_itemon && whichSkull && !setup_select) - strcat(menu_buffer, " <"); + M_BlinkingArrowRight(s); M_DrawMenuString(x,y,color); return; } @@ -1900,12 +1968,11 @@ static void M_DrawSetting(const setup_menu_t* s, int y) if (flags & S_CRITEM) { color = value; - if (dsda_StrictMode() && dsda_IsStrictConfig(s->config_id)) + if (M_ItemDisabled(s)) color += CR_DARKEN; } } - if (s == current_setup_menu + set_menu_itemon && whichSkull && !setup_select) - strcat(menu_buffer, " <"); + M_BlinkingArrowRight(s); M_DrawMenuString(x, y, color); return; } @@ -1962,9 +2029,7 @@ static void M_DrawSetting(const setup_menu_t* s, int y) if (!any_input) M_GetKeyString(0, 0); - if (s == current_setup_menu + set_menu_itemon && whichSkull && !setup_select) - strcat(menu_buffer, " <"); - + M_BlinkingArrowRight(s); M_DrawMenuString(x, y, color); return; @@ -1991,8 +2056,7 @@ static void M_DrawSetting(const setup_menu_t* s, int y) if (!ch) // don't show this item in automap mode V_DrawNamePatch(x+1,y,0,"M_PALNO", CR_DEFAULT, VPT_STRETCH); - if (s == current_setup_menu + set_menu_itemon && whichSkull && !setup_select) - M_DrawString(x + 8, y, color, " <"); + M_BlinkingArrowRight(s); return; } @@ -2049,8 +2113,7 @@ static void M_DrawSetting(const setup_menu_t* s, int y) // Draw the setting for the item strcpy(menu_buffer, text); - if (s == current_setup_menu + set_menu_itemon && whichSkull && !setup_select) - strcat(menu_buffer, " <"); + M_BlinkingArrowRight(s); M_DrawMenuString(x, y, color); return; } @@ -2081,8 +2144,7 @@ static void M_DrawSetting(const setup_menu_t* s, int y) } } - if (s == current_setup_menu + set_menu_itemon && whichSkull && !setup_select) - strcat(menu_buffer, " <"); + M_BlinkingArrowRight(s); M_DrawMenuString(x,y,color); return; } @@ -2092,8 +2154,7 @@ static void M_DrawSetting(const setup_menu_t* s, int y) sprintf(menu_buffer, "%d", dsda_IntConfig(s->config_id)); - if (s == current_setup_menu + set_menu_itemon && whichSkull && !setup_select) - strcat(menu_buffer, " <"); + M_BlinkingArrowRight(s); M_DrawMenuString(x + 80, y + 3, color); return; } @@ -2340,6 +2401,8 @@ static void M_DrawInstructions(void) else { if (flags & S_INPUT) M_DrawInstructionString(cr_info_highlight, "Press Enter to Change, Del to Clear"); + else if (flags & S_FUNC) + M_DrawInstructionString(cr_info_highlight, "Press Enter to Select"); else M_DrawInstructionString(cr_info_highlight, "Press Enter to Change"); } @@ -2351,6 +2414,7 @@ static void M_DrawInstructions(void) #define FINAL_ENTRY { 0, S_SKIP | S_END, m_null } #define EMPTY_LINE { 0, S_SKIP, m_null } #define NEW_COLUMN { 0, S_SKIP | S_RESET_Y, m_null } +#define FUNCTION(action_name, flags, offset_x, action_func) { action_name, !flags ? (S_FUNC) : (S_FUNC | flags), m_null, offset_x, .action = action_func } static void M_EnterSetup(menu_t *menu, dboolean *setup_flag, setup_menu_t *setup_menu) { @@ -3756,7 +3820,7 @@ static void M_BuildLevelTable(void) if (map->best_skill) { dsda_StringPrintF(&m_text, "%d", map->best_skill); entry->m_text = m_text.string; - if (map->best_skill == num_skills) + if (map->best_skill == num_og_skills) entry->m_flags |= S_TC_SEL; } else { @@ -4875,11 +4939,23 @@ static dboolean M_LevelTableResponder(int ch, int action, event_t* ev) static dboolean M_SetupCommonSelectResponder(int ch, int action, event_t* ev) { + setup_menu_t* ptr1 = current_setup_menu + set_menu_itemon; + + // Execute functions + if (ptr1->m_flags & S_FUNC) + { + if (action == MENU_ENTER) { + if (ptr1->action) + ptr1->action(); + + M_SelectDone(ptr1); + return true; + } + } + // changing an entry if (setup_select) { - setup_menu_t* ptr1 = current_setup_menu + set_menu_itemon; - if (action == MENU_ESCAPE) // Exit key = no change { M_SelectDone(ptr1); // phares 4/17/98 @@ -5100,7 +5176,7 @@ static dboolean M_SetupNavigationResponder(int ch, int action, event_t* ev) { int flags = ptr1->m_flags; - if (dsda_StrictMode() && dsda_IsStrictConfig(ptr1->config_id)) + if (M_ItemDisabled(ptr1)) return true; // You've selected an item to change. Highlight it, post a new @@ -6168,30 +6244,22 @@ void M_Drawer (void) if ( currentMenu->menuitems[i].status != -1 && ( !currentMenu->menuitems[i].name[0] || !W_LumpNameExists(currentMenu->menuitems[i].name) - ) + ) && !(currentMenu->menuitems[i].flags & MENUF_OPTLUMP) ) ++lumps_missing; - if (!lumps_missing) - for (i = 0; i < max; i++) - { - if (currentMenu->menuitems[i].name[0]) - V_DrawNamePatch(x, y, 0, currentMenu->menuitems[i].name, - currentMenu->menuitems[i].color, VPT_STRETCH); - - y += LINEHEIGHT; - } - else - for (i = 0; i < max; i++) - { - const char *alttext = currentMenu->menuitems[i].alttext; - - if (alttext) - M_WriteText(x, y + 8 - (M_StringHeight(alttext) / 2), - alttext, currentMenu->menuitems[i].color); - - y += LINEHEIGHT; - } + for (i = 0; i < max; i++) + { + const char *alttext = currentMenu->menuitems[i].alttext; + if (!lumps_missing && currentMenu->menuitems[i].name[0] && + !(currentMenu->menuitems[i].flags & MENUF_OPTLUMP)) + V_DrawNamePatch(x, y, 0, currentMenu->menuitems[i].name, + currentMenu->menuitems[i].color, VPT_STRETCH); + else if (alttext) + M_WriteText(x, y + 8 - (M_StringHeight(alttext) / 2), + alttext, currentMenu->menuitems[i].color); + y += LINEHEIGHT; + } // DRAW SKULL if (max > 0) diff --git a/prboom2/src/m_menu.h b/prboom2/src/m_menu.h index 486a56996..3cf0d6be6 100644 --- a/prboom2/src/m_menu.h +++ b/prboom2/src/m_menu.h @@ -127,6 +127,7 @@ typedef struct setup_menu_s int input; // composite input identifier const char **selectstrings; /* list of strings for choice value */ struct setup_menu_s *menu; /* next or prev menu */ + void (*action)(void); // killough 10/98: function to call after changing } setup_menu_t; // @@ -145,9 +146,11 @@ typedef struct char alphaKey; // hotkey in menu const char *alttext; int color; + byte flags; } menuitem_t; #define MENUF_TEXTINPUT 0x01 +#define MENUF_OPTLUMP 0x02 // make graphic lump optional typedef struct menu_s { From 4ed7f867a1e14fa0991310fef086122c68aa143c Mon Sep 17 00:00:00 2001 From: Arsinikk Date: Sat, 9 Aug 2025 05:35:53 -0500 Subject: [PATCH 3/6] Add Custom Skill --- prboom2/src/dsda/configuration.c | 65 +++++++++++ prboom2/src/dsda/configuration.h | 16 +++ prboom2/src/dsda/demo.c | 7 ++ prboom2/src/dsda/global.c | 1 + prboom2/src/dsda/global.h | 1 + prboom2/src/dsda/skill_info.c | 105 +++++++++++++++++- prboom2/src/dsda/skill_info.h | 22 ++++ prboom2/src/dsda/wad_stats.c | 12 +- prboom2/src/g_game.c | 23 +++- prboom2/src/g_game.h | 1 + prboom2/src/heretic/mn_menu.c | 8 +- prboom2/src/m_cheat.c | 2 +- prboom2/src/m_menu.c | 183 ++++++++++++++++++++++++++++++- 13 files changed, 432 insertions(+), 14 deletions(-) diff --git a/prboom2/src/dsda/configuration.c b/prboom2/src/dsda/configuration.c index 674ca4880..856a4f8fe 100644 --- a/prboom2/src/dsda/configuration.c +++ b/prboom2/src/dsda/configuration.c @@ -37,6 +37,7 @@ #include "dsda/exhud.h" #include "dsda/features.h" #include "dsda/input.h" +#include "dsda/skill_info.h" #include "dsda/stretch.h" #include "dsda/utility.h" @@ -1007,6 +1008,70 @@ dsda_config_t dsda_config[dsda_config_count] = { "dsda_coop_spawns", dsda_config_coop_spawns, CONF_BOOL(0), NULL, NOT_STRICT, dsda_AlterGameFlags }, + [dsda_config_skill_spawn_filter] = { + "dsda_skill_spawn_filter", dsda_config_skill_spawn_filter, + dsda_config_int, 0, 2, { 1 }, &cskill_spawn_filter + }, + [dsda_config_skill_coop_spawns] = { + "dsda_skill_coop_spawns", dsda_config_skill_coop_spawns, + CONF_BOOL(0), &cskill_coop_spawns + }, + [dsda_config_skill_ammo_factor] = { + "dsda_skill_ammo_factor", dsda_config_skill_ammo_factor, + dsda_config_int, 0, 4, { 1 }, &cskill_ammo_factor + }, + [dsda_config_skill_damage_factor] = { + "dsda_skill_damage_factor", dsda_config_skill_damage_factor, + dsda_config_int, 0, 4, { 1 }, &cskill_damage_factor + }, + [dsda_config_skill_armor_factor] = { + "dsda_skill_armor_factor", dsda_config_skill_armor_factor, + dsda_config_int, 0, 4, { 1 }, &cskill_armor_factor + }, + [dsda_config_skill_health_factor] = { + "dsda_skill_health_factor", dsda_config_skill_health_factor, + dsda_config_int, 0, 4, { 1 }, &cskill_health_factor + }, + [dsda_config_skill_monster_health_factor] = { + "dsda_skill_monster_health_factor", dsda_config_skill_monster_health_factor, + dsda_config_int, 0, 4, { 1 }, &cskill_monster_hp_factor + }, + [dsda_config_skill_friend_health_factor] = { + "dsda_skill_friend_health_factor", dsda_config_skill_friend_health_factor, + dsda_config_int, 0, 4, { 1 }, &cskill_friend_hp_factor + }, + [dsda_config_skill_respawn_monsters] = { + "dsda_skill_respawn_monsters", dsda_config_skill_respawn_monsters, + CONF_BOOL(0), &cskill_respawn + }, + [dsda_config_skill_respawn_time] = { + "dsda_skill_respawn_time", dsda_config_skill_respawn_time, + dsda_config_int, 1, 32, { 12 }, &cskill_respawn_time + }, + [dsda_config_skill_no_monsters] = { + "dsda_skill_no_monsters", dsda_config_skill_no_monsters, + CONF_BOOL(0), &cskill_no_monsters + }, + [dsda_config_skill_fast_monsters] = { + "dsda_skill_fast_monsters", dsda_config_skill_fast_monsters, + CONF_BOOL(0), &cskill_fast_monsters + }, + [dsda_config_skill_aggressive_monsters] = { + "dsda_skill_aggressive_monsters", dsda_config_skill_aggressive_monsters, + CONF_BOOL(0), &cskill_aggressive + }, + [dsda_config_skill_easy_brain] = { + "dsda_skill_easy_brain", dsda_config_skill_easy_brain, + CONF_BOOL(0), &cskill_easy_brain + }, + [dsda_config_skill_auto_use_health] = { + "dsda_skill_auto_use_health", dsda_config_skill_auto_use_health, + CONF_BOOL(0), &cskill_auto_use_hp + }, + [dsda_config_skill_no_pain] = { + "dsda_skill_no_pain", dsda_config_skill_no_pain, + CONF_BOOL(0), &cskill_no_pain + }, [dsda_config_parallel_sfx_limit] = { "dsda_parallel_sfx_limit", dsda_config_parallel_sfx_limit, dsda_config_int, 0, 32, { 0 }, NULL, NOT_STRICT, dsda_InitParallelSFXFilter diff --git a/prboom2/src/dsda/configuration.h b/prboom2/src/dsda/configuration.h index fb6b70e37..46acebe80 100644 --- a/prboom2/src/dsda/configuration.h +++ b/prboom2/src/dsda/configuration.h @@ -221,6 +221,22 @@ typedef enum { dsda_config_fast_monsters, dsda_config_no_monsters, dsda_config_coop_spawns, + dsda_config_skill_spawn_filter, + dsda_config_skill_coop_spawns, + dsda_config_skill_ammo_factor, + dsda_config_skill_damage_factor, + dsda_config_skill_armor_factor, + dsda_config_skill_health_factor, + dsda_config_skill_monster_health_factor, + dsda_config_skill_friend_health_factor, + dsda_config_skill_respawn_monsters, + dsda_config_skill_respawn_time, + dsda_config_skill_no_monsters, + dsda_config_skill_fast_monsters, + dsda_config_skill_aggressive_monsters, + dsda_config_skill_easy_brain, + dsda_config_skill_auto_use_health, + dsda_config_skill_no_pain, dsda_config_parallel_sfx_limit, dsda_config_parallel_sfx_window, dsda_config_movement_toggle_sfx, diff --git a/prboom2/src/dsda/demo.c b/prboom2/src/dsda/demo.c index 751e015de..1a2e06c92 100644 --- a/prboom2/src/dsda/demo.c +++ b/prboom2/src/dsda/demo.c @@ -39,6 +39,7 @@ #include "dsda/map_format.h" #include "dsda/preferences.h" #include "dsda/settings.h" +#include "dsda/skill_info.h" #include "dsda/split_tracker.h" #include "dsda/utility.h" @@ -280,6 +281,12 @@ void dsda_InitDemoRecording(void) { if (dsda_Flag(dsda_arg_pistol_start)) I_Error("The -pistolstart option is not allowed when recording a demo!"); + if (customskill && dsda_Flag(dsda_arg_skill)) + { + if (dsda_Arg(dsda_arg_skill)->value.v_int > num_og_skills) + I_Error("Custom Skill is not allowed when recording a demo!\n"); + } + demorecording = true; // Key settings revert when starting a new attempt diff --git a/prboom2/src/dsda/global.c b/prboom2/src/dsda/global.c index 7437e6904..90f1da49b 100644 --- a/prboom2/src/dsda/global.c +++ b/prboom2/src/dsda/global.c @@ -138,6 +138,7 @@ const char* g_skyflatname; dboolean hexen = false; dboolean heretic = false; dboolean raven = false; +dboolean customskill = false; static void dsda_InitDoom(void) { int i; diff --git a/prboom2/src/dsda/global.h b/prboom2/src/dsda/global.h index 8396180ca..d7048f86d 100644 --- a/prboom2/src/dsda/global.h +++ b/prboom2/src/dsda/global.h @@ -104,6 +104,7 @@ extern int g_mf_shadow; extern const char* g_skyflatname; extern dboolean heretic; +extern dboolean customskill; void dsda_InitGlobal(void); diff --git a/prboom2/src/dsda/skill_info.c b/prboom2/src/dsda/skill_info.c index b7dcb52ef..cf49ac104 100644 --- a/prboom2/src/dsda/skill_info.c +++ b/prboom2/src/dsda/skill_info.c @@ -127,6 +127,7 @@ const skill_info_t hexen_skill_infos[5] = { }; int num_skills; +int num_og_skills; skill_info_t* skill_infos; static void dsda_CopyFactor(fixed_t* dest, const char* source) { @@ -139,7 +140,7 @@ static void dsda_CopyFactor(fixed_t* dest, const char* source) { *dest = dsda_StringToFixed(source) + 1; } -void dsda_CopySkillInfo(int i, const doom_mapinfo_skill_t* info) { +static void dsda_CopySkillInfo(int i, const doom_mapinfo_skill_t* info) { memset(&skill_infos[i], 0, sizeof(skill_infos[i])); dsda_CopyFactor(&skill_infos[i].ammo_factor, info->ammo_factor); @@ -171,11 +172,18 @@ void dsda_CopySkillInfo(int i, const doom_mapinfo_skill_t* info) { void dsda_InitSkills(void) { int i = 0; int j; + int original_skills; dboolean clear_skills; + // Check for new skills + dsda_CheckCustomSkill(); + clear_skills = (doom_mapinfo.num_skills && doom_mapinfo.skills_cleared); - num_skills = (clear_skills ? 0 : 5) + doom_mapinfo.num_skills; + num_skills = (clear_skills ? 0 : 5) + (int)doom_mapinfo.num_skills + customskill; + num_og_skills = num_skills - customskill; + + original_skills = 5; skill_infos = Z_Calloc(num_skills, sizeof(*skill_infos)); @@ -186,7 +194,7 @@ void dsda_InitSkills(void) { heretic ? heretic_skill_infos : doom_skill_infos; - for (i = 0; i < 5; ++i) + for (i = 0; i < original_skills; ++i) skill_infos[i] = original_skill_infos[i]; } @@ -221,6 +229,87 @@ void dsda_InitSkills(void) { } } +///////////////////////////////////////// +// +// Add Custom Skill Properties +// +// + +// Custom Skill variables +int cskill_spawn_filter; +int cskill_ammo_factor; +int cskill_damage_factor; +int cskill_armor_factor; +int cskill_health_factor; +int cskill_monster_hp_factor; +int cskill_friend_hp_factor; +int cskill_respawn; +int cskill_respawn_time; +int cskill_coop_spawns; +int cskill_no_monsters; +int cskill_fast_monsters; +int cskill_aggressive; +int cskill_no_pain; +int cskill_easy_brain; +int cskill_auto_use_hp; + +static int dsda_GetCustomSpawnFilter(int config) { + switch (config) + { + case 0: return 1; // if "easy", skill 1 + case 1: return 3; // if "medium", skill 3 + case 2: return 4; // if "hard", skill 4 + default: return false; + } +} + +static int dsda_GetCustomFactor(int config) { + switch (config) + { + case 0: return FRACUNIT / 2; // Half + case 1: return FRACUNIT; // Default + case 2: return FRACUNIT * 3 / 2; // 1.5x - Raven games use this + case 3: return FRACUNIT * 2; // Double + case 4: return FRACUNIT * 4; // Quad + default: return false; + } +} + +void dsda_UpdateCustomSkill(int custom_skill_num) { + // Add label for skill cheat + skill_infos[custom_skill_num].name = "Custom Skill"; + + // Reset custom skill properties + skill_infos[custom_skill_num].flags = 0; + skill_infos[custom_skill_num].respawn_time = 0; + + // Get spawn filter value + skill_infos[custom_skill_num].spawn_filter = dsda_GetCustomSpawnFilter(cskill_spawn_filter);; + + // Get multiplier factors + skill_infos[custom_skill_num].ammo_factor = dsda_GetCustomFactor(cskill_ammo_factor); + skill_infos[custom_skill_num].damage_factor = dsda_GetCustomFactor(cskill_damage_factor); + skill_infos[custom_skill_num].armor_factor = dsda_GetCustomFactor(cskill_armor_factor); + skill_infos[custom_skill_num].health_factor = dsda_GetCustomFactor(cskill_health_factor); + skill_infos[custom_skill_num].monster_health_factor = dsda_GetCustomFactor(cskill_monster_hp_factor); + skill_infos[custom_skill_num].friend_health_factor = dsda_GetCustomFactor(cskill_friend_hp_factor); + + // Get respawn time (if respawn is enabled) + if (cskill_respawn) skill_infos[custom_skill_num].respawn_time = cskill_respawn_time; + + // Add remaining flags + if (cskill_coop_spawns) skill_infos[custom_skill_num].flags |= SI_SPAWN_MULTI; + if (cskill_no_monsters) skill_infos[custom_skill_num].flags |= SI_NO_MONSTERS; + if (cskill_fast_monsters) skill_infos[custom_skill_num].flags |= SI_FAST_MONSTERS; + if (cskill_aggressive) skill_infos[custom_skill_num].flags |= SI_INSTANT_REACTION; + if (cskill_no_pain) skill_infos[custom_skill_num].flags |= SI_NO_PAIN; + if (cskill_easy_brain && !raven) skill_infos[custom_skill_num].flags |= SI_EASY_BOSS_BRAIN; + if (cskill_auto_use_hp && raven) skill_infos[custom_skill_num].flags |= SI_AUTO_USE_HEALTH; + + // Update the skill + dsda_UpdateGameSkill(custom_skill_num); +} + // At startup, set-up temp game modifier configs based off args / persistent cfgs // Only set once, as modifiers can break away from args // @@ -315,3 +404,13 @@ void dsda_AlterGameFlags(void) dsda_RefreshGameSkill(); } + +void dsda_CheckCustomSkill(void) { + //if (started_demo) + //return; + + if (!allow_incompatibility || netgame) + return; + + customskill = true; +} diff --git a/prboom2/src/dsda/skill_info.h b/prboom2/src/dsda/skill_info.h index 3f8965f6a..333ecdda7 100644 --- a/prboom2/src/dsda/skill_info.h +++ b/prboom2/src/dsda/skill_info.h @@ -33,6 +33,24 @@ #define SI_AUTO_USE_HEALTH 0x0400 #define SI_NO_MONSTERS 0x1000 +// Custom Skill variables +extern int cskill_spawn_filter; +extern int cskill_ammo_factor; +extern int cskill_damage_factor; +extern int cskill_armor_factor; +extern int cskill_health_factor; +extern int cskill_monster_hp_factor; +extern int cskill_friend_hp_factor; +extern int cskill_respawn; +extern int cskill_respawn_time; +extern int cskill_coop_spawns; +extern int cskill_no_monsters; +extern int cskill_fast_monsters; +extern int cskill_aggressive; +extern int cskill_no_pain; +extern int cskill_easy_brain; +extern int cskill_auto_use_hp; + typedef uint16_t skill_info_flags_t; typedef struct { @@ -56,10 +74,14 @@ extern skill_info_t skill_info; extern skill_info_t *skill_infos; extern int num_skills; +extern int num_og_skills; void dsda_InitSkills(void); void dsda_RefreshGameSkill(void); void dsda_UpdateGameSkill(int skill); +void dsda_UpdateCustomSkill(int custom_skill); +void dsda_CheckCustomSkill(void); + void dsda_AlterGameFlags(void); void dsda_InitGameModifiers(void); void dsda_ResetGameModifiers(void); diff --git a/prboom2/src/dsda/wad_stats.c b/prboom2/src/dsda/wad_stats.c index b95227063..6afadaf6b 100644 --- a/prboom2/src/dsda/wad_stats.c +++ b/prboom2/src/dsda/wad_stats.c @@ -268,19 +268,23 @@ void dsda_WadStatsExitMap(int missed_monsters) { int skill; int nightmare_skill; int best_normal_skill; + int extra_skill; int nomo_flag; + int skip_stats; if (!current_map_stats || demoplayback) return; - nightmare_skill = num_skills; - best_normal_skill = num_skills - 1; + skill = gameskill + 1; + nightmare_skill = num_og_skills; + best_normal_skill = num_og_skills - 1; + extra_skill = skill > num_og_skills; // Get conditions for recording wad stats nomo_flag = skill_info.flags & SI_NO_MONSTERS; + skip_stats = extra_skill || nomo_flag; - if (!nomo_flag) { - skill = gameskill + 1; + if (!skip_stats) { if (skill > current_map_stats->best_skill) { if (current_map_stats->best_skill < best_normal_skill) { current_map_stats->best_time = -1; diff --git a/prboom2/src/g_game.c b/prboom2/src/g_game.c index 7f3214125..6d5c6504d 100644 --- a/prboom2/src/g_game.c +++ b/prboom2/src/g_game.c @@ -185,6 +185,7 @@ int levels_completed; int longtics; dboolean coop_spawns; +dboolean skill_loadout; // e6y // There is a new command-line switch "-shorttics". @@ -1234,10 +1235,14 @@ static void G_DoLoadLevel (void) } // automatic pistol start when advancing from one level to the next - if (pistolstart) + if (pistolstart && !skill_loadout) if (allow_incompatibility) G_PlayerReborn(0); + // Custom Skill - Reset Pistol Start from Loadout + if (skill_loadout) + skill_loadout = false; + // initialize the msecnode_t freelist. phares 3/25/98 // any nodes in the freelist are gone by now, cleared // by Z_FreeTag() when the previous level ended or player @@ -1492,7 +1497,7 @@ void G_Ticker (void) { case ga_loadlevel: // force players to be initialized on level reload - if (!hexen) + if (!hexen && !skill_loadout) for (i = 0; i < g_maxplayers; i++) players[i].playerstate = PST_REBORN; G_DoLoadLevel(); @@ -2625,6 +2630,20 @@ void G_DeferedInitNew(int skill, int episode, int map) dsda_WatchDeferredInitNew(skill, episode, map); } +// Custom Skill - Restart with loadout [Nugget] +void G_RestartWithLoadout(void) +{ + gameaction = ga_loadlevel; + + G_PlayerFinishLevel(consoleplayer); + + // Reset automap + AM_Stop(false); + AM_clearMarks(); + + skill_loadout = true; +} + /* cph - * G_Compatibility * diff --git a/prboom2/src/g_game.h b/prboom2/src/g_game.h index 22915e0d2..605aa0132 100644 --- a/prboom2/src/g_game.h +++ b/prboom2/src/g_game.h @@ -72,6 +72,7 @@ void G_Compatibility(void); const byte *G_ReadOptions(const byte *demo_p); /* killough 3/1/98 - cph: const byte* */ byte *G_WriteOptions(byte *demo_p); // killough 3/1/98 void G_PlayerReborn(int player); +void G_RestartWithLoadout(void); void G_DoVictory(void); void G_BuildTiccmd (ticcmd_t* cmd); // CPhipps - move decl to header void G_ReadOneTick(ticcmd_t* cmd, const byte **data_p); diff --git a/prboom2/src/heretic/mn_menu.c b/prboom2/src/heretic/mn_menu.c index 17276c438..54ee7c217 100644 --- a/prboom2/src/heretic/mn_menu.c +++ b/prboom2/src/heretic/mn_menu.c @@ -442,7 +442,13 @@ void MN_Drawer(void) for (i = 0; i < max; i++) { const char *text = currentMenu->menuitems[i].alttext; - if (text) + int text_sml = text && (currentMenu->menuitems[i].flags == MENUF_OPTLUMP); + + if (text_sml) { // use small font for custom skill + y += 4; // add some padding (looks bad otherwise) + MN_DrTextA(text, x, y); + } + else if (text) MN_DrTextB(text, x, y); y += ITEM_HEIGHT; } diff --git a/prboom2/src/m_cheat.c b/prboom2/src/m_cheat.c index d83b6dfd6..1f5d8a9f9 100644 --- a/prboom2/src/m_cheat.c +++ b/prboom2/src/m_cheat.c @@ -609,7 +609,7 @@ static void cheat_skill(char buf[1]) { int skill = buf[0] - '0'; - if (skill >= 1 && skill <= num_skills) + if (skill >= 1 && skill <= num_og_skills) { gameskill = skill - 1; diff --git a/prboom2/src/m_menu.c b/prboom2/src/m_menu.c index c1be2f476..f354e6561 100644 --- a/prboom2/src/m_menu.c +++ b/prboom2/src/m_menu.c @@ -171,6 +171,7 @@ static dboolean set_keybnd_active = false; // in key binding setup screens static dboolean set_display_active = false; static dboolean set_demos_active = false; // in demos setup screen static dboolean set_compatibility_active = false; +static dboolean set_skill_builder_active = false; static dboolean set_weapon_active = false; // in weapons setup screen static dboolean set_auto_active = false; // in automap setup screen static dboolean level_table_active = false; @@ -307,6 +308,7 @@ static void M_DrawKeybnd(void); static void M_DrawDisplay(void); static void M_DrawDemos(void); static void M_DrawCompatibility(void); +static void M_DrawSkillBuilder(void); static void M_DrawWeapons(void); static void M_DrawAutoMap(void); static void M_DrawLevelTable(void); @@ -1762,6 +1764,16 @@ static menu_t CompatibilityDef = // ki 0 }; +static menu_t SkillBuilderDef = // killough 10/98 +{ + generic_setup_end, + &SkillDef, + Generic_Setup, + M_DrawSkillBuilder, + 34,5, // skull drawn here + 0 +}; + static menu_t WeaponDef = { generic_setup_end, @@ -3604,6 +3616,141 @@ static void M_DrawCompatibility(void) M_DrawScreenItems(current_setup_menu, DEFAULT_LIST_Y); } +///////////////////////////// +// +// Custom Skill Functions [based off Nugget] + +enum +{ + cskill_new_game, + cskill_pistol_start, + cskill_loadout_current +} cskill_mode_e; + +static void M_StartCustomSkill(int mode) +{ + // Use custom skill (-1 to match gameskill) + chosen_skill = num_skills - 1; + + dsda_UpdateCustomSkill(chosen_skill); + + if (mode == cskill_new_game || gamestate == GS_DEMOSCREEN) + M_FinishGameSelection(); + else if (mode == cskill_pistol_start || !in_game) + G_DeferedInitNew(chosen_skill, gameepisode, gamemap); + else if (mode == cskill_loadout_current) + G_RestartWithLoadout(); + + M_ClearMenus(); +} + +static void StartCustomSkill(int mode) +{ + M_StartCustomSkill(mode); + + M_LeaveSetupMenu(); + M_ClearMenus(); + S_StartVoidSound(g_sfx_swtchx); +} + +static void CSNewGame(void) +{ + StartCustomSkill(cskill_new_game); +} + +static void CSPistolStart(void) +{ + StartCustomSkill(cskill_pistol_start); +} + +static void CSCurrentLoadout(void) +{ + StartCustomSkill(cskill_loadout_current); +} + + +///////////////////////////// +// +// Custom Skill Builder. + +static const char *skill_pages[] = +{ + "Basic", + "Advanced", + NULL +}; + +setup_menu_t skill_options_builder[], skill_options_start[]; + +setup_menu_t* skill_options[] = +{ + skill_options_builder, + skill_options_start, + NULL +}; + +static const char *skill_spawn_filter[] = { "Easy", "Medium", "Hard", NULL }; +static const char *skill_ammo_multiplier[] = { "Half", "Default", "1.5x - Raven", "Double - ITYTD/NM", "Quad", NULL }; +static const char *skill_damage_multiplier[] = { "Half - ITYTD", "Default", "1.5x", "Double", "Quad", NULL }; +static const char *skill_multiplier[] = { "Half", "Default", "1.5x", "Double", "Quad", NULL }; + +#define SK_X 200 +#define SK_X2 50 + +setup_menu_t skill_options_builder[] = { + { "Thing Spawns", S_CHOICE, m_conf, SK_X, dsda_config_skill_spawn_filter, 0, skill_spawn_filter }, + { "Coop Spawns", S_YESNO, m_conf, SK_X, dsda_config_skill_coop_spawns }, + EMPTY_LINE, + { "Damage to Player", S_CHOICE, m_conf, SK_X, dsda_config_skill_damage_factor, 0, skill_damage_multiplier }, + { "Ammo Pickups %", S_CHOICE, m_conf, SK_X, dsda_config_skill_ammo_factor, 0, skill_ammo_multiplier }, + { "Auto Use Health", S_YESNO, m_conf, SK_X, dsda_config_skill_auto_use_health }, + EMPTY_LINE, + { "Respawn Monsters", S_YESNO, m_conf, SK_X, dsda_config_skill_respawn_monsters }, + { "Fast Monsters", S_YESNO, m_conf, SK_X, dsda_config_skill_fast_monsters }, + { "Aggressive Monsters", S_YESNO, m_conf, SK_X, dsda_config_skill_aggressive_monsters}, + { "No Monsters", S_YESNO, m_conf, SK_X, dsda_config_skill_no_monsters }, + EMPTY_LINE, + { "Pistol Start", S_YESNO, m_conf, SK_X, dsda_config_pistol_start }, + EMPTY_LINE, + FUNCTION("Start New Game", S_LEFTJUST, SK_X2, CSNewGame), + FUNCTION("Restart Map -- Pistol Start", S_LEFTJUST, SK_X2, CSPistolStart), + FUNCTION("Restart Map -- Current Loadout", S_LEFTJUST, SK_X2, CSCurrentLoadout), + + NEXT_PAGE(skill_options_start), + FINAL_ENTRY +}; + +setup_menu_t skill_options_start[] = { + { "Respawn Time", S_NUM, m_conf, SK_X, dsda_config_skill_respawn_time }, + { "Slow Spawn-Cube Spitter", S_YESNO, m_conf, SK_X, dsda_config_skill_easy_brain }, + { "Disable Pain States", S_YESNO, m_conf, SK_X, dsda_config_skill_no_pain }, + EMPTY_LINE, + { "Armor Pickups %", S_CHOICE, m_conf, SK_X, dsda_config_skill_armor_factor, 0, skill_multiplier }, + { "Health Pickups %", S_CHOICE, m_conf, SK_X, dsda_config_skill_health_factor, 0, skill_multiplier }, + { "Monster Health", S_CHOICE, m_conf, SK_X, dsda_config_skill_monster_health_factor, 0, skill_multiplier }, + { "Friend Health", S_CHOICE, m_conf, SK_X, dsda_config_skill_friend_health_factor, 0, skill_multiplier }, + + PREV_PAGE(skill_options_builder), + FINAL_ENTRY +}; + +static void M_SkillBuilder(int choice) +{ + M_EnterSetup(&SkillBuilderDef, &set_skill_builder_active, skill_options[0]); +} + +static void M_DrawSkillBuilder(void) +{ + M_ChangeMenu(NULL, mnact_full); + + M_DrawBackground(g_menu_flat, 0); + + M_DrawTitle(2, "CUSTOM SKILL BUILDER", cr_title); // M_CSTSKL + M_DrawInstructions(); + M_DrawTabs(skill_pages, sizeof(skill_pages), TABS_Y); + M_DrawScreenItems(current_setup_menu, DEFAULT_LIST_Y); +} + ///////////////////////////// // // The level table. @@ -6061,17 +6208,26 @@ dboolean M_Responder(event_t* ev) { // Plus a variety of routines that control the Big Font menu display. // Plus some initialization for game-dependant situations. +static menuitem_t CustomSkillMenu[] = { + { 1, "M_CSTSKL", M_SkillBuilder, 'c', "Custom Skill...", 0, MENUF_OPTLUMP }, +}; + static void M_InitializeSkillMenu(void) { extern skill_info_t *skill_infos; int i; + // if skill has more than 7 items, remove custom skill space + int cskill_space = num_og_skills < 7 && !raven; // looks bad in raven + int cskill_space_num = customskill ? cskill_space ? 2 : 1 : 0; + int skill_list = num_og_skills + cskill_space_num; + SkillDef.lastOn = dsda_IntConfig(dsda_config_default_skill) - 1; - SkillDef.numitems = num_skills; - SkillDef.menuitems = Z_Calloc(num_skills, sizeof(*SkillDef.menuitems)); + SkillDef.numitems = skill_list; + SkillDef.menuitems = Z_Calloc(skill_list, sizeof(*SkillDef.menuitems)); - for (i = 0; i < num_skills; ++i) + for (i = 0; i < num_og_skills; ++i) { SkillDef.menuitems[i].status = 1; @@ -6088,6 +6244,27 @@ static void M_InitializeSkillMenu(void) SkillDef.lastOn = i; } + // Add Custom Skill + if (customskill) + { + // Find where Custom Skill is in menu + int num_cskill = num_og_skills + cskill_space; + + // Add Custom Skill Spacing (if less than 7 items) + if (cskill_space) + SkillDef.menuitems[num_skills - 1].status = -1; // Disable selection for space + + // Fill in Custom Skill Info + SkillDef.menuitems[num_cskill].status = CustomSkillMenu[0].status; + + strcpy(SkillDef.menuitems[num_cskill].name, CustomSkillMenu[0].name); + + SkillDef.menuitems[num_cskill].alttext = CustomSkillMenu[0].alttext; + SkillDef.menuitems[num_cskill].routine = CustomSkillMenu[0].routine; + SkillDef.menuitems[num_cskill].alphaKey = CustomSkillMenu[0].alphaKey; + SkillDef.menuitems[num_cskill].flags = CustomSkillMenu[0].flags; + } + if (SkillDef.lastOn >= num_skills) SkillDef.lastOn = num_skills - 1; } From 1b32f117336457dc5608de7543b151630a05f4ec Mon Sep 17 00:00:00 2001 From: Arsinikk Date: Sat, 9 Aug 2025 06:13:46 -0500 Subject: [PATCH 4/6] Disable Loadout and Pistolstart for Hexen - It's incompatible --- prboom2/src/m_menu.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/prboom2/src/m_menu.c b/prboom2/src/m_menu.c index f354e6561..0b585b195 100644 --- a/prboom2/src/m_menu.c +++ b/prboom2/src/m_menu.c @@ -314,6 +314,10 @@ static void M_DrawAutoMap(void); static void M_DrawLevelTable(void); static void M_DrawExtHelp(void); +static void CSNewGame(void); +static void CSPistolStart(void); +static void CSCurrentLoadout(void); + static int M_GetPixelWidth(const char*); static void M_DrawString(int cx, int cy, int color, const char* ch); static void M_DrawMenuString(int,int,int); @@ -1841,6 +1845,14 @@ static dboolean M_ItemDisabled(const setup_menu_t* s) if (dsda_StrictMode() && dsda_IsStrictConfig(s->config_id)) return true; + // Hexen Stuff + if (hexen) + { + // Hexen doesn't allow pistolstart + loadout doesn't work due to key management + if (s->action == CSPistolStart || s->action == CSCurrentLoadout) + return true; + } + return false; } @@ -5092,6 +5104,9 @@ static dboolean M_SetupCommonSelectResponder(int ch, int action, event_t* ev) if (ptr1->m_flags & S_FUNC) { if (action == MENU_ENTER) { + if (M_ItemDisabled(ptr1)) + return true; + if (ptr1->action) ptr1->action(); From 619142b8f3d7c4d8b49d1b9dcc7a36e09b762ee7 Mon Sep 17 00:00:00 2001 From: Arsinikk Date: Wed, 13 Aug 2025 00:39:30 -0500 Subject: [PATCH 5/6] Fix automap menu related crash --- prboom2/src/m_menu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/prboom2/src/m_menu.c b/prboom2/src/m_menu.c index 0b585b195..f7f2df34d 100644 --- a/prboom2/src/m_menu.c +++ b/prboom2/src/m_menu.c @@ -2080,7 +2080,8 @@ static void M_DrawSetting(const setup_menu_t* s, int y) if (!ch) // don't show this item in automap mode V_DrawNamePatch(x+1,y,0,"M_PALNO", CR_DEFAULT, VPT_STRETCH); - M_BlinkingArrowRight(s); + if (M_ItemSelected(s) && !setup_select) + M_DrawString(x + 8, y, color, " <"); return; } From 0ae491ee487a67576f425eb10c1136098103d017 Mon Sep 17 00:00:00 2001 From: Arsinikk Date: Tue, 23 Sep 2025 16:50:24 -0500 Subject: [PATCH 6/6] Add Custom Skill into saved game --- prboom2/src/dsda/save.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/prboom2/src/dsda/save.c b/prboom2/src/dsda/save.c index d05a2ebee..f83aa19b8 100644 --- a/prboom2/src/dsda/save.c +++ b/prboom2/src/dsda/save.c @@ -34,6 +34,7 @@ #include "dsda/music.h" #include "dsda/options.h" #include "dsda/settings.h" +#include "dsda/skill_info.h" #include "save.h" @@ -142,6 +143,30 @@ static void dsda_UnArchiveContext(void) { true_basetic = gametic - true_logictic_value; } +skill_info_t saved_custom_skill; + +void dsda_ArchiveCustomSkill(void) +{ + // don't store info if normal skill + if (gameskill != (num_skills - 1)) + return; + + saved_custom_skill = skill_infos[num_skills - 1]; // custom skill (-1 to match gameskill) + + P_SAVE_X(saved_custom_skill); +} + +void dsda_UnArchiveCustomSkill(void) +{ + // don't store info if normal skill + if (gameskill != (num_skills - 1)) + return; + + P_LOAD_X(saved_custom_skill); + + skill_infos[num_skills - 1] = saved_custom_skill; // custom skill (-1 to match gameskill) +} + int saved_pistolstart, saved_respawnparm, saved_fastparm, saved_nomonsters, saved_coop_spawns; void dsda_ArchiveGameModifiers(void) @@ -191,6 +216,7 @@ void dsda_ArchiveAll(void) { P_ArchiveRNG(); P_ArchiveMap(); + dsda_ArchiveCustomSkill(); dsda_ArchiveGameModifiers(); dsda_ArchiveInternal(); } @@ -212,6 +238,7 @@ void dsda_UnArchiveAll(void) { P_UnArchiveMap(); P_MapEnd(); + dsda_UnArchiveCustomSkill(); dsda_UnArchiveGameModifiers(); dsda_UnArchiveInternal(); }