- connecting the dots in the menu. Duke Nukem can now start a level.

This commit is contained in:
Christoph Oelckers 2019-11-26 23:20:54 +01:00
parent 46d1f8517a
commit 3b7aa74c27
9 changed files with 95 additions and 329 deletions

View file

@ -168,8 +168,23 @@ struct GameStats
int timesecnd; int timesecnd;
}; };
struct FGameStartup
{
int Episode;
int Level;
int Skill;
int CustomLevel1;
int CustomLevel2;
};
struct GameInterface struct GameInterface
{ {
enum EMenuSounds
{
SelectSound,
ChooseSound
};
virtual ~GameInterface() {} virtual ~GameInterface() {}
virtual void faketimerhandler() {} // This is a remnant of older versions, but Blood backend has not updated yet. virtual void faketimerhandler() {} // This is a remnant of older versions, but Blood backend has not updated yet.
virtual int app_main() = 0; virtual int app_main() = 0;
@ -182,9 +197,11 @@ struct GameInterface
virtual void DrawNativeMenuText(int fontnum, int state, int xpos, int ypos, float fontscale, const char* text, int flags) {} virtual void DrawNativeMenuText(int fontnum, int state, int xpos, int ypos, float fontscale, const char* text, int flags) {}
virtual void MainMenuOpened() {} virtual void MainMenuOpened() {}
virtual void MenuOpened() {} virtual void MenuOpened() {}
virtual void MenuSelectSound() {} virtual void MenuClosed() {}
virtual void MenuChooseSound() {} virtual void MenuSound(EMenuSounds snd) {}
virtual bool CanSave() { return true; } virtual bool CanSave() { return true; }
virtual void CustomMenuSelection(int menu, int item) {}
virtual void StartGame(FGameStartup& gs) {}
}; };
extern GameInterface* gi; extern GameInterface* gi;

View file

@ -130,7 +130,7 @@ bool DListMenu::Responder (event_t *ev)
if (mDesc->mItems[i]->CheckHotkey(ch)) if (mDesc->mItems[i]->CheckHotkey(ch))
{ {
mDesc->mSelectedItem = i; mDesc->mSelectedItem = i;
gi->MenuSelectSound(); gi->MenuSound(GameInterface::SelectSound);
return true; return true;
} }
} }
@ -139,7 +139,7 @@ bool DListMenu::Responder (event_t *ev)
if (mDesc->mItems[i]->CheckHotkey(ch)) if (mDesc->mItems[i]->CheckHotkey(ch))
{ {
mDesc->mSelectedItem = i; mDesc->mSelectedItem = i;
gi->MenuSelectSound(); gi->MenuSound(GameInterface::SelectSound);
return true; return true;
} }
} }
@ -166,7 +166,7 @@ bool DListMenu::MenuEvent (int mkey, bool fromcontroller)
if (--mDesc->mSelectedItem < 0) mDesc->mSelectedItem = mDesc->mItems.Size()-1; if (--mDesc->mSelectedItem < 0) mDesc->mSelectedItem = mDesc->mItems.Size()-1;
} }
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable() && mDesc->mSelectedItem != startedAt); while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable() && mDesc->mSelectedItem != startedAt);
gi->MenuSelectSound(); gi->MenuSound(GameInterface::SelectSound);
return true; return true;
case MKEY_Down: case MKEY_Down:
@ -175,13 +175,13 @@ bool DListMenu::MenuEvent (int mkey, bool fromcontroller)
if (++mDesc->mSelectedItem >= (int)mDesc->mItems.Size()) mDesc->mSelectedItem = 0; if (++mDesc->mSelectedItem >= (int)mDesc->mItems.Size()) mDesc->mSelectedItem = 0;
} }
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable() && mDesc->mSelectedItem != startedAt); while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable() && mDesc->mSelectedItem != startedAt);
gi->MenuSelectSound(); gi->MenuSound(GameInterface::SelectSound);
return true; return true;
case MKEY_Enter: case MKEY_Enter:
if (mDesc->mSelectedItem >= 0 && mDesc->mItems[mDesc->mSelectedItem]->Activate(mDesc->mMenuName)) if (mDesc->mSelectedItem >= 0 && mDesc->mItems[mDesc->mSelectedItem]->Activate(mDesc->mMenuName))
{ {
gi->MenuChooseSound(); gi->MenuSound(GameInterface::ChooseSound);
} }
return true; return true;

View file

@ -437,20 +437,23 @@ bool M_SetMenu(FName menu, int param, FName caller)
case NAME_EpisodeMenu: case NAME_EpisodeMenu:
// sent from the episode menu // sent from the episode menu
GameStartupInfo.Episode = param; GameStartupInfo.Episode = param;
GameStartupInfo.Level = 0;
GameStartupInfo.CustomLevel1 = GameStartupInfo.CustomLevel2 = -1; GameStartupInfo.CustomLevel1 = GameStartupInfo.CustomLevel2 = -1;
GameStartupInfo.Skill = gDefaultSkill; GameStartupInfo.Skill = gDefaultSkill;
break; break;
case NAME_CustomGameMenu: case NAME_CustomGameMenu:
GameStartupInfo.CustomLevel1 = param; GameStartupInfo.CustomLevel1 = param;
GameStartupInfo.Episode = GameStartupInfo.CustomLevel2 = -1; GameStartupInfo.CustomLevel2 = -1;
GameStartupInfo.Episode = -1;
GameStartupInfo.Level = -1;
GameStartupInfo.Skill = gDefaultSkill; GameStartupInfo.Skill = gDefaultSkill;
// gi->CustomMenuSelection(-1, param); gi->CustomMenuSelection(param, -1);
break; break;
case NAME_CustomSubMenu1: case NAME_CustomSubMenu1:
GameStartupInfo.CustomLevel2 = param; GameStartupInfo.CustomLevel2 = param;
// gi->CustomMenuSelection(GameStartupInfo.CustomLevel1, param); gi->CustomMenuSelection(GameStartupInfo.CustomLevel1, param);
menu = FName(ENamedName(menu + param)); menu = FName(ENamedName(menu + param));
break; break;
@ -462,7 +465,8 @@ bool M_SetMenu(FName menu, int param, FName caller)
switch (menu) switch (menu)
{ {
case NAME_StartGame: case NAME_StartGame:
// gi->StartGame(&GameStartupInfo); M_ClearMenus(); // must be done before starting the level.
gi->StartGame(GameStartupInfo);
return false; return false;
#if 0 #if 0
@ -844,6 +848,7 @@ void M_ClearMenus ()
} }
menuactive = MENU_Off; menuactive = MENU_Off;
GUICapture &= ~1; GUICapture &= ~1;
gi->MenuClosed();
} }
void Menu_Close(int playerid) void Menu_Close(int playerid)

View file

@ -9,6 +9,7 @@
#include "version.h" #include "version.h"
#include "textures.h" #include "textures.h"
#include "zstring.h" #include "zstring.h"
#include "baselayer.h"
EXTERN_CVAR(Float, snd_menuvolume) EXTERN_CVAR(Float, snd_menuvolume)
EXTERN_CVAR(Int, m_use_mouse); EXTERN_CVAR(Int, m_use_mouse);
@ -113,15 +114,6 @@ enum ENativeFontValues
// positive values for color are direct palswap indices. // positive values for color are direct palswap indices.
}; };
struct FGameStartup
{
int Episode;
int Skill;
int CustomLevel1;
int CustomLevel2;
};
extern FGameStartup GameStartupInfo; extern FGameStartup GameStartupInfo;
struct FSaveGameNode struct FSaveGameNode

View file

@ -1035,7 +1035,7 @@ static void BuildEpisodeMenu()
if (gVolumeNames[i].IsNotEmpty() && !(gVolumeFlags[i] & EF_HIDEFROMSP)) if (gVolumeNames[i].IsNotEmpty() && !(gVolumeFlags[i] & EF_HIDEFROMSP))
{ {
auto it = new FListMenuItemNativeText(ld->mXpos, 0, 0, gVolumeNames[i][0], gVolumeNames[i], NIT_BigFont, NIT_ActiveState, 1, NAME_SkillMenu, i + 1); auto it = new FListMenuItemNativeText(ld->mXpos, 0, 0, gVolumeNames[i][0], gVolumeNames[i], NIT_BigFont, NIT_ActiveState, 1, NAME_SkillMenu, i);
ld->mItems.Push(it); ld->mItems.Push(it);
addedVolumes++; addedVolumes++;
if (gVolumeSubtitles[i].IsNotEmpty()) if (gVolumeSubtitles[i].IsNotEmpty())

View file

@ -388,25 +388,30 @@ void GameInterface::MenuOpened()
} }
} }
void GameInterface::MenuSelectSound() void GameInterface::MenuSound(::GameInterface::EMenuSounds snd)
{ {
S_PlaySound(KICK_HIT); switch (snd)
} {
case SelectSound:
S_PlaySound(KICK_HIT);
break;
void GameInterface::MenuChooseSound() case ChooseSound:
{ S_PlaySound(PISTOL_BODYHIT);
S_PlaySound(PISTOL_BODYHIT); break;
default:
return;
}
} }
/*
void GameInterface::MenuClosed() void GameInterface::MenuClosed()
{ {
S_PlaySound(EXITMENUSOUND); S_PlaySound(EXITMENUSOUND);
if (!ud.pause_on) if (!ud.pause_on)
S_PauseSounds(false); S_PauseSounds(false);
} }
*/
bool GameInterface::CanSave() bool GameInterface::CanSave()
{ {
@ -420,6 +425,46 @@ bool GameInterface::CanSave()
return true; return true;
} }
void GameInterface::CustomMenuSelection(int menu, int item)
{
ud.returnvar[0] = item;
ud.returnvar[1] = -1;
VM_OnEventWithReturn(EVENT_NEWGAMECUSTOM, -1, myconnectindex, menu);
}
void GameInterface::StartGame(FGameStartup& gs)
{
int32_t skillsound = PISTOL_BODYHIT;
switch (gs.Skill)
{
case 0:
skillsound = JIBBED_ACTOR6;
break;
case 1:
skillsound = BONUS_SPEECH1;
break;
case 2:
skillsound = DUKE_GETWEAPON2;
break;
case 3:
skillsound = JIBBED_ACTOR5;
break;
}
ud.m_player_skill = gs.Skill + 1;
ud.skill_voice = S_PlaySound(skillsound);
ud.m_respawn_monsters = (gs.Skill == 3);
ud.m_monsters_off = ud.monsters_off = 0;
ud.m_respawn_items = 0;
ud.m_respawn_inventory = 0;
ud.multimode = 1;
ud.m_volume_number = gs.Episode;
ud.m_level_number = gs.Level;
G_NewGame_EnterLevel();
}
END_DUKE_NS END_DUKE_NS
static TMenuClassDescriptor<Duke::MainMenu> _mm("Duke.MainMenu"); static TMenuClassDescriptor<Duke::MainMenu> _mm("Duke.MainMenu");

View file

@ -158,9 +158,11 @@ struct GameInterface : ::GameInterface
// Everything else is either custom screens or will use the generic option menu style. // Everything else is either custom screens or will use the generic option menu style.
void DrawNativeMenuText(int fontnum, int state, int xpos, int ypos, float fontscale, const char* text, int orientation) override; void DrawNativeMenuText(int fontnum, int state, int xpos, int ypos, float fontscale, const char* text, int orientation) override;
void MenuOpened() override; void MenuOpened() override;
void MenuSelectSound() override; void MenuClosed() override;
void MenuChooseSound() override; void MenuSound(EMenuSounds snd) override;
bool CanSave() override; bool CanSave() override;
void CustomMenuSelection(int menu, int item) override;
void StartGame(FGameStartup& gs) override;
}; };

View file

@ -1632,8 +1632,8 @@ void __fastcall VM_SetUserdef(int const labelNum, int const lParm2, int32_t cons
case USERDEFS_M_FFIRE: m_ffire = iSet; break; case USERDEFS_M_FFIRE: m_ffire = iSet; break;
case USERDEFS_FFIRE: ud.ffire = iSet; break; case USERDEFS_FFIRE: ud.ffire = iSet; break;
case USERDEFS_M_PLAYER_SKILL: ud.m_player_skill = iSet; break; case USERDEFS_M_PLAYER_SKILL: ud.m_player_skill = iSet; break;
case USERDEFS_M_LEVEL_NUMBER: m_level_number = iSet; break; case USERDEFS_M_LEVEL_NUMBER: GameStartupInfo.Level = m_level_number = iSet; break;
case USERDEFS_M_VOLUME_NUMBER: ud.m_volume_number = iSet; break; case USERDEFS_M_VOLUME_NUMBER: GameStartupInfo.Episode = ud.m_volume_number = iSet; break;
case USERDEFS_MULTIMODE: ud.multimode = iSet; break; case USERDEFS_MULTIMODE: ud.multimode = iSet; break;
case USERDEFS_PLAYER_SKILL: ud.player_skill = iSet; break; case USERDEFS_PLAYER_SKILL: ud.player_skill = iSet; break;
case USERDEFS_LEVEL_NUMBER: ud.level_number = iSet; break; case USERDEFS_LEVEL_NUMBER: ud.level_number = iSet; break;

View file

@ -2763,63 +2763,6 @@ static void Menu_EntryLinkActivate(MenuEntry_t *entry)
{ {
switch (g_currentMenu) switch (g_currentMenu)
{ {
case MENU_EPISODE:
if (entry != &ME_EPISODE_USERMAP)
{
ud.m_volume_number = M_EPISODE.currentEntry;
m_level_number = 0;
if (g_skillCnt == 0)
Menu_StartGameWithoutSkill();
}
break;
case MENU_NEWGAMECUSTOM:
ud.returnvar[0] = -1;
VM_OnEventWithReturn(EVENT_NEWGAMECUSTOM, -1, myconnectindex, M_NEWGAMECUSTOM.currentEntry);
break;
case MENU_NEWGAMECUSTOMSUB:
ud.returnvar[0] = M_NEWGAMECUSTOMSUB.currentEntry;
ud.returnvar[1] = -1;
VM_OnEventWithReturn(EVENT_NEWGAMECUSTOM, -1, myconnectindex, M_NEWGAMECUSTOM.currentEntry);
break;
case MENU_SKILL:
{
int32_t skillsound = PISTOL_BODYHIT;
switch (M_SKILL.currentEntry)
{
case 0:
skillsound = JIBBED_ACTOR6;
break;
case 1:
skillsound = BONUS_SPEECH1;
break;
case 2:
skillsound = DUKE_GETWEAPON2;
break;
case 3:
skillsound = JIBBED_ACTOR5;
break;
}
ud.m_player_skill = M_SKILL.currentEntry+1;
ud.skill_voice = S_PlaySound(skillsound);
if (M_SKILL.currentEntry == 3) ud.m_respawn_monsters = 1;
else ud.m_respawn_monsters = 0;
ud.m_monsters_off = ud.monsters_off = 0;
ud.m_respawn_items = 0;
ud.m_respawn_inventory = 0;
ud.multimode = 1;
G_NewGame_EnterLevel();
break; break;
} }
@ -3563,163 +3506,6 @@ static void Menu_FileSelect(int32_t input)
} }
static Menu_t* Menu_BinarySearch(MenuID_t query, uint16_t searchstart, uint16_t searchend)
{
const uint16_t thissearch = (searchstart + searchend) / 2;
const MenuID_t difference = query - Menus[thissearch].menuID;
if (difference == 0)
return &Menus[thissearch];
else if (searchstart == searchend)
return NULL;
else if (difference > 0)
{
if (thissearch == searchend)
return NULL;
searchstart = thissearch + 1;
}
else if (difference < 0)
{
if (thissearch == searchstart)
return NULL;
searchend = thissearch - 1;
}
return Menu_BinarySearch(query, searchstart, searchend);
}
static Menu_t* Menu_Find(MenuID_t query)
{
if ((unsigned) query > (unsigned) Menus[numMenus-1].menuID)
return NULL;
return Menu_BinarySearch(query, 0, numMenus-1);
}
static Menu_t* Menu_FindFiltered(MenuID_t query)
{
if ((g_player[myconnectindex].ps->gm&MODE_GAME) && query == MENU_MAIN)
query = MENU_MAIN_INGAME;
return Menu_Find(query);
}
MenuAnimation_t m_animation;
int32_t Menu_Anim_SinOutRight(MenuAnimation_t *animdata)
{
return sintable[divscale10((int32_t) totalclock - animdata->start, animdata->length) + 512] - 16384;
}
int32_t Menu_Anim_SinInRight(MenuAnimation_t *animdata)
{
return sintable[divscale10((int32_t) totalclock - animdata->start, animdata->length) + 512] + 16384;
}
int32_t Menu_Anim_SinOutLeft(MenuAnimation_t *animdata)
{
return -sintable[divscale10((int32_t) totalclock - animdata->start, animdata->length) + 512] + 16384;
}
int32_t Menu_Anim_SinInLeft(MenuAnimation_t *animdata)
{
return -sintable[divscale10((int32_t) totalclock - animdata->start, animdata->length) + 512] - 16384;
}
void Menu_AnimateChange(int32_t cm, MenuAnimationType_t animtype)
{
if (cm == MENU_KEYBOARDKEYS)
{
GUICapture |= 2;
return;
}
if (FURY)
{
m_animation.start = 0;
m_animation.length = 0;
Menu_Change(cm);
return;
}
switch (animtype)
{
case MA_Advance:
{
Menu_t * const previousMenu = m_currentMenu;
if (!Menu_Change(cm))
{
m_animation.out = Menu_Anim_SinOutRight;
m_animation.in = Menu_Anim_SinInRight;
m_animation.start = (int32_t) totalclock;
m_animation.length = 30;
m_animation.previous = previousMenu;
m_animation.current = m_currentMenu;
}
break;
}
case MA_Return:
{
Menu_t * const previousMenu = m_currentMenu;
if (!Menu_Change(cm))
{
m_animation.out = Menu_Anim_SinOutLeft;
m_animation.in = Menu_Anim_SinInLeft;
m_animation.start = (int32_t) totalclock;
m_animation.length = 30;
m_animation.previous = previousMenu;
m_animation.current = m_currentMenu;
}
break;
}
default:
m_animation.start = 0;
m_animation.length = 0;
Menu_Change(cm);
break;
}
}
static void Menu_MaybeSetSelectionToChild(Menu_t * m, MenuID_t id)
{
if (m->type == Menu)
{
auto menu = (MenuMenu_t *)m->object;
if (menu->currentEntry < menu->numEntries)
{
MenuEntry_t const * currentEntry = menu->entrylist[menu->currentEntry];
if (currentEntry != NULL && currentEntry->type == Link)
{
auto const * link = (MenuLink_t const *)currentEntry->entry;
if (link->linkID == id)
return; // already good to go
}
}
for (int i = 0, i_end = menu->numEntries; i < i_end; ++i)
{
MenuEntry_t const * entry = menu->entrylist[i];
if (entry != NULL && entry->type == Link && !(entry->flags & MEF_Hidden))
{
auto const * link = (MenuLink_t const *)entry->entry;
if (link->linkID == id)
{
menu->currentEntry = i;
Menu_AdjustForCurrentEntryAssignmentBlind(menu);
break;
}
}
}
}
}
static void Menu_ReadSaveGameHeaders() static void Menu_ReadSaveGameHeaders()
{ {
ReadSaveGameHeaders(); ReadSaveGameHeaders();
@ -3761,16 +3547,6 @@ static void Menu_AboutToStartDisplaying(Menu_t * m)
{ {
switch (m->menuID) switch (m->menuID)
{ {
case MENU_MAIN:
if (FURY)
ME_MAIN_LOADGAME.name = s_Continue;
break;
case MENU_MAIN_INGAME:
if (FURY)
ME_MAIN_LOADGAME.name = s_LoadGame;
break;
case MENU_NEWGAMECUSTOMSUB: case MENU_NEWGAMECUSTOMSUB:
Menu_PopulateNewGameCustomSub(M_NEWGAMECUSTOM.currentEntry); Menu_PopulateNewGameCustomSub(M_NEWGAMECUSTOM.currentEntry);
break; break;
@ -3888,10 +3664,7 @@ static void Menu_AboutToStartDisplaying(Menu_t * m)
static void Menu_ChangingTo(Menu_t * m) static void Menu_ChangingTo(Menu_t * m)
{ {
#ifdef __ANDROID__
if (m->menuID == MENU_TOUCHBUTTONS)
AndroidToggleButtonEditor();
#endif
switch (m->type) switch (m->type)
{ {
@ -3903,74 +3676,6 @@ static void Menu_ChangingTo(Menu_t * m)
} }
} }
int Menu_Change(MenuID_t cm)
{
Menu_t * beginMenu = m_currentMenu;
cm = VM_OnEventWithReturn(EVENT_CHANGEMENU, g_player[screenpeek].ps->i, screenpeek, cm);
if (cm == MENU_PREVIOUS)
{
m_currentMenu = m_previousMenu;
g_currentMenu = g_previousMenu;
}
else if (cm == MENU_CLOSE)
Menu_Close(myconnectindex);
else if (cm >= 0)
{
Menu_t * search = Menu_FindFiltered(cm);
if (search == NULL)
return 0; // intentional, so that users don't use any random value as "don't change"
// security
if (search->type == Verify &&
search->parentID != MENU_PREVIOUS &&
search->parentID != MENU_CLOSE &&
search->parentID != g_currentMenu)
return 1;
m_previousMenu = m_currentMenu;
g_previousMenu = g_currentMenu;
m_currentMenu = search;
g_currentMenu = search->menuID;
}
else
return 1;
if (FURY)
{
Menu_t * parent = m_currentMenu, * result = NULL;
while (parent != NULL && parent->menuID != MENU_OPTIONS && parent->menuID != MENU_MAIN && parent->menuID != MENU_MAIN_INGAME)
{
result = parent = Menu_FindFiltered(parent->parentID);
}
m_parentMenu = result;
if (result)
{
Menu_MaybeSetSelectionToChild(result, m_currentMenu->menuID);
Menu_AboutToStartDisplaying(result);
}
}
Menu_MaybeSetSelectionToChild(m_currentMenu, beginMenu->menuID);
Menu_AboutToStartDisplaying(m_currentMenu);
Menu_ChangingTo(m_currentMenu);
#if !defined EDUKE32_TOUCH_DEVICES
m_menuchange_watchpoint = 1;
#endif
return 0;
}