From e0a94686b09ac741e50d7cf9ae560b8716a943e3 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Sat, 26 Sep 2020 18:44:49 +0200 Subject: [PATCH] Add game speed to multiplayer Speed can only be set on game creation --- Source/diablo.cpp | 2 +- Source/diablo.h | 2 +- Source/gamemenu.cpp | 2 +- Source/mainmenu.cpp | 3 +- Source/multi.cpp | 4 ++ Source/nthread.cpp | 8 +-- Source/stores.cpp | 2 +- SourceX/DiabloUI/selgame.cpp | 94 +++++++++++++++++++++++++++++++++--- SourceX/DiabloUI/selgame.h | 4 ++ SourceX/storm/storm_net.cpp | 2 +- structs.h | 1 + 11 files changed, 105 insertions(+), 19 deletions(-) diff --git a/Source/diablo.cpp b/Source/diablo.cpp index e4e0821ef..9bd483836 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -43,7 +43,7 @@ int sgnTimeoutCurs; char sgbMouseDown; int color_cycle_timer; int ticks_per_sec = 20; -WORD game_speed; +WORD tick_delay = 50; /* rdata */ diff --git a/Source/diablo.h b/Source/diablo.h index 181917290..6fbde94b0 100644 --- a/Source/diablo.h +++ b/Source/diablo.h @@ -48,7 +48,7 @@ extern int PauseMode; extern char sgbMouseDown; extern int color_cycle_timer; extern int ticks_per_sec; -extern WORD game_speed; +extern WORD tick_delay; void FreeGameMem(); BOOL StartGame(BOOL bNewGame, BOOL bSinglePlayer); diff --git a/Source/gamemenu.cpp b/Source/gamemenu.cpp index d55d2ca09..9e539b57c 100644 --- a/Source/gamemenu.cpp +++ b/Source/gamemenu.cpp @@ -340,7 +340,7 @@ void gamemenu_speed(BOOL bActivate) } SRegSaveValue("devilutionx", "game speed", 0, ticks_per_sec); - game_speed = 1000 / ticks_per_sec; + tick_delay = 1000 / ticks_per_sec; } void gamemenu_color_cycling(BOOL bActivate) diff --git a/Source/mainmenu.cpp b/Source/mainmenu.cpp index 2023443bc..9cba254ab 100644 --- a/Source/mainmenu.cpp +++ b/Source/mainmenu.cpp @@ -141,7 +141,7 @@ BOOL mainmenu_single_player() if (!SRegLoadValue("devilutionx", "game speed", 0, &ticks_per_sec)) { SRegSaveValue("devilutionx", "game speed", 0, ticks_per_sec); } - game_speed = 1000 / ticks_per_sec; + tick_delay = 1000 / ticks_per_sec; return mainmenu_init_menu(SELHERO_NEW_DUNGEON); } @@ -165,7 +165,6 @@ BOOL mainmenu_init_menu(int type) BOOL mainmenu_multi_player() { gbMaxPlayers = MAX_PLRS; - game_speed = 50; return mainmenu_init_menu(SELHERO_CONNECT); } diff --git a/Source/multi.cpp b/Source/multi.cpp index 7fd018933..f82002895 100644 --- a/Source/multi.cpp +++ b/Source/multi.cpp @@ -609,6 +609,7 @@ void multi_handle_events(_SNETEVENT *pEvt) gameData = (_gamedata *)pEvt->data; sgGameInitInfo.dwSeed = gameData->dwSeed; sgGameInitInfo.bDiff = gameData->bDiff; + sgGameInitInfo.bRate = gameData->bRate; sgbPlayerTurnBitTbl[pEvt->playerid] = TRUE; break; case EVENT_TYPE_PLAYER_LEAVE_GAME: @@ -647,6 +648,7 @@ BOOL NetInit(BOOL bSinglePlayer, BOOL *pfExitProgram) SetRndSeed(0); sgGameInitInfo.dwSeed = time(NULL); sgGameInitInfo.bDiff = gnDifficulty; + sgGameInitInfo.bRate = ticks_per_sec; memset(&ProgramData, 0, sizeof(ProgramData)); ProgramData.size = sizeof(ProgramData); #ifdef SPAWN @@ -720,6 +722,8 @@ BOOL NetInit(BOOL bSinglePlayer, BOOL *pfExitProgram) gbSelectProvider = FALSE; } gnDifficulty = sgGameInitInfo.bDiff; + ticks_per_sec = sgGameInitInfo.bRate; + tick_delay = 1000 / ticks_per_sec; SetRndSeed(sgGameInitInfo.dwSeed); for (i = 0; i < NUMLEVELS; i++) { diff --git a/Source/nthread.cpp b/Source/nthread.cpp index fb6e0d658..a258d815e 100644 --- a/Source/nthread.cpp +++ b/Source/nthread.cpp @@ -79,7 +79,7 @@ BOOL nthread_recv_turns(BOOL *pfSendAsync) *pfSendAsync = FALSE; sgbPacketCountdown--; if (sgbPacketCountdown) { - last_tick += game_speed; + last_tick += tick_delay; return TRUE; } sgbSyncCountdown--; @@ -87,7 +87,7 @@ BOOL nthread_recv_turns(BOOL *pfSendAsync) if (sgbSyncCountdown != 0) { *pfSendAsync = TRUE; - last_tick += game_speed; + last_tick += tick_delay; return TRUE; } if (!SNetReceiveTurns(0, MAX_PLRS, (char **)glpMsgTbl, gdwMsgLenTbl, (LPDWORD)player_state)) { @@ -105,7 +105,7 @@ BOOL nthread_recv_turns(BOOL *pfSendAsync) sgbSyncCountdown = 4; multi_msg_countdown(); *pfSendAsync = TRUE; - last_tick += game_speed; + last_tick += tick_delay; return TRUE; } } @@ -184,7 +184,7 @@ unsigned int nthread_handler(void *data) if (nthread_recv_turns(&received)) delta = last_tick - SDL_GetTicks(); else - delta = game_speed; + delta = tick_delay; sgMemCrit.Leave(); if (delta > 0) SDL_Delay(delta); diff --git a/Source/stores.cpp b/Source/stores.cpp index 6af347420..674977e1d 100644 --- a/Source/stores.cpp +++ b/Source/stores.cpp @@ -81,7 +81,7 @@ void InitStores() void PentSpn2Spin() { DWORD ticks = SDL_GetTicks(); - if (ticks - PentSpn2Tick > game_speed) { + if (ticks - PentSpn2Tick > tick_delay) { PentSpn2Frame = (PentSpn2Frame & 7) + 1; PentSpn2Tick = ticks; } diff --git a/SourceX/DiabloUI/selgame.cpp b/SourceX/DiabloUI/selgame.cpp index 31e344822..60aba63e5 100644 --- a/SourceX/DiabloUI/selgame.cpp +++ b/SourceX/DiabloUI/selgame.cpp @@ -19,6 +19,7 @@ int selgame_selectedGame; bool selgame_endMenu; int *gdwPlayerId; int gbDifficulty; +int gbTickRate; int heroLevel; static _SNETPROGRAMDATA *m_client_info; @@ -170,7 +171,7 @@ void selgame_GameSelection_Select(int value) UiInitList(0, NUM_DIFFICULTIES - 1, selgame_Diff_Focus, selgame_Diff_Select, selgame_Diff_Esc, vecSelGameDialog, true); break; } - case 1: + case 1: { strncpy(title, "Join TCP Games", sizeof(title) - 1); SDL_Rect rect4 = { PANEL_LEFT + 305, (UI_OFFSET_Y + 211), 285, 33 }; @@ -188,6 +189,7 @@ void selgame_GameSelection_Select(int value) UiInitList(0, 0, NULL, selgame_Password_Init, selgame_GameSelection_Init, vecSelGameDialog); break; } + } } void selgame_GameSelection_Esc() @@ -248,12 +250,7 @@ void selgame_Diff_Select(int value) return; } - if (provider == SELCONN_LOOPBACK) { - selgame_Password_Select(0); - return; - } - - selgame_Password_Init(0); + selgame_GameSpeedSelection(); } void selgame_Diff_Esc() @@ -274,6 +271,83 @@ void selgame_Diff_Esc() selgame_GameSelection_Init(); } +void selgame_GameSpeedSelection() +{ + gfnHeroInfo(UpdateHeroLevel); + + selgame_FreeVectors(); + + UiAddBackground(&vecSelGameDialog); + UiAddLogo(&vecSelGameDialog); + + SDL_Rect rect1 = { PANEL_LEFT + 24, (UI_OFFSET_Y + 161), 590, 35 }; + vecSelGameDialog.push_back(new UiArtText("Create Game", rect1, UIS_CENTER | UIS_BIG)); + + SDL_Rect rect2 = { PANEL_LEFT + 34, (UI_OFFSET_Y + 211), 205, 33 }; + vecSelGameDialog.push_back(new UiArtText(selgame_Label, rect2, UIS_CENTER | UIS_BIG)); + + SDL_Rect rect3 = { PANEL_LEFT + 35, (UI_OFFSET_Y + 256), DESCRIPTION_WIDTH, 192 }; + vecSelGameDialog.push_back(new UiArtText(selgame_Description, rect3)); + + SDL_Rect rect4 = { PANEL_LEFT + 299, (UI_OFFSET_Y + 211), 295, 35 }; + vecSelGameDialog.push_back(new UiArtText("Select Game Speed", rect4, UIS_CENTER | UIS_BIG)); + + vecSelGameDlgItems.push_back(new UiListItem("Normal", 0)); + vecSelGameDlgItems.push_back(new UiListItem("Fast", 1)); + vecSelGameDlgItems.push_back(new UiListItem("Faster", 2)); + vecSelGameDlgItems.push_back(new UiListItem("Fastest", 3)); + + vecSelGameDialog.push_back(new UiList(vecSelGameDlgItems, PANEL_LEFT + 300, (UI_OFFSET_Y + 279), 295, 26, UIS_CENTER | UIS_MED | UIS_GOLD)); + + SDL_Rect rect5 = { PANEL_LEFT + 299, (UI_OFFSET_Y + 427), 140, 35 }; + vecSelGameDialog.push_back(new UiArtTextButton("OK", &UiFocusNavigationSelect, rect5, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)); + + SDL_Rect rect6 = { PANEL_LEFT + 449, (UI_OFFSET_Y + 427), 140, 35 }; + vecSelGameDialog.push_back(new UiArtTextButton("CANCEL", &UiFocusNavigationEsc, rect6, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)); + + UiInitList(0, 3, selgame_Speed_Focus, selgame_Speed_Select, selgame_Speed_Esc, vecSelGameDialog, true); +} + +void selgame_Speed_Focus(int value) +{ + switch (value) { + case 0: + strncpy(selgame_Label, "Normal", sizeof(selgame_Label) - 1); + strncpy(selgame_Description, "Normal Speed\nThis is where a starting character should begin the quest to defeat Diablo.", sizeof(selgame_Description) - 1); + break; + case 1: + strncpy(selgame_Label, "Fast", sizeof(selgame_Label) - 1); + strncpy(selgame_Description, "Fast Speed\nThe denizens of the Labyrinth have been hastened and will prove to be a greater challenge. This is recommended for experienced characters only.", sizeof(selgame_Description) - 1); + break; + case 2: + strncpy(selgame_Label, "Faster", sizeof(selgame_Label) - 1); + strncpy(selgame_Description, "Faster Speed\nMost monsters of the dungeon will seek you out quicker than ever before. Only an experienced champion should try their luck at this speed.", sizeof(selgame_Description) - 1); + break; + case 3: + strncpy(selgame_Label, "Faster", sizeof(selgame_Label) - 1); + strncpy(selgame_Description, "Fastest Speed\nThe minions of the underworld will rush to attack with out hesitation. Only a true speed deamon should enter at this pace.", sizeof(selgame_Description) - 1); + break; + } + WordWrapArtStr(selgame_Description, DESCRIPTION_WIDTH); +} + +void selgame_Speed_Esc() +{ + selgame_GameSelection_Select(0); +} + +void selgame_Speed_Select(int value) +{ + gbTickRate = 20 + 10 * value; + + if (provider == SELCONN_LOOPBACK) { + selgame_Password_Select(0); + return; + } + + selgame_Password_Init(0); +} + void selgame_Password_Init(int value) { memset(&selgame_Password, 0, sizeof(selgame_Password)); @@ -330,6 +404,7 @@ void selgame_Password_Select(int value) _gamedata *info = m_client_info->initdata; info->bDiff = gbDifficulty; + info->bRate = gbTickRate; if (SNetCreateGame(NULL, selgame_Password, NULL, 0, (char *)info, sizeof(_gamedata), MAX_PLRS, NULL, NULL, gdwPlayerId)) { UiInitList_clear(); @@ -344,7 +419,10 @@ void selgame_Password_Select(int value) void selgame_Password_Esc() { - selgame_GameSelection_Select(selgame_selectedGame); + if (selgame_selectedGame == 1) + selgame_GameSelection_Select(1); + else + selgame_GameSpeedSelection(); } int UiSelectGame(int a1, _SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, diff --git a/SourceX/DiabloUI/selgame.h b/SourceX/DiabloUI/selgame.h index 715080ad1..25a6a3d29 100644 --- a/SourceX/DiabloUI/selgame.h +++ b/SourceX/DiabloUI/selgame.h @@ -11,6 +11,10 @@ void selgame_GameSelection_Esc(); void selgame_Diff_Focus(int value); void selgame_Diff_Select(int value); void selgame_Diff_Esc(); +void selgame_GameSpeedSelection(); +void selgame_Speed_Focus(int value); +void selgame_Speed_Select(int value); +void selgame_Speed_Esc(); void selgame_Password_Init(int value); void selgame_Password_Select(int value); void selgame_Password_Esc(); diff --git a/SourceX/storm/storm_net.cpp b/SourceX/storm/storm_net.cpp index 2585ba62d..6da6e1560 100644 --- a/SourceX/storm/storm_net.cpp +++ b/SourceX/storm/storm_net.cpp @@ -111,7 +111,7 @@ BOOL SNetCreateGame(const char *pszGameName, const char *pszGamePassword, const DWORD dwGameType, char *GameTemplateData, int GameTemplateSize, int playerCount, char *creatorName, char *a11, int *playerID) { - if (GameTemplateSize != 8) + if (GameTemplateSize != sizeof(_gamedata)) ABORT(); net::buffer_t game_init_info(GameTemplateData, GameTemplateData + GameTemplateSize); dvlnet_inst->setup_gameinfo(std::move(game_init_info)); diff --git a/structs.h b/structs.h index d345d2226..606158eb5 100644 --- a/structs.h +++ b/structs.h @@ -1213,6 +1213,7 @@ typedef struct DeadStruct { typedef struct _gamedata { int dwSeed; BYTE bDiff; + BYTE bRate; } _gamedata; typedef struct _uidefaultstats {