From d9faef58cb4c8d76b49a630af66b4e4e0ae7a73a Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 23 Mar 2023 22:17:26 -0700 Subject: [PATCH 01/31] Add game control for lossless video recording, set default keys for gc_screenshot, etc Renames gc_startgif to gc_startmovie. Default controls: - gc_screenshot - F8 - gc_startmovie - F9 - gc_startlossless - F10 Bumps PROFILEVER to 3, safely migrates existing profiles. --- src/g_input.c | 34 ++++++++++++---------- src/g_input.h | 3 +- src/k_profiles.c | 4 ++- src/menus/options-profiles-edit-controls.c | 9 ++++-- 4 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/g_input.c b/src/g_input.c index 5883cc36d..ecda7b3db 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -750,7 +750,8 @@ static const char *gamecontrolname[num_gamecontrols] = "teamtalk", "rankings", "screenshot", - "recordgif", + "startmovie", + "startlossless", }; #define NUMKEYNAMES (sizeof (keynames)/sizeof (keyname_t)) @@ -889,20 +890,23 @@ void G_DefineDefaultControls(void) { // These defaults are less bad than they used to be. // Keyboard controls - gamecontroldefault[gc_up ][0] = KEY_UPARROW; - gamecontroldefault[gc_down ][0] = KEY_DOWNARROW; - gamecontroldefault[gc_left ][0] = KEY_LEFTARROW; - gamecontroldefault[gc_right ][0] = KEY_RIGHTARROW; - gamecontroldefault[gc_a ][0] = 'f'; - gamecontroldefault[gc_b ][0] = 'a'; - gamecontroldefault[gc_c ][0] = 'v'; - gamecontroldefault[gc_x ][0] = 's'; - gamecontroldefault[gc_y ][0] = 'x'; - gamecontroldefault[gc_z ][0] = 'c'; - gamecontroldefault[gc_l ][0] = KEY_SPACE; - gamecontroldefault[gc_r ][0] = 'd'; - gamecontroldefault[gc_start ][0] = KEY_ESCAPE; - gamecontroldefault[gc_rankings][0] = KEY_TAB; + gamecontroldefault[gc_up ][0] = KEY_UPARROW; + gamecontroldefault[gc_down ][0] = KEY_DOWNARROW; + gamecontroldefault[gc_left ][0] = KEY_LEFTARROW; + gamecontroldefault[gc_right ][0] = KEY_RIGHTARROW; + gamecontroldefault[gc_a ][0] = 'f'; + gamecontroldefault[gc_b ][0] = 'a'; + gamecontroldefault[gc_c ][0] = 'v'; + gamecontroldefault[gc_x ][0] = 's'; + gamecontroldefault[gc_y ][0] = 'x'; + gamecontroldefault[gc_z ][0] = 'c'; + gamecontroldefault[gc_l ][0] = KEY_SPACE; + gamecontroldefault[gc_r ][0] = 'd'; + gamecontroldefault[gc_start ][0] = KEY_ESCAPE; + gamecontroldefault[gc_rankings ][0] = KEY_TAB; + gamecontroldefault[gc_screenshot ][0] = KEY_F8; + gamecontroldefault[gc_startmovie ][0] = KEY_F9; + gamecontroldefault[gc_startlossless][0] = KEY_F10; // Gamepad controls gamecontroldefault[gc_up ][1] = KEY_HAT1+0; // D-Pad Up diff --git a/src/g_input.h b/src/g_input.h index bd52d6ca4..9441a7ef1 100644 --- a/src/g_input.h +++ b/src/g_input.h @@ -84,7 +84,8 @@ typedef enum gc_teamtalk, gc_rankings, gc_screenshot, - gc_recordgif, + gc_startmovie, + gc_startlossless, num_gamecontrols, diff --git a/src/k_profiles.c b/src/k_profiles.c index d43253dfa..8f089b919 100644 --- a/src/k_profiles.c +++ b/src/k_profiles.c @@ -425,7 +425,9 @@ void PR_LoadProfiles(void) { #ifdef DEVELOP // Profile update 1-->2: Add gc_rankings. - if (j == gc_rankings && version < 2) + // Profile update 2-->3: Add gc_startlossless. + if ((j == gc_rankings && version < 2) || + (j == gc_startlossless && version < 3)) { for (k = 0; k < MAXINPUTMAPPING; k++) { diff --git a/src/menus/options-profiles-edit-controls.c b/src/menus/options-profiles-edit-controls.c index f3dd23871..5c1b24548 100644 --- a/src/menus/options-profiles-edit-controls.c +++ b/src/menus/options-profiles-edit-controls.c @@ -53,11 +53,14 @@ menuitem_t OPTIONS_ProfileControls[] = { {IT_HEADER, "OPTIONAL CONTROLS", "Take a screenshot, chat...", NULL, {NULL}, 0, 0}, - {IT_CONTROL, "SCREENSHOT", "Also usable with F8 on Keyboard.", + {IT_CONTROL, "SCREENSHOT", "Take a high resolution screenshot.", NULL, {.routine = M_ProfileSetControl}, gc_screenshot, 0}, - {IT_CONTROL, "GIF CAPTURE", "Also usable with F9 on Keyboard.", - NULL, {.routine = M_ProfileSetControl}, gc_recordgif, 0}, + {IT_CONTROL, "RECORD VIDEO", "Record a video with sound.", + NULL, {.routine = M_ProfileSetControl}, gc_startmovie, 0}, + + {IT_CONTROL, "RECORD LOSSLESS", "Record a pixel perfect GIF.", + NULL, {.routine = M_ProfileSetControl}, gc_startlossless, 0}, {IT_CONTROL, "OPEN CHAT", "Opens chatbox in online games.", NULL, {.routine = M_ProfileSetControl}, gc_talk, 0}, From 80421da5b3887836a7fd7be38d469f494565ab04 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 23 Mar 2023 22:20:24 -0700 Subject: [PATCH 02/31] Replace hardcoded keys for screenshot etc with bindable controls Renames M_ScreenshotResponder to M_ScreenshotTicker. No longer eats events. As a side effect, these controls cannot be used with the console open. --- src/d_clisrv.c | 2 ++ src/d_main.c | 4 ---- src/k_menu.h | 5 ++++- src/m_misc.cpp | 32 +++++++++----------------------- src/m_misc.h | 2 +- 5 files changed, 16 insertions(+), 29 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 4953f58f5..ad25a0d20 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -6755,6 +6755,8 @@ void NetUpdate(void) I_unlock_mutex(k_menu_mutex); #endif CON_Ticker(); + + M_ScreenshotTicker(); } FileSendTicker(); diff --git a/src/d_main.c b/src/d_main.c index 03df9b60d..9f5c15e5e 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -248,10 +248,6 @@ void D_ProcessEvents(void) HandleGamepadDeviceEvents(ev); - // Screenshots over everything so that they can be taken anywhere. - if (M_ScreenshotResponder(ev)) - continue; // ate the event - if (gameaction == ga_nothing && gamestate == GS_TITLESCREEN) { if (cht_Responder(ev)) diff --git a/src/k_menu.h b/src/k_menu.h index fa4b1e8ed..5a343f0f7 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -541,7 +541,10 @@ typedef enum MBT_Z = 1<<5, MBT_L = 1<<6, MBT_R = 1<<7, - MBT_START = 1<<8 + MBT_START = 1<<8, + MBT_SCREENSHOT = 1<<9, + MBT_STARTMOVIE = 1<<10, + MBT_STARTLOSSLESS = 1<<11, } menuButtonCode_t; struct menucmd_t diff --git a/src/m_misc.cpp b/src/m_misc.cpp index c6f23a056..f5b1594ba 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -1846,24 +1846,16 @@ failure: #endif } -boolean M_ScreenshotResponder(event_t *ev) +void M_ScreenshotTicker(void) { - INT32 ch = -1; - if (dedicated || ev->type != ev_keydown) - return false; + const UINT8 pid = 0; // TODO: should splitscreen players be allowed to use this too? - ch = ev->data1; - - if (ch >= NUMKEYS && menuactive) // If it's not a keyboard key, then don't allow it in the menus! - return false; - - switch (ch) + if (M_MenuButtonPressed(pid, MBT_SCREENSHOT)) { - case KEY_F8: M_ScreenShot(); - break; - - case KEY_F9: + } + else if (M_MenuButtonPressed(pid, MBT_STARTMOVIE)) + { if (moviemode) { M_StopMovie(); @@ -1872,9 +1864,9 @@ boolean M_ScreenshotResponder(event_t *ev) { M_StartMovie(MM_AVRECORDER); } - break; - - case KEY_F10: + } + else if (M_MenuButtonPressed(pid, MBT_STARTLOSSLESS)) + { if (moviemode) { M_StopMovie(); @@ -1883,13 +1875,7 @@ boolean M_ScreenshotResponder(event_t *ev) { M_StartMovie(static_cast(cv_lossless_recorder.value)); } - break; - - default: - return false; } - - return true; } void M_MinimapGenerate(void) diff --git a/src/m_misc.h b/src/m_misc.h index f11617612..b56f307a3 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -98,7 +98,7 @@ void M_ScreenShot(void); #ifdef HWRENDER void M_DoLegacyGLScreenShot(void); #endif -boolean M_ScreenshotResponder(event_t *ev); +void M_ScreenshotTicker(void); void M_MinimapGenerate(void); From 9ca196cb89d1ed25c5fabede00bdbc43e6de1346 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 23 Mar 2023 22:23:34 -0700 Subject: [PATCH 03/31] Reset input upon exiting bind menu While rebininding your controls: - Do not take a screenshot if you press whichever button it was bound to before - Try not to let a held button press buffer back into the controls menu --- src/menus/options-profiles-edit-controls.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/menus/options-profiles-edit-controls.c b/src/menus/options-profiles-edit-controls.c index 5c1b24548..9fded87e0 100644 --- a/src/menus/options-profiles-edit-controls.c +++ b/src/menus/options-profiles-edit-controls.c @@ -316,6 +316,10 @@ void M_MapProfileControl(event_t *ev) INT32 controln = currentMenu->menuitems[itemOn].mvar1; // gc_ UINT8 where = n; // By default, we'll save the bind where we're supposed to map. INT32 i; + INT32 *DeviceGameKeyDownArray = G_GetDeviceGameKeyDownArray(ev->device); + + if (!DeviceGameKeyDownArray) + return; //SetDeviceOnPress(); // Update player gamepad assignments @@ -413,6 +417,10 @@ void M_MapProfileControl(event_t *ev) // Set menu delay regardless of what we're doing to avoid stupid stuff. M_SetMenuDelay(0); + // Reset this input so (keyboard keys at least) are not + // buffered and caught by menucmd. + DeviceGameKeyDownArray[c] = 0; + // Check if this particular key (c) is already bound in any slot. // If that's the case, simply do nothing. for (i = 0; i < MAXINPUTMAPPING; i++) From e0f999fcd7a56f1b3f752f6f36f5c062fae3b6ca Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 23 Mar 2023 22:43:34 -0700 Subject: [PATCH 04/31] Ignore OS key repeats for game controls --- src/d_event.h | 2 +- src/g_input.c | 5 +++++ src/sdl/i_video.cpp | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/d_event.h b/src/d_event.h index 8b85eed6e..67bbc34fd 100644 --- a/src/d_event.h +++ b/src/d_event.h @@ -38,7 +38,7 @@ struct event_t { evtype_t type; INT32 data1; // keys / mouse/joystick buttons - INT32 data2; // mouse/joystick x move + INT32 data2; // mouse/joystick x move; key repeat INT32 data3; // mouse/joystick y move INT32 device; // which device ID it belongs to (controller ID) }; diff --git a/src/g_input.c b/src/g_input.c index ecda7b3db..0ea851dec 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -456,6 +456,11 @@ void G_MapEventsToControls(event_t *ev) case ev_keydown: if (ev->data1 < NUMINPUTS) { + if (ev->data2) // OS repeat? We handle that ourselves + { + break; + } + DeviceGameKeyDownArray[ev->data1] = JOYAXISRANGE; if (AutomaticControllerReassignmentIsAllowed(ev->device)) diff --git a/src/sdl/i_video.cpp b/src/sdl/i_video.cpp index 73c51315d..7fa82e058 100644 --- a/src/sdl/i_video.cpp +++ b/src/sdl/i_video.cpp @@ -571,6 +571,7 @@ static void Impl_HandleKeyboardEvent(SDL_KeyboardEvent evt, Uint32 type) return; } event.data1 = Impl_SDL_Scancode_To_Keycode(evt.keysym.scancode); + event.data2 = evt.repeat; if (event.data1) D_PostEvent(&event); } From 44bd11f95d8a9fc5e7f8fdcf845fafecb030b243 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 2 Apr 2023 20:24:08 +0100 Subject: [PATCH 05/31] Update new PROFILEVER to 4 to account for public/private key-related changes --- src/k_profiles.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_profiles.c b/src/k_profiles.c index 8f089b919..6c03847bd 100644 --- a/src/k_profiles.c +++ b/src/k_profiles.c @@ -425,9 +425,9 @@ void PR_LoadProfiles(void) { #ifdef DEVELOP // Profile update 1-->2: Add gc_rankings. - // Profile update 2-->3: Add gc_startlossless. + // Profile update 3-->4: Add gc_startlossless. if ((j == gc_rankings && version < 2) || - (j == gc_startlossless && version < 3)) + (j == gc_startlossless && version < 4)) { for (k = 0; k < MAXINPUTMAPPING; k++) { From ed3ed6f18986a9a1c9cc24f15e7dce889c1d5996 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 2 Apr 2023 20:29:06 +0100 Subject: [PATCH 06/31] M_UpdateMenuCMD: Enable access to screenshots/etc based on player inputs Returns early if any of these have been added this tic --- src/k_menufunc.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index fc16f606d..aabadff37 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -754,10 +754,18 @@ void M_UpdateMenuCMD(UINT8 i) menucmd[i].buttonsHeld = menucmd[i].buttons; menucmd[i].buttons = 0; - if (G_PlayerInputDown(i, gc_up, mp)) { menucmd[i].dpad_ud--; } + if (G_PlayerInputDown(i, gc_screenshot, mp)) { menucmd[i].buttons |= MBT_SCREENSHOT; } + if (G_PlayerInputDown(i, gc_startmovie, mp)) { menucmd[i].buttons |= MBT_STARTMOVIE; } + if (G_PlayerInputDown(i, gc_startlossless, mp)) { menucmd[i].buttons |= MBT_STARTLOSSLESS; } + + // Screenshot et al take priority + if (menucmd[i].buttons != 0) + return; + + if (G_PlayerInputDown(i, gc_up, mp)) { menucmd[i].dpad_ud--; } if (G_PlayerInputDown(i, gc_down, mp)) { menucmd[i].dpad_ud++; } - if (G_PlayerInputDown(i, gc_left, mp)) { menucmd[i].dpad_lr--; } + if (G_PlayerInputDown(i, gc_left, mp)) { menucmd[i].dpad_lr--; } if (G_PlayerInputDown(i, gc_right, mp)) { menucmd[i].dpad_lr++; } if (G_PlayerInputDown(i, gc_a, mp)) { menucmd[i].buttons |= MBT_A; } @@ -768,6 +776,7 @@ void M_UpdateMenuCMD(UINT8 i) if (G_PlayerInputDown(i, gc_z, mp)) { menucmd[i].buttons |= MBT_Z; } if (G_PlayerInputDown(i, gc_l, mp)) { menucmd[i].buttons |= MBT_L; } if (G_PlayerInputDown(i, gc_r, mp)) { menucmd[i].buttons |= MBT_R; } + if (G_PlayerInputDown(i, gc_start, mp)) { menucmd[i].buttons |= MBT_START; } if (menucmd[i].dpad_ud == 0 && menucmd[i].dpad_lr == 0 && menucmd[i].buttons == 0) From 2d175c609409c6b6d7d38c5902f25c5e8cf5c9a9 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 2 Apr 2023 20:39:38 +0100 Subject: [PATCH 07/31] Permit tertiary and ... quadridly(?) gamecontrol binds for console open/close, which had been silently broken for years. --- src/console.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/console.c b/src/console.c index aac5c2c5f..6571b9f2a 100644 --- a/src/console.c +++ b/src/console.c @@ -913,7 +913,8 @@ boolean CON_Responder(event_t *ev) // let go keyup events, don't eat them if (ev->type != ev_keydown && ev->type != ev_console) { - if (ev->data1 == gamecontrol[0][gc_console][0] || ev->data1 == gamecontrol[0][gc_console][1]) + if (ev->data1 == gamecontrol[0][gc_console][0] || ev->data1 == gamecontrol[0][gc_console][1] + || ev->data1 == gamecontrol[0][gc_console][2] || ev->data1 == gamecontrol[0][gc_console][3]) consdown = false; return false; } @@ -933,7 +934,8 @@ boolean CON_Responder(event_t *ev) INT32 i; for (i = 0; i < num_gamecontrols; i++) { - if (gamecontrol[0][i][0] == ev->data1 || gamecontrol[0][i][1] == ev->data1) + if (gamecontrol[0][i][0] == ev->data1 || gamecontrol[0][i][1] == ev->data1 + || gamecontrol[0][i][2] == ev->data1 || gamecontrol[0][i][3] == ev->data1) break; } @@ -941,7 +943,8 @@ boolean CON_Responder(event_t *ev) return false; } - if (key == gamecontrol[0][gc_console][0] || key == gamecontrol[0][gc_console][1]) + if (key == gamecontrol[0][gc_console][0] || key == gamecontrol[0][gc_console][1] + || key == gamecontrol[0][gc_console][2] || key == gamecontrol[0][gc_console][3]) { if (consdown) // ignore repeat return true; From 04f371bbb448aaa9ce598dea7b27330a739d868b Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 2 Apr 2023 20:51:20 +0100 Subject: [PATCH 08/31] Also permit tertiary and ... quadridly(?) gamecontrol binds for chat open, which had been silently broken for years. --- src/hu_stuff.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 5a8069414..e5eb0aed9 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1215,7 +1215,8 @@ boolean HU_Responder(event_t *ev) if (!chat_on) { // enter chat mode - if ((ev->data1 == gamecontrol[0][gc_talk][0] || ev->data1 == gamecontrol[0][gc_talk][1]) + if ((ev->data1 == gamecontrol[0][gc_talk][0] || ev->data1 == gamecontrol[0][gc_talk][1] + || ev->data1 == gamecontrol[0][gc_talk][2] || ev->data1 == gamecontrol[0][gc_talk][3]) && netgame && !OLD_MUTE) // check for old chat mute, still let the players open the chat incase they want to scroll otherwise. { chat_on = true; @@ -1225,7 +1226,8 @@ boolean HU_Responder(event_t *ev) typelines = 1; return true; } - if ((ev->data1 == gamecontrol[0][gc_teamtalk][0] || ev->data1 == gamecontrol[0][gc_teamtalk][1]) + if ((ev->data1 == gamecontrol[0][gc_teamtalk][0] || ev->data1 == gamecontrol[0][gc_teamtalk][1] + || ev->data1 == gamecontrol[0][gc_teamtalk][2] || ev->data1 == gamecontrol[0][gc_teamtalk][3]) && netgame && !OLD_MUTE) { chat_on = true; From 5349b45a09c3c3e30a475f958764cb3638c37879 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 3 Apr 2023 00:20:31 +0100 Subject: [PATCH 09/31] Revert "Ignore OS key repeats for game controls" This reverts commit 2131973ecce45690bb82ddc80a2dee2107f8362f. --- src/d_event.h | 2 +- src/g_input.c | 5 ----- src/sdl/i_video.cpp | 1 - 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/d_event.h b/src/d_event.h index 67bbc34fd..8b85eed6e 100644 --- a/src/d_event.h +++ b/src/d_event.h @@ -38,7 +38,7 @@ struct event_t { evtype_t type; INT32 data1; // keys / mouse/joystick buttons - INT32 data2; // mouse/joystick x move; key repeat + INT32 data2; // mouse/joystick x move INT32 data3; // mouse/joystick y move INT32 device; // which device ID it belongs to (controller ID) }; diff --git a/src/g_input.c b/src/g_input.c index 0ea851dec..ecda7b3db 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -456,11 +456,6 @@ void G_MapEventsToControls(event_t *ev) case ev_keydown: if (ev->data1 < NUMINPUTS) { - if (ev->data2) // OS repeat? We handle that ourselves - { - break; - } - DeviceGameKeyDownArray[ev->data1] = JOYAXISRANGE; if (AutomaticControllerReassignmentIsAllowed(ev->device)) diff --git a/src/sdl/i_video.cpp b/src/sdl/i_video.cpp index 7fa82e058..73c51315d 100644 --- a/src/sdl/i_video.cpp +++ b/src/sdl/i_video.cpp @@ -571,7 +571,6 @@ static void Impl_HandleKeyboardEvent(SDL_KeyboardEvent evt, Uint32 type) return; } event.data1 = Impl_SDL_Scancode_To_Keycode(evt.keysym.scancode); - event.data2 = evt.repeat; if (event.data1) D_PostEvent(&event); } From 046ff491341c83dcc4aaba6cf2fa25d99c0f21e5 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 6 Apr 2023 20:09:42 +0100 Subject: [PATCH 10/31] Update PROFILEVER handling to account for Rumble support --- src/k_profiles.c | 4 ++-- src/k_profiles.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/k_profiles.c b/src/k_profiles.c index 6c03847bd..853306556 100644 --- a/src/k_profiles.c +++ b/src/k_profiles.c @@ -425,9 +425,9 @@ void PR_LoadProfiles(void) { #ifdef DEVELOP // Profile update 1-->2: Add gc_rankings. - // Profile update 3-->4: Add gc_startlossless. + // Profile update 3-->5: Add gc_startlossless. if ((j == gc_rankings && version < 2) || - (j == gc_startlossless && version < 4)) + (j == gc_startlossless && version < 5)) { for (k = 0; k < MAXINPUTMAPPING; k++) { diff --git a/src/k_profiles.h b/src/k_profiles.h index 06b880c42..2a866868f 100644 --- a/src/k_profiles.h +++ b/src/k_profiles.h @@ -31,7 +31,7 @@ extern "C" { #define SKINNAMESIZE 16 #define PROFILENAMELEN 6 -#define PROFILEVER 4 +#define PROFILEVER 5 #define MAXPROFILES 16 #define PROFILESFILE "ringprofiles.prf" #define PROFILE_GUEST 0 From 21a31c7a51bd774a200b4a38779f97cb82309430 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 8 Apr 2023 00:37:12 -0700 Subject: [PATCH 11/31] devmode: offset with showfps and showping --- src/st_stuff.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index 6c66d069d..9f4ff882f 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -446,15 +446,25 @@ void ST_drawDebugInfo(void) if (!stplyr->mo) return; + if (cv_ticrate.value) + { + height -= 20; + } + + if (cv_showping.value) + { + height -= 20; + } + if (cht_debug & DBG_BASIC) { const fixed_t d = AngleFixed(stplyr->mo->angle); - V_DrawRightAlignedString(320, 168, V_MONOSPACE, va("X: %6d", stplyr->mo->x>>FRACBITS)); - V_DrawRightAlignedString(320, 176, V_MONOSPACE, va("Y: %6d", stplyr->mo->y>>FRACBITS)); - V_DrawRightAlignedString(320, 184, V_MONOSPACE, va("Z: %6d", stplyr->mo->z>>FRACBITS)); - V_DrawRightAlignedString(320, 192, V_MONOSPACE, va("A: %6d", FixedInt(d))); + V_DrawRightAlignedString(320, height - 24, V_MONOSPACE, va("X: %6d", stplyr->mo->x>>FRACBITS)); + V_DrawRightAlignedString(320, height - 16, V_MONOSPACE, va("Y: %6d", stplyr->mo->y>>FRACBITS)); + V_DrawRightAlignedString(320, height - 8, V_MONOSPACE, va("Z: %6d", stplyr->mo->z>>FRACBITS)); + V_DrawRightAlignedString(320, height, V_MONOSPACE, va("A: %6d", FixedInt(d))); - height = 152; + height -= 40; } if (cht_debug & DBG_DETAILED) From 39ea73a4ada341c73736a09c96e18f45863cf8b0 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 8 Apr 2023 00:37:58 -0700 Subject: [PATCH 12/31] devmode render: display skybox portal, visplane and drawseg counts on HUD - Skybox portal count moved from console print to HUD - Displays visplane count and drawseg count --- src/r_main.c | 4 ++++ src/r_main.h | 9 +++++++++ src/r_plane.c | 3 +++ src/r_portal.c | 2 +- src/r_segs.c | 2 ++ src/st_stuff.c | 17 +++++++++++++++++ 6 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/r_main.c b/src/r_main.c index 4f07cb1c9..1b8fd6110 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -126,6 +126,8 @@ int ps_numsprites = 0; int ps_numdrawnodes = 0; int ps_numpolyobjects = 0; +struct RenderStats g_renderstats; + static CV_PossibleValue_t drawdist_cons_t[] = { /*{256, "256"},*/ {512, "512"}, {768, "768"}, {1024, "1024"}, {1536, "1536"}, {2048, "2048"}, @@ -1525,6 +1527,8 @@ void R_RenderPlayerView(void) framecount++; validcount++; + memset(&g_renderstats, 0, sizeof g_renderstats); + // Clear buffers. R_ClearPlanes(); if (viewmorph[viewssnum].use) diff --git a/src/r_main.h b/src/r_main.h index 786b1eaf6..567577f07 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -106,6 +106,15 @@ extern int ps_numsprites; extern int ps_numdrawnodes; extern int ps_numpolyobjects; +struct RenderStats +{ + size_t visplanes; + size_t drawsegs; + size_t skybox_portals; +}; + +extern struct RenderStats g_renderstats; + // // REFRESH - the actual rendering functions. // diff --git a/src/r_plane.c b/src/r_plane.c index be4ecd02d..57de53ea9 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -341,6 +341,9 @@ static visplane_t *new_visplane(unsigned hash) } check->next = visplanes[hash]; visplanes[hash] = check; + + g_renderstats.visplanes++; + return check; } diff --git a/src/r_portal.c b/src/r_portal.c index e66d4343c..86c727e1e 100644 --- a/src/r_portal.c +++ b/src/r_portal.c @@ -312,5 +312,5 @@ void Portal_AddSkyboxPortals (const player_t *player) } } - CONS_Debug(DBG_RENDER, "Skybox portals: %d\n", count); + g_renderstats.skybox_portals = count; } diff --git a/src/r_segs.c b/src/r_segs.c index 74800fb21..c4f41ba11 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -3024,4 +3024,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) ds_p->bsilheight = twosidedmidtexture ? INT32_MAX: INT32_MIN; } ds_p++; + + g_renderstats.drawsegs++; } diff --git a/src/st_stuff.c b/src/st_stuff.c index 9f4ff882f..5dde5c826 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -434,6 +434,18 @@ static void ST_drawMusicDebug(INT32 *height) } } +static void ST_drawRenderDebug(INT32 *height) +{ + const struct RenderStats *i = &g_renderstats; + + ST_pushDebugString(height, va(" Visplanes: %4s", sizeu1(i->visplanes))); + ST_pushDebugString(height, va(" Drawsegs: %4s", sizeu1(i->drawsegs))); + + ST_pushRow(height); + + ST_pushDebugString(height, va("Skybox Portals: %4s", sizeu1(i->skybox_portals))); +} + void ST_drawDebugInfo(void) { INT32 height = 192; @@ -516,6 +528,11 @@ void ST_drawDebugInfo(void) ST_drawMusicDebug(&height); } + if (cht_debug & DBG_RENDER) + { + ST_drawRenderDebug(&height); + } + if (cht_debug & DBG_MEMORY) V_DrawRightAlignedString(320, height, V_MONOSPACE, va("Heap used: %7sKB", sizeu1(Z_TagsUsage(0, INT32_MAX)>>10))); } From dc18fa745a881ae483b49daa18eba713a01bbcf4 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 8 Apr 2023 00:47:30 -0700 Subject: [PATCH 13/31] Overhaul teleport command, let it work in netgames Old syntax with -x, -y, -z, -ang, -aim parameters is simply replaced with 3 argument syntax like rteleport. Before - teleport -x 100 -y 50 -z 25 After - teleport 100 50 25 The lost angle, aiming and star post features can be added back in separate commands. --- src/d_netcmd.c | 24 ++++-- src/m_cheat.c | 216 ++----------------------------------------------- src/m_cheat.h | 1 + 3 files changed, 26 insertions(+), 215 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index bf9416ce9..1ab532025 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2032,6 +2032,7 @@ void D_Cheat(INT32 playernum, INT32 cheat, ...) break; case CHEAT_RELATIVE_TELEPORT: + case CHEAT_TELEPORT: COPY(WRITEFIXED, fixed_t); COPY(WRITEFIXED, fixed_t); COPY(WRITEFIXED, fixed_t); @@ -5699,7 +5700,8 @@ static void Got_Cheat(UINT8 **cp, INT32 playernum) break; } - case CHEAT_RELATIVE_TELEPORT: { + case CHEAT_RELATIVE_TELEPORT: + case CHEAT_TELEPORT: { fixed_t x = READFIXED(*cp); fixed_t y = READFIXED(*cp); fixed_t z = READFIXED(*cp); @@ -5714,10 +5716,17 @@ static void Got_Cheat(UINT8 **cp, INT32 playernum) if (!P_MobjWasRemoved(player->mo)) { P_MapStart(); - P_SetOrigin(player->mo, - player->mo->x + x, - player->mo->y + y, - player->mo->z + z); + if (cheat == CHEAT_RELATIVE_TELEPORT) + { + P_SetOrigin(player->mo, + player->mo->x + x, + player->mo->y + y, + player->mo->z + z); + } + else + { + P_SetOrigin(player->mo, x, y, z); + } P_MapEnd(); S_StartSound(player->mo, sfx_mixup); @@ -5727,7 +5736,10 @@ static void Got_Cheat(UINT8 **cp, INT32 playernum) strlcpy(t[1], M_Ftrim(f[1]), sizeof t[1]); strlcpy(t[2], M_Ftrim(f[2]), sizeof t[2]); - CV_CheaterWarning(targetPlayer, va("relative teleport by %d%s, %d%s, %d%s", + CV_CheaterWarning(targetPlayer, va("%s %d%s, %d%s, %d%s", + cheat == CHEAT_RELATIVE_TELEPORT + ? "relative teleport by" + : "teleport to", (int)f[0], t[0], (int)f[1], t[1], (int)f[2], t[2])); break; } diff --git a/src/m_cheat.c b/src/m_cheat.c index cbeefafb6..ac66a5c97 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -327,223 +327,21 @@ void Command_RTeleport_f(void) void Command_Teleport_f(void) { - fixed_t intx, inty, intz; - size_t i; - player_t *p = &players[consoleplayer]; - subsector_t *ss; + float x = atof(COM_Argv(1)); + float y = atof(COM_Argv(2)); + float z = atof(COM_Argv(3)); REQUIRE_CHEATS; REQUIRE_INLEVEL; - REQUIRE_SINGLEPLAYER; // TODO: make multiplayer compatible - if (COM_Argc() < 3 || COM_Argc() > 11) + if (COM_Argc() != 4) { - CONS_Printf(M_GetText("teleport -x -y -z -ang -aim : teleport to a location\nteleport -sp : teleport to specified checkpoint\n")); + CONS_Printf(M_GetText("teleport : teleport to a location\n")); return; } - if (!p->mo) - return; - - i = COM_CheckParm("-sp"); - if (i) - { - INT32 starpostnum = atoi(COM_Argv(i + 1)); // starpost number - INT32 starpostpath = atoi(COM_Argv(i + 2)); // quick, dirty way to distinguish between paths - - if (starpostnum < 0 || starpostpath < 0) - { - CONS_Alert(CONS_NOTICE, M_GetText("Negative starpost indexing is not valid.\n")); - return; - } - - if (!starpostnum) // spawnpoints... - { - mapthing_t *mt; - fixed_t offset; - - if (starpostpath >= numcoopstarts) - { - CONS_Alert(CONS_NOTICE, M_GetText("Player %d spawnpoint not found (%d max).\n"), starpostpath+1, numcoopstarts-1); - return; - } - - mt = playerstarts[starpostpath]; // Given above check, should never be NULL. - intx = mt->x<y<z<sector->ceilingheight - ss->sector->floorheight < p->mo->height) - { - CONS_Alert(CONS_NOTICE, M_GetText("Spawnpoint not in a valid location.\n")); - return; - } - - // Flagging a player's ambush will make them start on the ceiling - // Objectflip inverts - if (!!(mt->args[0]) ^ !!(mt->options & MTF_OBJECTFLIP)) - intz = ss->sector->ceilingheight - p->mo->height - offset; - else - intz = ss->sector->floorheight + offset; - - if (mt->options & MTF_OBJECTFLIP) // flip the player! - { - p->mo->eflags |= MFE_VERTICALFLIP; - p->mo->flags2 |= MF2_OBJECTFLIP; - } - else - { - p->mo->eflags &= ~MFE_VERTICALFLIP; - p->mo->flags2 &= ~MF2_OBJECTFLIP; - } - - p->mo->angle = p->drawangle = FixedAngle(mt->angle<mo->angle); - } - else // scan the thinkers to find starposts... - { - mobj_t *mo2 = NULL; - thinker_t *th; - - INT32 starpostmax = 0; - intz = starpostpath; // variable reuse - counting down for selection purposes - - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) - { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type != MT_STARPOST) - continue; - - if (mo2->health != starpostnum) - { - if (mo2->health > starpostmax) - starpostmax = mo2->health; - continue; - } - - if (intz--) - continue; - - break; - } - - if (th == &thlist[THINK_MOBJ]) - { - if (intz == starpostpath) - CONS_Alert(CONS_NOTICE, M_GetText("No starpost of position %d found (%d max).\n"), starpostnum, starpostmax); - else - CONS_Alert(CONS_NOTICE, M_GetText("Starpost of position %d, %d not found (%d, %d max).\n"), starpostnum, starpostpath, starpostmax, (starpostpath-intz)-1); - return; - } - - ss = R_PointInSubsectorOrNull(mo2->x, mo2->y); - if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height) - { - CONS_Alert(CONS_NOTICE, M_GetText("Starpost not in a valid location.\n")); - return; - } - - intx = mo2->x; - inty = mo2->y; - intz = mo2->z; - - if (mo2->flags2 & MF2_OBJECTFLIP) // flip the player! - { - p->mo->eflags |= MFE_VERTICALFLIP; - p->mo->flags2 |= MF2_OBJECTFLIP; - } - else - { - p->mo->eflags &= ~MFE_VERTICALFLIP; - p->mo->flags2 &= ~MF2_OBJECTFLIP; - } - - p->mo->angle = p->drawangle = mo2->angle; - P_SetPlayerAngle(p, p->mo->angle); - } - - CONS_Printf(M_GetText("Teleporting to checkpoint %d, %d...\n"), starpostnum, starpostpath); - } - else - { - i = COM_CheckParm("-nop"); // undocumented stupid addition to allow pivoting on the spot with -ang and -aim - if (i) - { - intx = p->mo->x; - inty = p->mo->y; - } - else - { - i = COM_CheckParm("-x"); - if (i) - intx = atoi(COM_Argv(i + 1))<sector->ceilingheight - ss->sector->floorheight < p->mo->height) - { - CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n")); - return; - } - i = COM_CheckParm("-z"); - if (i) - { - intz = atoi(COM_Argv(i + 1))<sector->floorheight) - intz = ss->sector->floorheight; - if (intz > ss->sector->ceilingheight - p->mo->height) - intz = ss->sector->ceilingheight - p->mo->height; - } - else - intz = ((p->mo->eflags & MFE_VERTICALFLIP) ? ss->sector->ceilingheight : ss->sector->floorheight); - - i = COM_CheckParm("-ang"); - if (i) - { - p->drawangle = p->mo->angle = FixedAngle(atoi(COM_Argv(i + 1))<mo->angle); - } - - i = COM_CheckParm("-aim"); - if (i) - { - angle_t aim = FixedAngle(atoi(COM_Argv(i + 1))<= ANGLE_90 && aim <= ANGLE_270) - { - CONS_Alert(CONS_NOTICE, M_GetText("Not a valid aiming angle (between +/-90).\n")); - return; - } - localaiming[0] = p->aiming = aim; - } - - CONS_Printf(M_GetText("Teleporting to %d, %d, %d...\n"), FixedInt(intx), FixedInt(inty), FixedInt(intz)); - } - - P_MapStart(); - if (!P_SetOrigin(p->mo, intx, inty, intz)) - CONS_Alert(CONS_WARNING, M_GetText("Unable to teleport to that spot!\n")); - else - S_StartSound(p->mo, sfx_mixup); - P_MapEnd(); + D_Cheat(consoleplayer, CHEAT_TELEPORT, + FLOAT_TO_FIXED(x), FLOAT_TO_FIXED(y), FLOAT_TO_FIXED(z)); } void Command_Skynum_f(void) diff --git a/src/m_cheat.h b/src/m_cheat.h index b272400fe..92e25243a 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -33,6 +33,7 @@ typedef enum { CHEAT_FLIP, CHEAT_HURT, CHEAT_RELATIVE_TELEPORT, + CHEAT_TELEPORT, CHEAT_DEVMODE, CHEAT_GIVEITEM, CHEAT_SCORE, From 5b2d791cf6d3eb748f0ce2a03ff6d60a426af01e Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 8 Apr 2023 01:01:17 -0700 Subject: [PATCH 14/31] Add goto command, teleport to a waypoint --- src/d_netcmd.c | 1 + src/m_cheat.c | 24 ++++++++++++++++++++++++ src/m_cheat.h | 1 + 3 files changed, 26 insertions(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 1ab532025..1c974fa7a 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1098,6 +1098,7 @@ void D_RegisterClientCommands(void) COM_AddCommand("skynum", Command_Skynum_f); COM_AddCommand("weather", Command_Weather_f); COM_AddCommand("grayscale", Command_Grayscale_f); + COM_AddCommand("goto", Command_Goto_f); CV_RegisterVar(&cv_renderhitbox); CV_RegisterVar(&cv_devmode_screen); diff --git a/src/m_cheat.c b/src/m_cheat.c index ac66a5c97..dff5d27c2 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -579,6 +579,30 @@ void Command_Grayscale_f(void) COM_ImmedExecute("toggle palette \"\" GRAYPAL"); } +void Command_Goto_f(void) +{ + const INT32 id = atoi(COM_Argv(1)); + const waypoint_t *wayp = K_GetWaypointFromID(id); + + REQUIRE_CHEATS; + REQUIRE_INLEVEL; + + if (COM_Argc() != 2) + { + CONS_Printf(M_GetText("goto : teleport to a waypoint\n")); + return; + } + + if (wayp == NULL) + { + CONS_Alert(CONS_WARNING, "goto %d: no waypoint with that ID\n", id); + return; + } + + D_Cheat(consoleplayer, CHEAT_TELEPORT, + wayp->mobj->x, wayp->mobj->y, wayp->mobj->z); +} + // // OBJECTPLACE (and related variables) // diff --git a/src/m_cheat.h b/src/m_cheat.h index 92e25243a..a7a1c020c 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -83,6 +83,7 @@ void Command_RTeleport_f(void); void Command_Skynum_f(void); void Command_Weather_f(void); void Command_Grayscale_f(void); +void Command_Goto_f(void); #ifdef _DEBUG void Command_CauseCfail_f(void); #endif From 05b0ecb5b60d1a5b62d5ab3df4d45641026a68a6 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 8 Apr 2023 01:19:44 -0700 Subject: [PATCH 15/31] Add angle command, set your angle precisely --- src/d_netcmd.c | 15 +++++++++++++++ src/m_cheat.c | 11 +++++++++++ src/m_cheat.h | 2 ++ 3 files changed, 28 insertions(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 1c974fa7a..a02242625 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1099,6 +1099,7 @@ void D_RegisterClientCommands(void) COM_AddCommand("weather", Command_Weather_f); COM_AddCommand("grayscale", Command_Grayscale_f); COM_AddCommand("goto", Command_Goto_f); + COM_AddCommand("angle", Command_Angle_f); CV_RegisterVar(&cv_renderhitbox); CV_RegisterVar(&cv_devmode_screen); @@ -2051,6 +2052,10 @@ void D_Cheat(INT32 playernum, INT32 cheat, ...) case CHEAT_SCORE: COPY(WRITEUINT32, UINT32); break; + + case CHEAT_ANGLE: + COPY(WRITEANGLE, angle_t); + break; } #undef COPY @@ -5790,6 +5795,16 @@ static void Got_Cheat(UINT8 **cp, INT32 playernum) break; } + case CHEAT_ANGLE: { + angle_t angle = READANGLE(*cp); + float anglef = FIXED_TO_FLOAT(AngleFixed(angle)); + + P_SetPlayerAngle(player, angle); + + CV_CheaterWarning(targetPlayer, va("angle = %d%s", (int)anglef, M_Ftrim(anglef))); + break; + } + case NUMBER_OF_CHEATS: break; } diff --git a/src/m_cheat.c b/src/m_cheat.c index dff5d27c2..d4e774f43 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -603,6 +603,17 @@ void Command_Goto_f(void) wayp->mobj->x, wayp->mobj->y, wayp->mobj->z); } +void Command_Angle_f(void) +{ + const float anglef = atof(COM_Argv(1)); + const angle_t angle = FixedAngle(FLOAT_TO_FIXED(anglef)); + + REQUIRE_CHEATS; + REQUIRE_INLEVEL; + + D_Cheat(consoleplayer, CHEAT_ANGLE, angle); +} + // // OBJECTPLACE (and related variables) // diff --git a/src/m_cheat.h b/src/m_cheat.h index a7a1c020c..d3c808d3e 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -37,6 +37,7 @@ typedef enum { CHEAT_DEVMODE, CHEAT_GIVEITEM, CHEAT_SCORE, + CHEAT_ANGLE, NUMBER_OF_CHEATS } cheat_t; @@ -84,6 +85,7 @@ void Command_Skynum_f(void); void Command_Weather_f(void); void Command_Grayscale_f(void); void Command_Goto_f(void); +void Command_Angle_f(void); #ifdef _DEBUG void Command_CauseCfail_f(void); #endif From f1ec39764f8ac897daec73961038c9190d20234b Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 3 Apr 2023 22:34:17 -0400 Subject: [PATCH 16/31] New voting screen background --- src/k_vote.c | 120 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 101 insertions(+), 19 deletions(-) diff --git a/src/k_vote.c b/src/k_vote.c index 0eefbacda..bf8fdb6ee 100644 --- a/src/k_vote.c +++ b/src/k_vote.c @@ -55,10 +55,6 @@ #include "hardware/hw_main.h" #endif -// graphics -static patch_t *bgpatch = NULL; // INTERSCR -static patch_t *widebgpatch = NULL; - static INT32 timer; #define UNLOAD(x) if (x) {Patch_Free(x);} x = NULL; @@ -105,6 +101,14 @@ static patch_t *cursor4 = NULL; static patch_t *randomlvl = NULL; static patch_t *rubyicon = NULL; +#define PLANET_FRAMES (9) +#define TEXT_LEVEL_SCROLL (2*FRACUNIT) +#define TEXT_DERR_SCROLL (2*FRACUNIT) +static patch_t *bg_planet[PLANET_FRAMES] = { NULL }; +static patch_t *bg_checker = NULL; +static patch_t *bg_levelText = NULL; +static patch_t *bg_derrText = NULL; + static void Y_UnloadVoteData(void); // @@ -112,6 +116,75 @@ static void Y_UnloadVoteData(void); // // Draws the voting screen! // +static void Y_DrawVoteBackground(void) +{ + static fixed_t bgTimer = 0; + + static fixed_t derrPos = 0; + const fixed_t derrLoop = bg_derrText->width * FRACUNIT; + + static fixed_t levelPos = 0; + const fixed_t levelLoop = bg_levelText->height * FRACUNIT; + + const UINT8 planetFrame = (bgTimer / FRACUNIT) % PLANET_FRAMES; + + V_DrawFixedPatch( + 0, 0, + FRACUNIT, 0, + bg_planet[planetFrame], NULL + ); + V_DrawFixedPatch( + (BASEVIDWIDTH - bg_checker->width) * FRACUNIT, 0, + FRACUNIT, V_ADD, + bg_checker, NULL + ); + V_DrawFixedPatch( + (BASEVIDWIDTH - bg_checker->width) * FRACUNIT, 0, + FRACUNIT, V_ADD, + bg_checker, NULL + ); + + levelPos += FixedMul(TEXT_DERR_SCROLL, renderdeltatics); + while (levelPos > levelLoop) + { + levelPos -= levelLoop; + } + + V_DrawFixedPatch( + ((BASEVIDWIDTH - bg_levelText->width) * FRACUNIT) - levelPos, + -levelPos, + FRACUNIT, V_ADD, + bg_levelText, NULL + ); + V_DrawFixedPatch( + ((BASEVIDWIDTH - bg_levelText->width) * FRACUNIT) - levelPos + levelLoop, + -levelPos + levelLoop, + FRACUNIT, V_ADD, + bg_levelText, NULL + ); + + derrPos += FixedMul(TEXT_DERR_SCROLL, renderdeltatics); + while (derrPos > derrLoop) + { + derrPos -= derrLoop; + } + + V_DrawFixedPatch( + -derrPos, + (BASEVIDHEIGHT - bg_derrText->height) * FRACUNIT, + FRACUNIT, V_SUBTRACT, + bg_derrText, NULL + ); + V_DrawFixedPatch( + -derrPos + derrLoop, + (BASEVIDHEIGHT - bg_derrText->height) * FRACUNIT, + FRACUNIT, V_SUBTRACT, + bg_derrText, NULL + ); + + bgTimer += renderdeltatics; +} + void Y_VoteDrawer(void) { INT32 i, x, y = 0, height = 0; @@ -138,16 +211,7 @@ void Y_VoteDrawer(void) rubyfloattime += FixedMul(ANGLE_MAX/NEWTICRATE, renderdeltatics); } - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); - - if (widebgpatch && rendermode == render_soft && vid.width / vid.dupx > 320) - V_DrawScaledPatch(((vid.width/2) / vid.dupx) - (SHORT(widebgpatch->width)/2), - (vid.height / vid.dupy) - SHORT(widebgpatch->height), - V_SNAPTOTOP|V_SNAPTOLEFT, widebgpatch); - else - V_DrawScaledPatch(((vid.width/2) / vid.dupx) - (SHORT(bgpatch->width)/2), // Keep the width/height adjustments, for screens that are less wide than 320(?) - (vid.height / vid.dupy) - SHORT(bgpatch->height), - V_SNAPTOTOP|V_SNAPTOLEFT, bgpatch); + Y_DrawVoteBackground(); for (i = 0; i < 4; i++) // First, we need to figure out the height of this thing... { @@ -395,6 +459,8 @@ void Y_VoteDrawer(void) V_DrawCenteredString(BASEVIDWIDTH/2, 188, V_YELLOWMAP, va("Vote ends in %d", tickdown)); } + + M_DrawMenuForeground(); } // @@ -659,7 +725,7 @@ void Y_VoteTicker(void) void Y_StartVote(void) { INT32 i = 0; - boolean battlemode = ((votelevels[0][1] & ~VOTEMODIFIER_ENCORE) == GT_BATTLE); // todo gametyperules + //boolean battlemode = ((votelevels[0][1] & ~VOTEMODIFIER_ENCORE) == GT_BATTLE); // todo gametyperules votetic = -1; @@ -668,8 +734,6 @@ void Y_StartVote(void) I_Error("voteendtic is dirty"); #endif - widebgpatch = W_CachePatchName((battlemode ? "BATTLSCW" : "INTERSCW"), PU_STATIC); - bgpatch = W_CachePatchName((battlemode ? "BATTLSCR" : "INTERSCR"), PU_STATIC); cursor = W_CachePatchName("M_CURSOR", PU_STATIC); cursor1 = W_CachePatchName("P1CURSOR", PU_STATIC); cursor2 = W_CachePatchName("P2CURSOR", PU_STATIC); @@ -678,6 +742,15 @@ void Y_StartVote(void) randomlvl = W_CachePatchName("RANDOMLV", PU_STATIC); rubyicon = W_CachePatchName("RUBYICON", PU_STATIC); + for (i = 0; i < PLANET_FRAMES; i++) + { + bg_planet[i] = W_CachePatchName(va("VT_BG_%d", i + 1), PU_STATIC); + } + + bg_checker = W_CachePatchName("VT_RACE", PU_STATIC); + bg_levelText = W_CachePatchName("VT_WELC", PU_STATIC); + bg_derrText = W_CachePatchName("VT_DERR", PU_STATIC); + timer = cv_votetime.value*TICRATE; pickedvote = -1; @@ -760,13 +833,13 @@ void Y_EndVote(void) // static void Y_UnloadVoteData(void) { + INT32 i; + voteclient.loaded = false; if (rendermode != render_soft) return; - UNLOAD(widebgpatch); - UNLOAD(bgpatch); UNLOAD(cursor); UNLOAD(cursor1); UNLOAD(cursor2); @@ -774,6 +847,15 @@ static void Y_UnloadVoteData(void) UNLOAD(cursor4); UNLOAD(randomlvl); UNLOAD(rubyicon); + + for (i = 0; i < PLANET_FRAMES; i++) + { + UNLOAD(bg_planet[i]); + } + + UNLOAD(bg_checker); + UNLOAD(bg_levelText); + UNLOAD(bg_derrText); } // From 8432d7e5529201b1aea695a8fe63c253b6ba792b Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 4 Apr 2023 01:49:12 -0400 Subject: [PATCH 17/31] Big vote screen cleanup - 4th map is now a regular option instead of dice. - Add function to draw a maintained Combi Catcher object on screen. - Put all vote static variables into either a "vote" struct or a "vote_draw" struct, if it's logic or drawing code. - Prefix netcode vote globals with _g. - Add enums/defines for vote magic numbers. --- src/d_netcmd.c | 130 +++---- src/doomstat.h | 12 +- src/g_game.c | 76 ++-- src/g_game.h | 3 +- src/k_vote.c | 987 +++++++++++++++++++++++++------------------------ src/k_vote.h | 5 + src/p_saveg.c | 18 +- 7 files changed, 620 insertions(+), 611 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index bf9416ce9..2e845fa8f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2615,30 +2615,18 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r void D_SetupVote(void) { - UINT8 buf[5*2]; // four UINT16 maps (at twice the width of a UINT8), and two gametypes + UINT8 buf[(VOTE_NUM_LEVELS * 2) + 2]; // four UINT16 maps (at twice the width of a UINT8), and two gametypes UINT8 *p = buf; INT32 i; - UINT8 secondgt = G_SometimesGetDifferentGametype(); - INT16 votebuffer[4] = {-1,-1,-1,0}; + INT16 votebuffer[VOTE_NUM_LEVELS] = {-1}; - if ((cv_kartencore.value == 1) && (gametyperules & GTR_ENCORE)) - WRITEUINT8(p, (gametype|VOTEMODIFIER_ENCORE)); - else - WRITEUINT8(p, gametype); - WRITEUINT8(p, secondgt); - secondgt &= ~VOTEMODIFIER_ENCORE; + WRITEUINT8(p, ((cv_kartencore.value == 1) && (gametyperules & GTR_ENCORE))); + WRITEUINT8(p, G_SometimesGetDifferentEncore()); - for (i = 0; i < 4; i++) + for (i = 0; i < VOTE_NUM_LEVELS; i++) { - UINT16 m; - if (i == 2) // sometimes a different gametype - m = G_RandMap(G_TOLFlag(secondgt), prevmap, ((secondgt != gametype) ? 2 : 0), 0, true, votebuffer); - else if (i >= 3) // Don't Care. Pick any of the available choices. - m = votebuffer[M_RandomRange(0, 2)]; - else - m = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, true, votebuffer); - if (i < 3) - votebuffer[i] = m; + UINT16 m = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, true, votebuffer); + votebuffer[i] = m; WRITEUINT16(p, m); } @@ -2672,13 +2660,13 @@ void D_PickVote(void) { if (!playeringame[i] || players[i].spectator) continue; - if (votes[i] != -1) + if (g_votes[i] != -1) { temppicks[numvotes] = i; - templevels[numvotes] = votes[i]; + templevels[numvotes] = g_votes[i]; numvotes++; if (votecompare == -1) - votecompare = votes[i]; + votecompare = g_votes[i]; } } @@ -5371,75 +5359,55 @@ static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum) static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) { + boolean baseEncore = false; + boolean optionalEncore = false; + INT16 tempVoteLevels[VOTE_NUM_LEVELS][2]; INT32 i; - UINT8 gt, secondgt; - INT16 tempvotelevels[4][2]; if (playernum != serverplayer) // admin shouldn't be able to set up vote... { CONS_Alert(CONS_WARNING, M_GetText("Illegal vote setup received from %s\n"), player_names[playernum]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); - return; - } - - gt = (UINT8)READUINT8(*cp); - secondgt = (UINT8)READUINT8(*cp); - - // Strip illegal Encore flag. - if ((gt & VOTEMODIFIER_ENCORE) - && !(gametypes[(gt & ~VOTEMODIFIER_ENCORE)]->rules & GTR_ENCORE)) - { - gt &= ~VOTEMODIFIER_ENCORE; - } - - if ((gt & ~VOTEMODIFIER_ENCORE) >= numgametypes) - { - gt &= ~VOTEMODIFIER_ENCORE; - if (server) - I_Error("Got_SetupVotecmd: Internal gametype ID %d not found (numgametypes = %d)", gt, numgametypes); - CONS_Alert(CONS_WARNING, M_GetText("Vote setup with bad gametype ID %d received from %s\n"), gt, player_names[playernum]); - return; - } - - if ((secondgt & ~VOTEMODIFIER_ENCORE) >= numgametypes) - { - secondgt &= ~VOTEMODIFIER_ENCORE; - if (server) - I_Error("Got_SetupVotecmd: Internal second gametype ID %d not found (numgametypes = %d)", secondgt, numgametypes); - CONS_Alert(CONS_WARNING, M_GetText("Vote setup with bad second gametype ID %d received from %s\n"), secondgt, player_names[playernum]); - return; - } - - for (i = 0; i < 4; i++) - { - tempvotelevels[i][0] = (UINT16)READUINT16(*cp); - tempvotelevels[i][1] = gt; - if (tempvotelevels[i][0] < nummapheaders && mapheaderinfo[tempvotelevels[i][0]]) - continue; - - if (server) - I_Error("Got_SetupVotecmd: Internal map ID %d not found (nummapheaders = %d)", tempvotelevels[i][0], nummapheaders); - CONS_Alert(CONS_WARNING, M_GetText("Vote setup with bad map ID %d received from %s\n"), tempvotelevels[i][0], player_names[playernum]); - return; - } - - // If third entry has an illelegal Encore flag... (illelegal!?) - if ((secondgt & VOTEMODIFIER_ENCORE) - && !(gametypes[(secondgt & ~VOTEMODIFIER_ENCORE)]->rules & GTR_ENCORE)) - { - secondgt &= ~VOTEMODIFIER_ENCORE; - // Apply it to the second entry instead, gametype permitting! - if (gametypes[gt]->rules & GTR_ENCORE) { - tempvotelevels[1][1] |= VOTEMODIFIER_ENCORE; + SendKick(playernum, KICK_MSG_CON_FAIL); } + return; } - // Finally, set third entry's gametype/Encore status. - tempvotelevels[2][1] = secondgt; + baseEncore = (boolean)READUINT8(*cp); + optionalEncore = (boolean)READUINT8(*cp); - memcpy(votelevels, tempvotelevels, sizeof(votelevels)); + if (!(gametyperules & GTR_ENCORE)) + { + // Strip illegal Encore flags. + baseEncore = optionalEncore = false; + } + + for (i = 0; i < VOTE_NUM_LEVELS; i++) + { + tempVoteLevels[i][0] = (UINT16)READUINT16(*cp); + tempVoteLevels[i][1] = (baseEncore == true) ? VOTE_MOD_ENCORE : 0; + + if (tempVoteLevels[i][0] < nummapheaders && mapheaderinfo[tempVoteLevels[i][0]]) + { + continue; + } + + if (server) + { + I_Error("Got_SetupVotecmd: Internal map ID %d not found (nummapheaders = %d)", tempVoteLevels[i][0], nummapheaders); + } + + CONS_Alert(CONS_WARNING, M_GetText("Vote setup with bad map ID %d received from %s\n"), tempVoteLevels[i][0], player_names[playernum]); + return; + } + + if (optionalEncore == true) + { + tempVoteLevels[VOTE_NUM_LEVELS - 1][1] ^= VOTE_MOD_ENCORE; + } + + memcpy(g_voteLevels, tempVoteLevels, sizeof(g_voteLevels)); G_SetGamestate(GS_VOTING); Y_StartVote(); @@ -5451,7 +5419,7 @@ static void Got_ModifyVotecmd(UINT8 **cp, INT32 playernum) UINT8 p = READUINT8(*cp); (void)playernum; - votes[p] = voted; + g_votes[p] = voted; } static void Got_PickVotecmd(UINT8 **cp, INT32 playernum) diff --git a/src/doomstat.h b/src/doomstat.h index 01f584dd4..fd74129dc 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -488,8 +488,8 @@ extern mapheader_t** mapheaderinfo; extern INT32 nummapheaders, mapallocsize; // Gametypes -#define NUMGAMETYPEFREESLOTS (MAXGAMETYPES-GT_FIRSTFREESLOT) -#define MAXGAMETYPELENGTH 32 +#define NUMGAMETYPEFREESLOTS (128) +#define MAXGAMETYPELENGTH (32) enum GameType { @@ -500,7 +500,7 @@ enum GameType GT_TUTORIAL, GT_FIRSTFREESLOT, - GT_LASTFREESLOT = 127, // Previously (GT_FIRSTFREESLOT + NUMGAMETYPEFREESLOTS - 1) - it would be necessary to rewrite VOTEMODIFIER_ENCORE to go higher than this. + GT_LASTFREESLOT = GT_FIRSTFREESLOT + NUMGAMETYPEFREESLOTS - 1, MAXGAMETYPES }; // If you alter this list, update defaultgametypes and *gametypes in g_game.c @@ -732,9 +732,9 @@ extern boolean legitimateexit; extern boolean comebackshowninfo; extern tic_t curlap, bestlap; -extern INT16 votelevels[4][2]; -extern SINT8 votes[MAXPLAYERS]; -extern SINT8 pickedvote; +extern INT16 g_voteLevels[4][2]; +extern SINT8 g_votes[MAXPLAYERS]; +extern SINT8 g_pickedVote; // =========================== // Internal parameters, fixed. diff --git a/src/g_game.c b/src/g_game.c index 72d4663f6..02c3cc682 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -298,9 +298,9 @@ boolean prevencoremode; boolean franticitems; // Frantic items currently enabled? // Voting system -INT16 votelevels[4][2]; // Levels that were rolled by the host -SINT8 votes[MAXPLAYERS]; // Each player's vote -SINT8 pickedvote; // What vote the host rolls +INT16 g_voteLevels[4][2]; // Levels that were rolled by the host +SINT8 g_votes[MAXPLAYERS]; // Each player's vote +SINT8 g_pickedVote; // What vote the host rolls // Server-sided, synched variables tic_t wantedcalcdelay; // Time before it recalculates WANTED @@ -3627,32 +3627,28 @@ boolean G_GametypeHasSpectators(void) } // -// G_SometimesGetDifferentGametype +// G_SometimesGetDifferentEncore // // Because gametypes are no longer on the vote screen, all this does is sometimes flip encore mode. // However, it remains a seperate function for long-term possibility. // -INT16 G_SometimesGetDifferentGametype(void) +INT16 G_SometimesGetDifferentEncore(void) { boolean encorepossible = ((M_SecretUnlocked(SECRET_ENCORE, false) || encorescramble == 1) && (gametyperules & GTR_ENCORE)); UINT8 encoremodifier = 0; - // -- the below is only necessary if you want to use randmaps.mapbuffer here - //if (randmaps.lastnummapheaders != nummapheaders) - //G_ResetRandMapBuffer(); - // FORCE to what was scrambled on intermission? if (encorepossible && encorescramble != -1) { // FORCE to what was scrambled on intermission if ((encorescramble != 0) != (cv_kartencore.value == 1)) { - encoremodifier = VOTEMODIFIER_ENCORE; + encoremodifier = VOTE_MOD_ENCORE; } } - return (gametype|encoremodifier); + return encoremodifier; } /** Get the typeoflevel flag needed to indicate support of a gametype. @@ -3736,10 +3732,11 @@ INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, UINT8 ignorebuffer, UINT8 maphe UINT32 numokmaps = 0; INT16 ix, bufx; UINT16 extbufsize = 0; - boolean usehellmaps; // Only consider Hell maps in this pick if (randmaps.lastnummapheaders != nummapheaders) + { G_ResetRandMapBuffer(); + } if (!okmaps) { @@ -3750,33 +3747,39 @@ INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, UINT8 ignorebuffer, UINT8 maphe if (extbuffer != NULL) { bufx = 0; + while (extbuffer[bufx]) { - extbufsize++; bufx++; + extbufsize++; + bufx++; } } tryagain: - usehellmaps = (maphell == 0 ? false : (maphell == 2 || M_RandomChance(FRACUNIT/100))); // 1% chance of Hell - // Find all the maps that are ok and and put them in an array. for (ix = 0; ix < nummapheaders; ix++) { boolean isokmap = true; if (!mapheaderinfo[ix] || mapheaderinfo[ix]->lumpnum == LUMPERROR) + { continue; + } if (!(mapheaderinfo[ix]->typeoflevel & tolflags) || ix == pprevmap || M_MapLocked(ix+1) - || (usehellmaps != (mapheaderinfo[ix]->menuflags & LF2_HIDEINMENU))) // this is bad + || (mapheaderinfo[ix]->menuflags & LF2_HIDEINMENU)) // this is bad + { continue; //isokmap = false; + } if (pprevmap == -2 // title demo hack && mapheaderinfo[ix]->ghostCount == 0) + { continue; + } if (!ignorebuffer) { @@ -3785,7 +3788,10 @@ tryagain: for (bufx = 0; bufx < extbufsize; bufx++) { if (extbuffer[bufx] == -1) // Rest of buffer SHOULD be empty + { break; + } + if (ix == extbuffer[bufx]) { isokmap = false; @@ -3794,13 +3800,18 @@ tryagain: } if (!isokmap) + { continue; + } } for (bufx = 0; bufx < (maphell ? 3 : randmaps.lastnummapheaders); bufx++) { if (randmaps.mapbuffer[bufx] == -1) // Rest of buffer SHOULD be empty + { break; + } + if (ix == randmaps.mapbuffer[bufx]) { isokmap = false; @@ -3819,33 +3830,32 @@ tryagain: { if (!ignorebuffer) { - if (randmaps.mapbuffer[3] == -1) // Is the buffer basically empty? + if (randmaps.mapbuffer[VOTE_NUM_LEVELS] == -1) // Is the buffer basically empty? { ignorebuffer = 1; // This will probably only help in situations where there's very few maps, but it's folly not to at least try it //CONS_Printf("RANDMAP - ignoring buffer\n"); goto tryagain; } - for (bufx = 3; bufx < randmaps.lastnummapheaders; bufx++) // Let's clear all but the three most recent maps... + for (bufx = VOTE_NUM_LEVELS; bufx < randmaps.lastnummapheaders; bufx++) // Let's clear all but the three most recent maps... + { randmaps.mapbuffer[bufx] = -1; - //CONS_Printf("RANDMAP - emptying randmapbuffer\n"); - goto tryagain; - } + } - if (maphell) // Any wiggle room to loosen our restrictions here? - { - //CONS_Printf("RANDMAP -maphell decrement\n"); - maphell--; + //CONS_Printf("RANDMAP - emptying randmapbuffer\n"); goto tryagain; } //CONS_Printf("RANDMAP - defaulting to map01\n"); ix = 0; // Sorry, none match. You get MAP01. + if (ignorebuffer == 1) { //CONS_Printf("(emptying randmapbuffer entirely)\n"); for (bufx = 0; bufx < randmaps.lastnummapheaders; bufx++) + { randmaps.mapbuffer[bufx] = -1; // if we're having trouble finding a map we should probably clear it + } } } else @@ -3867,10 +3877,12 @@ tryagain: void G_AddMapToBuffer(INT16 map) { INT16 bufx; - INT16 refreshnum = (TOLMaps(gametype))-3; + INT16 refreshnum = (TOLMaps(gametype)) - VOTE_NUM_LEVELS; if (refreshnum < 0) - refreshnum = 3; + { + refreshnum = 0; + } if (nummapheaders != randmaps.lastnummapheaders) { @@ -3878,8 +3890,10 @@ void G_AddMapToBuffer(INT16 map) } else { - for (bufx = randmaps.lastnummapheaders-1; bufx > 0; bufx--) + for (bufx = randmaps.lastnummapheaders - 1; bufx > 0; bufx--) + { randmaps.mapbuffer[bufx] = randmaps.mapbuffer[bufx-1]; + } } randmaps.mapbuffer[0] = map; @@ -3887,9 +3901,11 @@ void G_AddMapToBuffer(INT16 map) // We're getting pretty full, so lets flush this for future usage. if (randmaps.mapbuffer[refreshnum] != -1) { - // Clear all but the five most recent maps. - for (bufx = 5; bufx < randmaps.lastnummapheaders; bufx++) + // Clear all but the most recent maps. + for (bufx = VOTE_NUM_LEVELS; bufx < randmaps.lastnummapheaders; bufx++) + { randmaps.mapbuffer[bufx] = -1; + } //CONS_Printf("Random map buffer has been flushed.\n"); } } diff --git a/src/g_game.h b/src/g_game.h index 41a22a6c5..90c19f440 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -182,8 +182,7 @@ INT32 G_GuessGametypeByTOL(UINT32 tol); boolean G_GametypeUsesLives(void); boolean G_GametypeHasTeams(void); boolean G_GametypeHasSpectators(void); -#define VOTEMODIFIER_ENCORE 0x80 -INT16 G_SometimesGetDifferentGametype(void); +INT16 G_SometimesGetDifferentEncore(void); void G_ExitLevel(void); void G_NextLevel(void); void G_Continue(void); diff --git a/src/k_vote.c b/src/k_vote.c index bf8fdb6ee..58cab978a 100644 --- a/src/k_vote.c +++ b/src/k_vote.c @@ -50,66 +50,147 @@ #include "k_boss.h" #include "k_pwrlv.h" #include "k_grandprix.h" +#include "k_color.h" #ifdef HWRENDER #include "hardware/hw_main.h" #endif -static INT32 timer; - #define UNLOAD(x) if (x) {Patch_Free(x);} x = NULL; #define CLEANUP(x) x = NULL; -// SRB2Kart: voting stuff -// Level images +#define PLANET_FRAMES (9) +#define TEXT_LEVEL_SCROLL (2*FRACUNIT) +#define TEXT_DERR_SCROLL (2*FRACUNIT) + +#define ARM_FRAMES (4) +#define BULB_FRAMES (4) + +// Catcher data typedef struct { - char str[62]; - UINT8 gtc; - const char *gts; - boolean encore; -} y_votelvlinfo; + fixed_t x, y; + UINT8 spr; + boolean small; +} y_vote_catcher; // Clientside & splitscreen player info. typedef struct { + y_vote_catcher catcher; SINT8 selection; UINT8 delay; -} y_voteplayer; +} y_vote_player; typedef struct { - y_voteplayer playerinfo[4]; + INT32 timer; + INT32 tic, endtic; + boolean notYetPicked; + boolean loaded; + + y_vote_player players[MAXSPLITSCREENPLAYERS]; UINT8 ranim; UINT8 rtics; UINT8 roffset; UINT8 rsynctime; UINT8 rendoff; - boolean loaded; -} y_voteclient; -static y_votelvlinfo levelinfo[5]; -static y_voteclient voteclient; -static INT32 votetic; -static INT32 voteendtic = -1; -static boolean votenotyetpicked; -static patch_t *cursor = NULL; -static patch_t *cursor1 = NULL; -static patch_t *cursor2 = NULL; -static patch_t *cursor3 = NULL; -static patch_t *cursor4 = NULL; -static patch_t *randomlvl = NULL; -static patch_t *rubyicon = NULL; + SINT8 deferredLevel; +} y_vote_data; -#define PLANET_FRAMES (9) -#define TEXT_LEVEL_SCROLL (2*FRACUNIT) -#define TEXT_DERR_SCROLL (2*FRACUNIT) -static patch_t *bg_planet[PLANET_FRAMES] = { NULL }; -static patch_t *bg_checker = NULL; -static patch_t *bg_levelText = NULL; -static patch_t *bg_derrText = NULL; +typedef struct +{ + char str[62]; + boolean encore; + fixed_t hop; +} y_vote_draw_level; -static void Y_UnloadVoteData(void); +typedef struct +{ + patch_t *ruby_icon; + patch_t *bg_planet[PLANET_FRAMES]; + patch_t *bg_checker; + patch_t *bg_levelText; + patch_t *bg_derrText; + patch_t *catcher_ufo; + patch_t *catcher_arms[ARM_FRAMES]; + patch_t *catcher_pole; + patch_t *catcher_bulb[BULB_FRAMES]; + y_vote_draw_level levels[VOTE_NUM_LEVELS]; +} y_vote_draw; + +static y_vote_data vote = {0}; +static y_vote_draw vote_draw = {0}; + +static boolean Y_PlayerIDCanVote(const UINT8 id) +{ + if (id >= MAXPLAYERS) + { + return false; + } + + if (playeringame[id] == false || players[id].spectator == true) + { + return false; + } + + if (players[id].bot == true) + { + return false; + } + + return true; +} + +static void Y_DrawCatcher(y_vote_catcher *catcher) +{ +#define NUM_BULB_COLORS (2) + static const skincolornum_t bulbColors[NUM_BULB_COLORS] = { + SKINCOLOR_JAWZ, + SKINCOLOR_LILAC, + }; + + const tic_t anim = gametic / 3; // Using gametic for this is probably a bit goofy + + fixed_t x = catcher->x - (vote_draw.catcher_ufo->width * FRACUNIT / 2); + fixed_t y = catcher->y - (vote_draw.catcher_ufo->height * FRACUNIT * 7 / 8); + + UINT8 *craneColor = NULL; + UINT8 *bulbColor = NULL; + + craneColor = R_GetTranslationColormap(TC_DEFAULT, K_RainbowColor(anim), GTC_MENUCACHE); + bulbColor = R_GetTranslationColormap(TC_DEFAULT, bulbColors[(anim / BULB_FRAMES) % NUM_BULB_COLORS], GTC_MENUCACHE); + + V_DrawFixedPatch( + x, y, + FRACUNIT, 0, + vote_draw.catcher_arms[catcher->spr % ARM_FRAMES], + craneColor + ); + + V_DrawFixedPatch( + x, y, + FRACUNIT, 0, + vote_draw.catcher_bulb[anim % BULB_FRAMES], + bulbColor + ); + + V_DrawFixedPatch( + x, y, + FRACUNIT, 0, + vote_draw.catcher_ufo, + craneColor + ); + + V_DrawFixedPatch( + x, y, + FRACUNIT, 0, + vote_draw.catcher_pole, + NULL + ); +#undef NUM_BULB_COLORS +} // // Y_VoteDrawer @@ -121,27 +202,27 @@ static void Y_DrawVoteBackground(void) static fixed_t bgTimer = 0; static fixed_t derrPos = 0; - const fixed_t derrLoop = bg_derrText->width * FRACUNIT; + const fixed_t derrLoop = vote_draw.bg_derrText->width * FRACUNIT; static fixed_t levelPos = 0; - const fixed_t levelLoop = bg_levelText->height * FRACUNIT; + const fixed_t levelLoop = vote_draw.bg_levelText->height * FRACUNIT; const UINT8 planetFrame = (bgTimer / FRACUNIT) % PLANET_FRAMES; V_DrawFixedPatch( 0, 0, FRACUNIT, 0, - bg_planet[planetFrame], NULL + vote_draw.bg_planet[planetFrame], NULL ); V_DrawFixedPatch( - (BASEVIDWIDTH - bg_checker->width) * FRACUNIT, 0, + (BASEVIDWIDTH - vote_draw.bg_checker->width) * FRACUNIT, 0, FRACUNIT, V_ADD, - bg_checker, NULL + vote_draw.bg_checker, NULL ); V_DrawFixedPatch( - (BASEVIDWIDTH - bg_checker->width) * FRACUNIT, 0, + (BASEVIDWIDTH - vote_draw.bg_checker->width) * FRACUNIT, 0, FRACUNIT, V_ADD, - bg_checker, NULL + vote_draw.bg_checker, NULL ); levelPos += FixedMul(TEXT_DERR_SCROLL, renderdeltatics); @@ -151,16 +232,16 @@ static void Y_DrawVoteBackground(void) } V_DrawFixedPatch( - ((BASEVIDWIDTH - bg_levelText->width) * FRACUNIT) - levelPos, + ((BASEVIDWIDTH - vote_draw.bg_levelText->width) * FRACUNIT) - levelPos, -levelPos, FRACUNIT, V_ADD, - bg_levelText, NULL + vote_draw.bg_levelText, NULL ); V_DrawFixedPatch( - ((BASEVIDWIDTH - bg_levelText->width) * FRACUNIT) - levelPos + levelLoop, + ((BASEVIDWIDTH - vote_draw.bg_levelText->width) * FRACUNIT) - levelPos + levelLoop, -levelPos + levelLoop, FRACUNIT, V_ADD, - bg_levelText, NULL + vote_draw.bg_levelText, NULL ); derrPos += FixedMul(TEXT_DERR_SCROLL, renderdeltatics); @@ -171,15 +252,15 @@ static void Y_DrawVoteBackground(void) V_DrawFixedPatch( -derrPos, - (BASEVIDHEIGHT - bg_derrText->height) * FRACUNIT, + (BASEVIDHEIGHT - vote_draw.bg_derrText->height) * FRACUNIT, FRACUNIT, V_SUBTRACT, - bg_derrText, NULL + vote_draw.bg_derrText, NULL ); V_DrawFixedPatch( -derrPos + derrLoop, - (BASEVIDHEIGHT - bg_derrText->height) * FRACUNIT, + (BASEVIDHEIGHT - vote_draw.bg_derrText->height) * FRACUNIT, FRACUNIT, V_SUBTRACT, - bg_derrText, NULL + vote_draw.bg_derrText, NULL ); bgTimer += renderdeltatics; @@ -187,200 +268,116 @@ static void Y_DrawVoteBackground(void) void Y_VoteDrawer(void) { - INT32 i, x, y = 0, height = 0; - UINT8 selected[4]; - fixed_t rubyheight = 0; + fixed_t x, y; + fixed_t rubyHeight = 0; + INT32 i, j; // If we early return, skip drawing the 3D scene (software buffer) so it doesn't clobber the frame for the wipe g_wipeskiprender = true; if (rendermode == render_none) + { return; + } - if (votetic >= voteendtic && voteendtic != -1) + if (vote.tic >= vote.endtic && vote.endtic != -1) + { return; + } - if (!voteclient.loaded) + if (vote.loaded == false) + { return; + } g_wipeskiprender = false; { - static angle_t rubyfloattime = 0; - rubyheight = FINESINE(rubyfloattime>>ANGLETOFINESHIFT); - rubyfloattime += FixedMul(ANGLE_MAX/NEWTICRATE, renderdeltatics); + static angle_t rubyFloatTime = 0; + rubyHeight = FINESINE(rubyFloatTime >> ANGLETOFINESHIFT); + rubyFloatTime += FixedMul(ANGLE_MAX / NEWTICRATE, renderdeltatics); } Y_DrawVoteBackground(); - for (i = 0; i < 4; i++) // First, we need to figure out the height of this thing... - { - UINT8 j; - selected[i] = 0; // Initialize + x = 10 * FRACUNIT; + y = 144 * FRACUNIT; - for (j = 0; j <= splitscreen; j++) + for (i = 0; i < VOTE_NUM_LEVELS; i++) + { + boolean selected = false; + INT32 flags = 0; + fixed_t destHop = 0; + + for (j = 0; j <= splitscreen; j++) // another loop for drawing the selection backgrounds in the right order, grumble grumble.. { - if (voteclient.playerinfo[j].selection == i) - selected[i]++; + const UINT8 p = g_localplayers[j]; + + if (vote.players[j].selection != i) + { + continue; + } + + if (g_votes[p] != VOTE_NOT_PICKED || Y_PlayerIDCanVote(p) == false) + { + continue; + } + + selected = true; + break; } - if (selected[i]) - height += 50; - else - height += 25; - - if (i < 3) - height += 5-splitscreen; - } - - y = (200-height)/2; - for (i = 0; i < 4; i++) - { - UINT8 j, color; - - if (selected[i]) + if (selected == true) { - const char *str; - UINT8 sizeadd = selected[i]; - - for (j = 0; j <= splitscreen; j++) // another loop for drawing the selection backgrounds in the right order, grumble grumble.. - { - INT32 handy = y; - UINT8 p; - UINT8 *colormap; - patch_t *thiscurs; - - if (voteclient.playerinfo[j].selection != i) - continue; - - if (!splitscreen) - { - thiscurs = cursor; - p = consoleplayer; - color = levelinfo[i].gtc; - colormap = NULL; - } - else - { - switch (j) - { - case 1: - thiscurs = cursor2; - p = g_localplayers[1]; - break; - case 2: - thiscurs = cursor3; - p = g_localplayers[2]; - break; - case 3: - thiscurs = cursor4; - p = g_localplayers[3]; - break; - default: - thiscurs = cursor1; - p = g_localplayers[0]; - break; - } - - color = skincolors[players[p].skincolor].ramp[7]; - colormap = R_GetTranslationColormap(TC_DEFAULT, players[p].skincolor, GTC_CACHE); - } - - if (votes[p] != -1 || players[p].spectator) - continue; - - handy += 6*(3-splitscreen) + (13*j); - V_DrawMappedPatch(BASEVIDWIDTH-124, handy, V_SNAPTORIGHT, thiscurs, colormap); - - if (votetic % 10 < 4) - V_DrawFill(BASEVIDWIDTH-100-sizeadd, y-sizeadd, 80+(sizeadd*2), 50+(sizeadd*2), 0|V_SNAPTORIGHT); - else - V_DrawFill(BASEVIDWIDTH-100-sizeadd, y-sizeadd, 80+(sizeadd*2), 50+(sizeadd*2), color|V_SNAPTORIGHT); - - sizeadd--; - } - - if (i == 3) - { - str = "RANDOM"; - K_DrawLikeMapThumbnail( - (BASEVIDWIDTH-100)<= 3 && (i != pickedvote || voteendtic == -1)) - { - K_DrawLikeMapThumbnail( - (x)< 0) { - INT32 tickdown = (timer+1)/TICRATE; - V_DrawCenteredString(BASEVIDWIDTH/2, 188, V_YELLOWMAP, - va("Vote ends in %d", tickdown)); + const INT32 tickDown = (vote.timer + 1) / TICRATE; + + V_DrawCenteredString( + BASEVIDWIDTH/2, 188, + V_YELLOWMAP, + va("Vote ends in %d", tickDown) + ); } M_DrawMenuForeground(); @@ -468,29 +458,20 @@ void Y_VoteDrawer(void) // // Vote screen's selection stops moving // -SINT8 deferredlevel = 0; static void Y_VoteStops(SINT8 pick, SINT8 level) { - nextmap = votelevels[level][0]; + nextmap = g_voteLevels[level][0]; - //if (level == 4) - // S_StartSound(NULL, sfx_noooo2); // gasp - if (mapheaderinfo[nextmap] && (mapheaderinfo[nextmap]->menuflags & LF2_HIDEINMENU)) - S_StartSound(NULL, sfx_noooo1); // this is bad - else if (netgame && P_IsLocalPlayer(&players[pick])) - S_StartSound(NULL, sfx_yeeeah); // yeeeah! - else - S_StartSound(NULL, sfx_kc48); // just a cool sound - - if (gametype != votelevels[level][1]) + if (netgame && P_IsLocalPlayer(&players[pick])) { - INT16 lastgametype = gametype; - G_SetGametype(votelevels[level][1]); - D_GameTypeChanged(lastgametype); - forceresetplayers = true; + S_StartSound(NULL, sfx_yeeeah); // yeeeah! + } + else + { + S_StartSound(NULL, sfx_kc48); // just a cool sound } - deferencoremode = (levelinfo[level].encore); + deferencoremode = (g_voteLevels[level][1] & VOTE_MOD_ENCORE); } // @@ -503,14 +484,16 @@ void Y_VoteTicker(void) INT32 i; boolean everyone_voted; - if (paused || P_AutoPause() || !voteclient.loaded) + if (paused || P_AutoPause() || vote.loaded == false) + { return; + } LUA_HOOK(VoteThinker); - votetic++; + vote.tic++; - if (votetic == voteendtic) + if (vote.tic == vote.endtic) { Y_EndVote(); G_AfterIntermission(); @@ -519,38 +502,49 @@ void Y_VoteTicker(void) for (i = 0; i < MAXPLAYERS; i++) // Correct votes as early as possible, before they're processed by the game at all { - if (!playeringame[i] || players[i].spectator) - votes[i] = -1; // Spectators are the lower class, and have effectively no voice in the government. Democracy sucks. - else if (pickedvote != -1 && votes[i] == -1) - votes[i] = 3; // Slow people get random + if (playeringame[i] == false || players[i].spectator == true) + { + g_votes[i] = VOTE_NOT_PICKED; // Spectators are the lower class, and have effectively no voice in the government. Democracy sucks. + } + else if (g_pickedVote != VOTE_NOT_PICKED && g_votes[i] == VOTE_NOT_PICKED) + { + g_votes[i] = 3; // Slow people get random values -- TODO: random vote doesn't exist anymore + } } - if (server && pickedvote != -1 && votes[pickedvote] == -1) // Uh oh! The person who got picked left! Recalculate, quick! + if (server && g_pickedVote != VOTE_NOT_PICKED && g_votes[g_pickedVote] == VOTE_NOT_PICKED) // Uh oh! The person who got picked left! Recalculate, quick! + { D_PickVote(); + } - if (!votetic) + if (vote.tic == 0) { S_ChangeMusicInternal("vote", true); S_ShowMusicCredit(); } - if (timer) - timer--; - - if (pickedvote != -1) + if (vote.timer) { - timer = 0; - voteclient.rsynctime++; + vote.timer--; + } - if (voteendtic == -1) + if (g_pickedVote != VOTE_NOT_PICKED) + { + vote.timer = 0; + vote.rsynctime++; + + if (vote.endtic == -1) { UINT8 tempvotes[MAXPLAYERS]; UINT8 numvotes = 0; for (i = 0; i < MAXPLAYERS; i++) { - if (votes[i] == -1) + if (g_votes[i] == VOTE_NOT_PICKED) + { continue; + } + tempvotes[numvotes] = i; numvotes++; } @@ -562,114 +556,116 @@ void Y_VoteTicker(void) return; } - voteclient.rtics--; + vote.rtics--; - if (voteclient.rtics <= 0) + if (vote.rtics <= 0) { - voteclient.roffset++; - voteclient.rtics = min(20, (3*voteclient.roffset/4)+5); + vote.roffset++; + vote.rtics = min(20, (3*vote.roffset/4)+5); S_StartSound(NULL, sfx_kc39); } - if (voteclient.rendoff == 0 || voteclient.roffset < voteclient.rendoff) - voteclient.ranim = tempvotes[((pickedvote + voteclient.roffset) % numvotes)]; - - if (voteclient.roffset >= 20) + if (vote.rendoff == 0 || vote.roffset < vote.rendoff) { - if (voteclient.rendoff == 0) + vote.ranim = tempvotes[((g_pickedVote + vote.roffset) % numvotes)]; + } + + if (vote.roffset >= 20) + { + if (vote.rendoff == 0) { - if (voteclient.rsynctime % 51 == 0) // Song is 1.45 seconds long (sorry @ whoever wants to replace it in a music wad :V) + if (vote.rsynctime % 51 == 0) // Song is 1.45 seconds long (sorry @ whoever wants to replace it in a music wad :V) { for (i = 5; i >= 3; i--) // Find a suitable place to stop { - if (tempvotes[((pickedvote + voteclient.roffset + i) % numvotes)] == pickedvote) + if (tempvotes[((g_pickedVote + vote.roffset + i) % numvotes)] == g_pickedVote) { - voteclient.rendoff = voteclient.roffset+i; + vote.rendoff = vote.roffset + i; + if (M_RandomChance(FRACUNIT/32)) // Let it cheat occasionally~ - voteclient.rendoff++; + { + vote.rendoff++; + } + S_ChangeMusicInternal("voteeb", false); break; } } } } - else if (voteclient.roffset >= voteclient.rendoff) + else if (vote.roffset >= vote.rendoff) { - voteendtic = votetic + (3*TICRATE); - Y_VoteStops(pickedvote, deferredlevel); + vote.endtic = vote.tic + (3*TICRATE); + Y_VoteStops(g_pickedVote, vote.deferredLevel); } } } else - voteclient.ranim = pickedvote; + { + vote.ranim = g_pickedVote; + } } - else if (votenotyetpicked) + else if (vote.notYetPicked) { - if (votetic < 3*(NEWTICRATE/7)) // give it some time before letting you control it :V + if (vote.tic < 3*(NEWTICRATE/7)) // give it some time before letting you control it :V + { return; + } /* The vote ended, but it will take at least a tic for that to reach us from the server. Don't let me change the vote now, it won't matter anyway! */ - if (timer) + if (vote.timer) { for (i = 0; i <= splitscreen; i++) { - UINT8 p; - boolean pressed = false; + const UINT8 p = g_localplayers[i]; + boolean moved = false; - switch (i) + if (vote.players[i].delay) { - case 1: - p = g_localplayers[1]; - break; - case 2: - p = g_localplayers[2]; - break; - case 3: - p = g_localplayers[3]; - break; - default: - p = consoleplayer; - break; + vote.players[i].delay--; } - if (voteclient.playerinfo[i].delay) - voteclient.playerinfo[i].delay--; - - if ((playeringame[p] && !players[p].spectator) - && !voteclient.playerinfo[i].delay - && pickedvote == -1 && votes[p] == -1 && menuactive == false) + if (Y_PlayerIDCanVote(p) == true + && vote.players[i].delay == 0 + && g_pickedVote == VOTE_NOT_PICKED && g_votes[p] == VOTE_NOT_PICKED + && menuactive == false) { - if (G_PlayerInputDown(i, gc_up, 0)) + if (G_PlayerInputDown(i, gc_left, 0)) { - voteclient.playerinfo[i].selection--; - pressed = true; + vote.players[i].selection--; + moved = true; } - if (G_PlayerInputDown(i, gc_down, 0) && pressed == false) + if (G_PlayerInputDown(i, gc_right, 0)) { - voteclient.playerinfo[i].selection++; - pressed = true; + vote.players[i].selection++; + moved = true; } - if (voteclient.playerinfo[i].selection < 0) - voteclient.playerinfo[i].selection = 3; - if (voteclient.playerinfo[i].selection > 3) - voteclient.playerinfo[i].selection = 0; - - if (G_PlayerInputDown(i, gc_a, 0) && pressed == false) + if (vote.players[i].selection < 0) { - D_ModifyClientVote(consoleplayer, voteclient.playerinfo[i].selection, i); - pressed = true; + vote.players[i].selection = VOTE_NUM_LEVELS - 1; + } + + if (vote.players[i].selection >= VOTE_NUM_LEVELS) + { + vote.players[i].selection = 0; + } + + if (G_PlayerInputDown(i, gc_a, 0) && moved == false) + { + D_ModifyClientVote(consoleplayer, vote.players[i].selection, i); + moved = true; } } - if (pressed) + if (moved) { S_StartSound(NULL, sfx_kc4a); - voteclient.playerinfo[i].delay = NEWTICRATE/7; + vote.players[i].delay = NEWTICRATE/7; } } } @@ -678,38 +674,33 @@ void Y_VoteTicker(void) { everyone_voted = true;/* the default condition */ - if (timer == 0) + for (i = 0; i < MAXPLAYERS; i++) { - for (i = 0; i < MAXPLAYERS; i++) + if (Y_PlayerIDCanVote(i) == false) { - if ((playeringame[i] && !players[i].spectator) && votes[i] == -1) - votes[i] = 3; + continue; } - } - else - { - for (i = 0; i < MAXPLAYERS; i++) - { - if ((playeringame[i] && !players[i].spectator) && votes[i] == -1) - { - if (players[i].bot) - { - if (( M_RandomFixed() % 100 ) == 0) - D_ModifyClientVote(i, M_RandomKey(4), 0); - } - if (votes[i] == -1) - everyone_voted = false; + if (g_votes[i] == VOTE_NOT_PICKED) + { + if (vote.timer == 0) + { + g_votes[i] = 3; // RANDOMIZE LATER + } + else + { + everyone_voted = false; } } } - if (everyone_voted) + if (everyone_voted == true) { - timer = 0; - if (voteendtic == -1) + vote.timer = 0; + + if (vote.endtic == -1) { - votenotyetpicked = false;/* don't pick vote twice */ + vote.notYetPicked = false; /* don't pick vote twice */ D_PickVote(); } } @@ -725,107 +716,93 @@ void Y_VoteTicker(void) void Y_StartVote(void) { INT32 i = 0; - //boolean battlemode = ((votelevels[0][1] & ~VOTEMODIFIER_ENCORE) == GT_BATTLE); // todo gametyperules - votetic = -1; + vote.tic = vote.endtic = -1; -#ifdef PARANOIA - if (voteendtic != -1) - I_Error("voteendtic is dirty"); -#endif - - cursor = W_CachePatchName("M_CURSOR", PU_STATIC); - cursor1 = W_CachePatchName("P1CURSOR", PU_STATIC); - cursor2 = W_CachePatchName("P2CURSOR", PU_STATIC); - cursor3 = W_CachePatchName("P3CURSOR", PU_STATIC); - cursor4 = W_CachePatchName("P4CURSOR", PU_STATIC); - randomlvl = W_CachePatchName("RANDOMLV", PU_STATIC); - rubyicon = W_CachePatchName("RUBYICON", PU_STATIC); + vote_draw.ruby_icon = W_CachePatchName("RUBYICON", PU_STATIC); for (i = 0; i < PLANET_FRAMES; i++) { - bg_planet[i] = W_CachePatchName(va("VT_BG_%d", i + 1), PU_STATIC); + vote_draw.bg_planet[i] = W_CachePatchName(va("VT_BG_%d", i + 1), PU_STATIC); } - bg_checker = W_CachePatchName("VT_RACE", PU_STATIC); - bg_levelText = W_CachePatchName("VT_WELC", PU_STATIC); - bg_derrText = W_CachePatchName("VT_DERR", PU_STATIC); + vote_draw.bg_checker = W_CachePatchName("VT_RACE", PU_STATIC); + vote_draw.bg_levelText = W_CachePatchName("VT_WELC", PU_STATIC); + vote_draw.bg_derrText = W_CachePatchName("VT_DERR", PU_STATIC); - timer = cv_votetime.value*TICRATE; - pickedvote = -1; - - votenotyetpicked = true; - - for (i = 0; i < 3; i++) + vote_draw.catcher_ufo = W_CachePatchName("VT_UFO1", PU_STATIC); + for (i = 0; i < ARM_FRAMES; i++) { - voteclient.playerinfo[i].selection = 0; - voteclient.playerinfo[i].delay = 0; + vote_draw.catcher_arms[i] = W_CachePatchName(va("VT_ARMS%d", i + 1), PU_STATIC); + } + vote_draw.catcher_pole = W_CachePatchName("VT_POLE", PU_STATIC); + for (i = 0; i < BULB_FRAMES; i++) + { + vote_draw.catcher_bulb[i] = W_CachePatchName(va("VT_BULB%d", i + 1), PU_STATIC); } - voteclient.ranim = 0; - voteclient.rtics = 1; - voteclient.roffset = 0; - voteclient.rsynctime = 0; - voteclient.rendoff = 0; + vote.timer = cv_votetime.value * TICRATE; + + g_pickedVote = VOTE_NOT_PICKED; + vote.notYetPicked = true; + + for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) + { + vote.players[i].selection = 0; + vote.players[i].delay = 0; + vote.players[i].catcher.x = 10*FRACUNIT + (72*FRACUNIT/2); + vote.players[i].catcher.y = 144*FRACUNIT + (48*FRACUNIT/2); + } + + vote.ranim = 0; + vote.rtics = 1; + vote.roffset = 0; + vote.rsynctime = 0; + vote.rendoff = 0; for (i = 0; i < MAXPLAYERS; i++) - votes[i] = -1; - - for (i = 0; i < 4; i++) { - // set up the encore - levelinfo[i].encore = (votelevels[i][1] & VOTEMODIFIER_ENCORE); - votelevels[i][1] &= ~VOTEMODIFIER_ENCORE; - - // set up the levelstring - if (mapheaderinfo[votelevels[i][0]]->levelflags & LF_NOZONE || !mapheaderinfo[votelevels[i][0]]->zonttl[0]) - { - if (mapheaderinfo[votelevels[i][0]]->actnum > 0) - snprintf(levelinfo[i].str, - sizeof levelinfo[i].str, - "%s %d", - mapheaderinfo[votelevels[i][0]]->lvlttl, mapheaderinfo[votelevels[i][0]]->actnum); - else - snprintf(levelinfo[i].str, - sizeof levelinfo[i].str, - "%s", - mapheaderinfo[votelevels[i][0]]->lvlttl); - } - else - { - if (mapheaderinfo[votelevels[i][0]]->actnum > 0) - snprintf(levelinfo[i].str, - sizeof levelinfo[i].str, - "%s %s %d", - mapheaderinfo[votelevels[i][0]]->lvlttl, mapheaderinfo[votelevels[i][0]]->zonttl, mapheaderinfo[votelevels[i][0]]->actnum); - else - snprintf(levelinfo[i].str, - sizeof levelinfo[i].str, - "%s %s", - mapheaderinfo[votelevels[i][0]]->lvlttl, mapheaderinfo[votelevels[i][0]]->zonttl); - } - - levelinfo[i].str[sizeof levelinfo[i].str - 1] = '\0'; - - // set up the gtc and gts - levelinfo[i].gtc = 73; // yellowmap[0] -- TODO rewrite vote screen - if (i == 2 && votelevels[i][1] != votelevels[0][1]) - levelinfo[i].gts = gametypes[votelevels[i][1]]->name; - else - levelinfo[i].gts = NULL; + g_votes[i] = VOTE_NOT_PICKED; } - voteclient.loaded = true; - Automate_Run(AEV_VOTESTART); -} + for (i = 0; i < VOTE_NUM_LEVELS; i++) + { + // set up the encore + vote_draw.levels[i].encore = (g_voteLevels[i][1] & VOTE_MOD_ENCORE); -// -// Y_EndVote -// -void Y_EndVote(void) -{ - Y_UnloadVoteData(); - voteendtic = -1; + // set up the levelstring + if (mapheaderinfo[g_voteLevels[i][0]]->levelflags & LF_NOZONE || !mapheaderinfo[g_voteLevels[i][0]]->zonttl[0]) + { + if (mapheaderinfo[g_voteLevels[i][0]]->actnum > 0) + snprintf(vote_draw.levels[i].str, + sizeof vote_draw.levels[i].str, + "%s %d", + mapheaderinfo[g_voteLevels[i][0]]->lvlttl, mapheaderinfo[g_voteLevels[i][0]]->actnum); + else + snprintf(vote_draw.levels[i].str, + sizeof vote_draw.levels[i].str, + "%s", + mapheaderinfo[g_voteLevels[i][0]]->lvlttl); + } + else + { + if (mapheaderinfo[g_voteLevels[i][0]]->actnum > 0) + snprintf(vote_draw.levels[i].str, + sizeof vote_draw.levels[i].str, + "%s %s %d", + mapheaderinfo[g_voteLevels[i][0]]->lvlttl, mapheaderinfo[g_voteLevels[i][0]]->zonttl, mapheaderinfo[g_voteLevels[i][0]]->actnum); + else + snprintf(vote_draw.levels[i].str, + sizeof vote_draw.levels[i].str, + "%s %s", + mapheaderinfo[g_voteLevels[i][0]]->lvlttl, mapheaderinfo[g_voteLevels[i][0]]->zonttl); + } + + vote_draw.levels[i].str[sizeof vote_draw.levels[i].str - 1] = '\0'; + } + + vote.loaded = true; + Automate_Run(AEV_VOTESTART); } // @@ -835,89 +812,131 @@ static void Y_UnloadVoteData(void) { INT32 i; - voteclient.loaded = false; + vote.loaded = false; if (rendermode != render_soft) + { return; + } - UNLOAD(cursor); - UNLOAD(cursor1); - UNLOAD(cursor2); - UNLOAD(cursor3); - UNLOAD(cursor4); - UNLOAD(randomlvl); - UNLOAD(rubyicon); + UNLOAD(vote_draw.ruby_icon); for (i = 0; i < PLANET_FRAMES; i++) { - UNLOAD(bg_planet[i]); + UNLOAD(vote_draw.bg_planet[i]); } + UNLOAD(vote_draw.bg_checker); + UNLOAD(vote_draw.bg_levelText); + UNLOAD(vote_draw.bg_derrText); - UNLOAD(bg_checker); - UNLOAD(bg_levelText); - UNLOAD(bg_derrText); + UNLOAD(vote_draw.catcher_ufo); + for (i = 0; i < ARM_FRAMES; i++) + { + UNLOAD(vote_draw.catcher_arms[i]); + } + UNLOAD(vote_draw.catcher_pole); + for (i = 0; i < BULB_FRAMES; i++) + { + UNLOAD(vote_draw.catcher_bulb[i]); + } +} + +// +// Y_EndVote +// +void Y_EndVote(void) +{ + Y_UnloadVoteData(); + vote.endtic = -1; } // // Y_SetupVoteFinish // + +enum +{ + VOTE_END_IMMEDIATE = 0, + VOTE_END_QUICK, + VOTE_END_NORMAL, +}; + void Y_SetupVoteFinish(SINT8 pick, SINT8 level) { - if (!voteclient.loaded) + if (vote.loaded == false) + { return; + } - if (pick == -1) // No other votes? We gotta get out of here, then! + if (pick == VOTE_NOT_PICKED) // No other votes? We gotta get out of here, then! { Y_EndVote(); G_AfterIntermission(); return; } - if (pickedvote == -1) + if (g_pickedVote == VOTE_NOT_PICKED) { INT32 i; - SINT8 votecompare = -1; - INT32 endtype = 0; + SINT8 votecompare = VOTE_NOT_PICKED; + INT32 endtype = VOTE_END_IMMEDIATE; - voteclient.rsynctime = 0; + vote.rsynctime = 0; for (i = 0; i < MAXPLAYERS; i++) { - if ((playeringame[i] && !players[i].spectator) && votes[i] == -1) - votes[i] = 3; - - if (votes[i] == -1 || endtype > 1) // Don't need to go on - continue; - - if (endtype == 2) - continue; - - if (votecompare == -1) + if (Y_PlayerIDCanVote(i) == true && g_votes[i] == VOTE_NOT_PICKED) { - votecompare = votes[i]; - endtype = 1; + g_votes[i] = 3; // RANDOMIZE + } + + if (g_votes[i] == VOTE_NOT_PICKED || endtype > VOTE_END_QUICK) // Don't need to go on + { + continue; + } + + if (endtype == VOTE_END_NORMAL) + { + continue; + } + + if (votecompare == VOTE_NOT_PICKED) + { + votecompare = g_votes[i]; + endtype = VOTE_END_QUICK; + } + else if (g_votes[i] != votecompare) + { + endtype = VOTE_END_NORMAL; } - else if (votes[i] != votecompare) - endtype = 2; } - if (endtype == 1) // Only one unique vote, so just end it immediately. + switch (endtype) { - voteendtic = votetic + (5*TICRATE); - S_ChangeMusicInternal("voteeb", false); - Y_VoteStops(pick, level); + case VOTE_END_IMMEDIATE: + { + // Might as well put it here, too, just in case. + Y_EndVote(); + G_AfterIntermission(); + return; + } + case VOTE_END_QUICK: + { + // Only one unique vote, so just end it immediately. + vote.endtic = vote.tic + (5*TICRATE); + S_ChangeMusicInternal("voteeb", false); + Y_VoteStops(pick, level); + break; + } + default: + { + S_ChangeMusicInternal("voteea", true); + break; + } } - else if (endtype == 0) // Might as well put this here, too. - { - Y_EndVote(); - G_AfterIntermission(); - return; - } - else - S_ChangeMusicInternal("voteea", true); } - deferredlevel = level; - pickedvote = pick; - timer = 0; + vote.deferredLevel = level; + g_pickedVote = pick; + vote.timer = 0; } diff --git a/src/k_vote.h b/src/k_vote.h index 1e82b40b5..3f3d12b44 100644 --- a/src/k_vote.h +++ b/src/k_vote.h @@ -19,6 +19,11 @@ extern "C" { #endif +#define VOTE_NUM_LEVELS (4) +#define VOTE_NOT_PICKED (-1) + +#define VOTE_MOD_ENCORE (0x01) + void Y_VoteDrawer(void); void Y_VoteTicker(void); void Y_StartVote(void); diff --git a/src/p_saveg.c b/src/p_saveg.c index be5b65132..05c55e0ea 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4999,14 +4999,14 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) for (i = 0; i < 4; i++) { - WRITEINT16(save->p, votelevels[i][0]); - WRITEINT16(save->p, votelevels[i][1]); + WRITEINT16(save->p, g_voteLevels[i][0]); + WRITEINT16(save->p, g_voteLevels[i][1]); } for (i = 0; i < MAXPLAYERS; i++) - WRITESINT8(save->p, votes[i]); + WRITESINT8(save->p, g_votes[i]); - WRITESINT8(save->p, pickedvote); + WRITESINT8(save->p, g_pickedVote); WRITEUINT16(save->p, emeralds); { @@ -5171,14 +5171,16 @@ static inline boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading) for (i = 0; i < 4; i++) { - votelevels[i][0] = READINT16(save->p); - votelevels[i][1] = READINT16(save->p); + g_voteLevels[i][0] = READINT16(save->p); + g_voteLevels[i][1] = READINT16(save->p); } for (i = 0; i < MAXPLAYERS; i++) - votes[i] = READSINT8(save->p); + { + g_votes[i] = READSINT8(save->p); + } - pickedvote = READSINT8(save->p); + g_pickedVote = READSINT8(save->p); emeralds = READUINT16(save->p); { From 7641c6a276351130f9d7aeac44f35dc265cefab0 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 4 Apr 2023 02:07:30 -0400 Subject: [PATCH 18/31] ModifyClientVote sends a netxcmd for the player It was implemented before SendNetXCmdForPlayer, so it used to just send it from the consoleplayer and just attach the player number separately. Now the packet will actually be guaranteed to come from the player that wants to change their vote. (Probably was fuckin possible to just change everyone else's votes with a hacked client before, right) --- src/d_netcmd.c | 35 +++++++++++++++++++---------------- src/d_netcmd.h | 2 +- src/k_vote.c | 8 ++++---- src/k_vote.h | 1 + 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 2e845fa8f..9337e98c6 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2633,17 +2633,18 @@ void D_SetupVote(void) SendNetXCmd(XD_SETUPVOTE, buf, p - buf); } -void D_ModifyClientVote(UINT8 player, SINT8 voted, UINT8 splitplayer) +void D_ModifyClientVote(UINT8 player, SINT8 voted) { - char buf[2]; + char buf[1]; char *p = buf; - if (splitplayer > 0) - player = g_localplayers[splitplayer]; + if (player >= MAXSPLITSCREENPLAYERS) + { + return; + } WRITESINT8(p, voted); - WRITEUINT8(p, player); - SendNetXCmd(XD_MODIFYVOTE, &buf, 2); + SendNetXCmdForPlayer(player, XD_MODIFYVOTE, &buf, 2); } void D_PickVote(void) @@ -2652,21 +2653,27 @@ void D_PickVote(void) char* p = buf; SINT8 temppicks[MAXPLAYERS]; SINT8 templevels[MAXPLAYERS]; - SINT8 votecompare = -1; + SINT8 votecompare = VOTE_NOT_PICKED; UINT8 numvotes = 0, key = 0; INT32 i; for (i = 0; i < MAXPLAYERS; i++) { - if (!playeringame[i] || players[i].spectator) + if (Y_PlayerIDCanVote(i) == false) + { continue; - if (g_votes[i] != -1) + } + + if (g_votes[i] != VOTE_NOT_PICKED) { temppicks[numvotes] = i; templevels[numvotes] = g_votes[i]; numvotes++; - if (votecompare == -1) + + if (votecompare == VOTE_NOT_PICKED) + { votecompare = g_votes[i]; + } } } @@ -2679,7 +2686,7 @@ void D_PickVote(void) } else { - WRITESINT8(p, -1); + WRITESINT8(p, VOTE_NOT_PICKED); WRITESINT8(p, 0); } @@ -5415,11 +5422,7 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) static void Got_ModifyVotecmd(UINT8 **cp, INT32 playernum) { - SINT8 voted = READSINT8(*cp); - UINT8 p = READUINT8(*cp); - - (void)playernum; - g_votes[p] = voted; + g_votes[playernum] = READSINT8(*cp); } static void Got_PickVotecmd(UINT8 **cp, INT32 playernum) diff --git a/src/d_netcmd.h b/src/d_netcmd.h index c7e75b83c..d4c7d82a4 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -240,7 +240,7 @@ void Command_Retry_f(void); void D_GameTypeChanged(INT32 lastgametype); // not a real _OnChange function anymore void D_MapChange(INT32 pmapnum, INT32 pgametype, boolean pencoremode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pfromlevelselect); void D_SetupVote(void); -void D_ModifyClientVote(UINT8 player, SINT8 voted, UINT8 splitplayer); +void D_ModifyClientVote(UINT8 player, SINT8 voted); void D_PickVote(void); void ObjectPlace_OnChange(void); boolean IsPlayerAdmin(INT32 playernum); diff --git a/src/k_vote.c b/src/k_vote.c index 58cab978a..542bd5566 100644 --- a/src/k_vote.c +++ b/src/k_vote.c @@ -123,7 +123,7 @@ typedef struct static y_vote_data vote = {0}; static y_vote_draw vote_draw = {0}; -static boolean Y_PlayerIDCanVote(const UINT8 id) +boolean Y_PlayerIDCanVote(const UINT8 id) { if (id >= MAXPLAYERS) { @@ -386,7 +386,7 @@ void Y_VoteDrawer(void) if (dedicated && i == 0) // While leaving blank spots for non-existent players is largely intentional, the first spot *always* being blank looks a tad silly :V continue; - if ((playeringame[i] && !players[i].spectator) && g_votes[i] != VOTE_NOT_PICKED) + if (Y_PlayerIDCanVote(i) == true && g_votes[i] != VOTE_NOT_PICKED) { if (!timer && i == voteclient.ranim) { @@ -502,7 +502,7 @@ void Y_VoteTicker(void) for (i = 0; i < MAXPLAYERS; i++) // Correct votes as early as possible, before they're processed by the game at all { - if (playeringame[i] == false || players[i].spectator == true) + if (Y_PlayerIDCanVote(i) == false) { g_votes[i] = VOTE_NOT_PICKED; // Spectators are the lower class, and have effectively no voice in the government. Democracy sucks. } @@ -657,7 +657,7 @@ void Y_VoteTicker(void) if (G_PlayerInputDown(i, gc_a, 0) && moved == false) { - D_ModifyClientVote(consoleplayer, vote.players[i].selection, i); + D_ModifyClientVote(i, vote.players[i].selection); moved = true; } } diff --git a/src/k_vote.h b/src/k_vote.h index 3f3d12b44..6705c994a 100644 --- a/src/k_vote.h +++ b/src/k_vote.h @@ -24,6 +24,7 @@ extern "C" { #define VOTE_MOD_ENCORE (0x01) +boolean Y_PlayerIDCanVote(const UINT8 id); void Y_VoteDrawer(void); void Y_VoteTicker(void); void Y_StartVote(void); From b799862ccbf32abc59e9262015b3aa5559ead148 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 4 Apr 2023 22:09:37 -0400 Subject: [PATCH 19/31] Implement FG catchers - Catcher comes down to grab your selection. (Needs per-player arrows, as discussed last night.) - Catcher has more accurate rainbow cycle. Just looks a bit cleaner. - Vote thumbnails now have outlines & dims, instead of transparency. - Put voting roulette code into its own struct. - Sped up voting roulette. (although it's not visible currently) - Made modify vote stricter (kick hacked clients trying to do funky stuff) - Added VOTE_TIME_WAIT_FOR_VOTE define. If enabled, voting timer will only start when any player gives a vote. Currently disable because it'd be exploitable without mid-game vote joining. --- src/d_netcmd.c | 27 +- src/k_vote.c | 649 +++++++++++++++++++++++++++++++++++------------- src/k_vote.h | 4 +- src/v_video.cpp | 2 +- 4 files changed, 503 insertions(+), 179 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 9337e98c6..f70f556ae 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2635,7 +2635,7 @@ void D_SetupVote(void) void D_ModifyClientVote(UINT8 player, SINT8 voted) { - char buf[1]; + char buf[2]; char *p = buf; if (player >= MAXSPLITSCREENPLAYERS) @@ -2643,8 +2643,10 @@ void D_ModifyClientVote(UINT8 player, SINT8 voted) return; } + WRITEUINT8(p, g_localplayers[player]); WRITESINT8(p, voted); - SendNetXCmdForPlayer(player, XD_MODIFYVOTE, &buf, 2); + + SendNetXCmdForPlayer(player, XD_MODIFYVOTE, buf, p - buf); } void D_PickVote(void) @@ -5422,7 +5424,26 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) static void Got_ModifyVotecmd(UINT8 **cp, INT32 playernum) { - g_votes[playernum] = READSINT8(*cp); + UINT8 targetID = READUINT8(*cp); + SINT8 vote = READSINT8(*cp); + + if (targetID >= MAXPLAYERS + || playernode[targetID] != playernode[playernum]) + { + CONS_Alert(CONS_WARNING, + M_GetText ("Illegal modify vote command received from %s\n"), + player_names[playernum] + ); + + if (server) + { + SendKick(playernum, KICK_MSG_CON_FAIL); + } + + return; + } + + Y_SetPlayersVote(targetID, vote); } static void Got_PickVotecmd(UINT8 **cp, INT32 playernum) diff --git a/src/k_vote.c b/src/k_vote.c index 542bd5566..b5eefe7a9 100644 --- a/src/k_vote.c +++ b/src/k_vote.c @@ -56,6 +56,15 @@ #include "hardware/hw_main.h" #endif +// Wait for any player to vote before starting the timer. +// Disabled because a player can join and be sent to +// the waiting screen, and if there's only 1 player in +// the vote screen they can idle for as long as they want, +// effectively locking the server up. +// This can be re-enabled if you want to send the vote +// screen in gamestate. (I don't feel like it.) +//#define VOTE_TIME_WAIT_FOR_VOTE + #define UNLOAD(x) if (x) {Patch_Free(x);} x = NULL; #define CLEANUP(x) x = NULL; @@ -66,12 +75,48 @@ #define ARM_FRAMES (4) #define BULB_FRAMES (4) +#define CATCHER_SPEED (8*FRACUNIT) +#define CATCHER_Y_OFFSET (32*FRACUNIT) +#define CATCHER_OFFSCREEN (-CATCHER_Y_OFFSET * 2) + +#define SELECTION_WIDTH (72*FRACUNIT) +#define SELECTION_HEIGHT ((SELECTION_WIDTH * BASEVIDHEIGHT) / BASEVIDWIDTH) +#define SELECTION_X (10*FRACUNIT + (SELECTION_WIDTH >> 1)) +#define SELECTION_Y (144*FRACUNIT + (SELECTION_HEIGHT >> 1)) +#define SELECTION_SPACE (4*FRACUNIT) +#define SELECTION_SPACING_W (SELECTION_WIDTH + SELECTION_SPACE) +#define SELECTION_SPACING_H (SELECTION_HEIGHT + SELECTION_SPACE) +#define SELECTION_HOP (10*FRACUNIT) + // Catcher data +enum +{ + CATCHER_NA = 0, + + CATCHER_FG_LOWER, + CATCHER_FG_GRAB, + CATCHER_FG_STRUGGLE, + CATCHER_FG_POPUP, + CATCHER_FG_RISE, + + CATCHER_BG_LOWER, + CATCHER_BG_RELEASE, + CATCHER_BG_RISE, +}; + typedef struct { fixed_t x, y; + fixed_t destX, destY; + UINT8 spr; boolean small; + + UINT8 action; + tic_t delay; + + SINT8 level; + UINT8 player; } y_vote_catcher; // Clientside & splitscreen player info. @@ -82,23 +127,38 @@ typedef struct UINT8 delay; } y_vote_player; +// Vote "pile" data. Objects for each vote scattered about. +typedef struct +{ + fixed_t x, y; + fixed_t destX, destY; + y_vote_catcher catcher; +} y_vote_pile; + +// Voting roulette variables. +typedef struct +{ + y_vote_pile pile[MAXPLAYERS]; + UINT8 anim; + UINT8 tics; + UINT32 offset; + UINT32 endOffset; + UINT8 syncTime; +} y_vote_roulette; + +// General vote variables typedef struct { INT32 timer; INT32 tic, endtic; boolean notYetPicked; boolean loaded; - - y_vote_player players[MAXSPLITSCREENPLAYERS]; - UINT8 ranim; - UINT8 rtics; - UINT8 roffset; - UINT8 rsynctime; - UINT8 rendoff; - SINT8 deferredLevel; + y_vote_player players[MAXSPLITSCREENPLAYERS]; + y_vote_roulette roulette; } y_vote_data; +// Voting level drawing typedef struct { char str[62]; @@ -106,36 +166,40 @@ typedef struct fixed_t hop; } y_vote_draw_level; +// General vote drawing typedef struct { patch_t *ruby_icon; + fixed_t ruby_height; + patch_t *bg_planet[PLANET_FRAMES]; patch_t *bg_checker; patch_t *bg_levelText; patch_t *bg_derrText; + patch_t *catcher_ufo; patch_t *catcher_arms[ARM_FRAMES]; patch_t *catcher_pole; patch_t *catcher_bulb[BULB_FRAMES]; + + fixed_t selectTransition; y_vote_draw_level levels[VOTE_NUM_LEVELS]; } y_vote_draw; static y_vote_data vote = {0}; static y_vote_draw vote_draw = {0}; -boolean Y_PlayerIDCanVote(const UINT8 id) +boolean Y_PlayerIDCanVote(const UINT8 playerId) { - if (id >= MAXPLAYERS) + player_t *player = NULL; + + if (playerId >= MAXPLAYERS || playeringame[playerId] == false) { return false; } - if (playeringame[id] == false || players[id].spectator == true) - { - return false; - } - - if (players[id].bot == true) + player = &players[playerId]; + if (player->spectator == true || player->bot == true) { return false; } @@ -143,24 +207,167 @@ boolean Y_PlayerIDCanVote(const UINT8 id) return true; } +void Y_SetPlayersVote(const UINT8 playerId, SINT8 newVote) +{ + if (gamestate != GS_VOTING) + { + return; + } + + if (newVote < 0 || newVote >= VOTE_NUM_LEVELS) + { + newVote = VOTE_NOT_PICKED; + } + + g_votes[playerId] = newVote; + +#ifdef VOTE_TIME_WAIT_FOR_VOTE + if (vote.timer == -1) + { + // Someone has voted, so start the timer now. + vote.timer = cv_votetime.value * TICRATE; + } +#endif +} + +static void Y_DrawVoteThumbnail(fixed_t x, fixed_t y, fixed_t width, INT32 flags, SINT8 v, boolean dim) +{ + const fixed_t height = (width * BASEVIDHEIGHT) / BASEVIDWIDTH; + INT32 fx, fy, fw, fh; + INT32 dupx, dupy; + + if (v < 0 || v >= VOTE_NUM_LEVELS) + { + return; + } + + x -= width / 2; + y -= height / 2; + + dupx = vid.dupx; + dupy = vid.dupy; + + if (flags & V_SCALEPATCHMASK) + { + switch ((flags & V_SCALEPATCHMASK) >> V_SCALEPATCHSHIFT) + { + case 1: // V_NOSCALEPATCH + dupx = dupy = 1; + break; + case 2: // V_SMALLSCALEPATCH + dupx = vid.smalldupx; + dupy = vid.smalldupy; + break; + case 3: // V_MEDSCALEPATCH + dupx = vid.meddupx; + dupy = vid.meddupy; + break; + default: + break; + } + } + + // only use one dup, to avoid stretching (har har) + dupx = dupy = (dupx < dupy ? dupx : dupy); + + fx = FixedMul(x, dupx << FRACBITS) >> FRACBITS; + fy = FixedMul(y, dupy << FRACBITS) >> FRACBITS; + fw = FixedMul(width - 1, dupx << FRACBITS) >> FRACBITS; // Why does only this need -1 to match up? IDFK + fh = FixedMul(height, dupy << FRACBITS) >> FRACBITS; + + V_AdjustXYWithSnap(&fx, &fy, flags, dupx, dupy); + + V_DrawFill( + fx - dupx, fy - dupy, + fw + (dupx << 1), fh + (dupy << 1), + 0|flags|V_NOSCALESTART + ); + + K_DrawMapThumbnail( + x, y, + width, flags, + g_voteLevels[v][0], + NULL + ); + + if (dim == true) + { + V_DrawFadeFill( + fx, fy, + fw, fh, + flags|V_NOSCALESTART, + 31, 5 + ); + } +} + static void Y_DrawCatcher(y_vote_catcher *catcher) { +#define NUM_UFO_COLORS (8) + static const skincolornum_t ufoColors[NUM_UFO_COLORS] = { + SKINCOLOR_EMERALD, + SKINCOLOR_SWAMP, + SKINCOLOR_TAFFY, + SKINCOLOR_ROSE, + SKINCOLOR_CYAN, + SKINCOLOR_NAVY, + SKINCOLOR_GOLD, + SKINCOLOR_BRONZE, + }; + #define NUM_BULB_COLORS (2) static const skincolornum_t bulbColors[NUM_BULB_COLORS] = { SKINCOLOR_JAWZ, SKINCOLOR_LILAC, }; - const tic_t anim = gametic / 3; // Using gametic for this is probably a bit goofy + static fixed_t anim = 0; + tic_t colorTic = 0; - fixed_t x = catcher->x - (vote_draw.catcher_ufo->width * FRACUNIT / 2); - fixed_t y = catcher->y - (vote_draw.catcher_ufo->height * FRACUNIT * 7 / 8); + fixed_t baseX = INT32_MAX; + fixed_t x = INT32_MAX; + fixed_t y = INT32_MAX; UINT8 *craneColor = NULL; UINT8 *bulbColor = NULL; - craneColor = R_GetTranslationColormap(TC_DEFAULT, K_RainbowColor(anim), GTC_MENUCACHE); - bulbColor = R_GetTranslationColormap(TC_DEFAULT, bulbColors[(anim / BULB_FRAMES) % NUM_BULB_COLORS], GTC_MENUCACHE); + if (catcher->action == CATCHER_NA) + { + // Don't display in the empty state + return; + } + + anim += renderdeltatics; + colorTic = (anim / 3) / FRACUNIT; + + baseX = catcher->x; + + if (catcher->action == CATCHER_FG_STRUGGLE) + { + if ((anim / FRACUNIT) & 1) + { + baseX += FRACUNIT; + } + else + { + baseX -= FRACUNIT; + } + } + + x = baseX - (vote_draw.catcher_ufo->width * FRACUNIT / 2); + y = catcher->y - (vote_draw.catcher_ufo->height * FRACUNIT) + CATCHER_Y_OFFSET; + + craneColor = R_GetTranslationColormap(TC_DEFAULT, ufoColors[colorTic % NUM_UFO_COLORS], GTC_MENUCACHE); + bulbColor = R_GetTranslationColormap(TC_DEFAULT, bulbColors[(colorTic / BULB_FRAMES) % NUM_BULB_COLORS], GTC_MENUCACHE); + + if (catcher->level != VOTE_NOT_PICKED) + { + Y_DrawVoteThumbnail( + baseX, catcher->y, + SELECTION_WIDTH, 0, + catcher->level, false + ); + } V_DrawFixedPatch( x, y, @@ -172,7 +379,7 @@ static void Y_DrawCatcher(y_vote_catcher *catcher) V_DrawFixedPatch( x, y, FRACUNIT, 0, - vote_draw.catcher_bulb[anim % BULB_FRAMES], + vote_draw.catcher_bulb[colorTic % BULB_FRAMES], bulbColor ); @@ -189,6 +396,7 @@ static void Y_DrawCatcher(y_vote_catcher *catcher) vote_draw.catcher_pole, NULL ); +#undef NUM_UFO_COLORS #undef NUM_BULB_COLORS } @@ -216,12 +424,12 @@ static void Y_DrawVoteBackground(void) ); V_DrawFixedPatch( (BASEVIDWIDTH - vote_draw.bg_checker->width) * FRACUNIT, 0, - FRACUNIT, V_ADD, + FRACUNIT, V_ADD|V_TRANSLUCENT, vote_draw.bg_checker, NULL ); V_DrawFixedPatch( (BASEVIDWIDTH - vote_draw.bg_checker->width) * FRACUNIT, 0, - FRACUNIT, V_ADD, + FRACUNIT, V_ADD|V_TRANSLUCENT, vote_draw.bg_checker, NULL ); @@ -266,48 +474,21 @@ static void Y_DrawVoteBackground(void) bgTimer += renderdeltatics; } -void Y_VoteDrawer(void) +static void Y_DrawVoteSelection(fixed_t offset) { - fixed_t x, y; - fixed_t rubyHeight = 0; - INT32 i, j; - - // If we early return, skip drawing the 3D scene (software buffer) so it doesn't clobber the frame for the wipe - g_wipeskiprender = true; - - if (rendermode == render_none) - { - return; - } - - if (vote.tic >= vote.endtic && vote.endtic != -1) - { - return; - } - - if (vote.loaded == false) - { - return; - } - - g_wipeskiprender = false; - - { - static angle_t rubyFloatTime = 0; - rubyHeight = FINESINE(rubyFloatTime >> ANGLETOFINESHIFT); - rubyFloatTime += FixedMul(ANGLE_MAX / NEWTICRATE, renderdeltatics); - } - - Y_DrawVoteBackground(); - - x = 10 * FRACUNIT; - y = 144 * FRACUNIT; + fixed_t x = SELECTION_X; + fixed_t y = SELECTION_Y + FixedMul(offset, SELECTION_HEIGHT * 2); + INT32 i; + // + // Draw map icons + // for (i = 0; i < VOTE_NUM_LEVELS; i++) { boolean selected = false; INT32 flags = 0; fixed_t destHop = 0; + INT32 j; for (j = 0; j <= splitscreen; j++) // another loop for drawing the selection backgrounds in the right order, grumble grumble.. { @@ -329,11 +510,7 @@ void Y_VoteDrawer(void) if (selected == true) { - destHop = 10*FRACUNIT; - } - else - { - flags |= V_TRANSLUCENT; + destHop = SELECTION_HOP; } if (vote_draw.levels[i].encore == true) @@ -341,103 +518,80 @@ void Y_VoteDrawer(void) flags |= V_FLIP; } - if (vote_draw.levels[i].hop < destHop) - { - vote_draw.levels[i].hop += FixedMul( - (destHop - vote_draw.levels[i].hop) / 2, - renderdeltatics - ); - } - else - { - vote_draw.levels[i].hop = destHop; - } + vote_draw.levels[i].hop += FixedMul( + (destHop - vote_draw.levels[i].hop) / 2, + renderdeltatics + ); - K_DrawMapThumbnail( + Y_DrawVoteThumbnail( x, y - vote_draw.levels[i].hop, - 72 << FRACBITS, flags, - g_voteLevels[i][0], - NULL + SELECTION_WIDTH, flags, + i, (selected == false) ); if (vote_draw.levels[i].encore == true) { V_DrawFixedPatch( - x + (40 << FRACBITS), - ((y + 25) << FRACBITS) - (rubyHeight << 1), + x - (vote_draw.ruby_icon->width * (FRACUNIT >> 1)), + y - (vote_draw.ruby_icon->height * (FRACUNIT >> 1)) - (vote_draw.ruby_height << 1), FRACUNIT, (flags & ~V_FLIP), - vote_draw.ruby_icon, + vote_draw.ruby_icon, NULL ); } - x += (75 << FRACBITS); + x += SELECTION_SPACING_W; } - // TODO: draw + update catchers - Y_DrawCatcher(&vote.players[0].catcher); - - /* - x = 20; - y = 10; - - for (i = 0; i < MAXPLAYERS; i++) + // + // Draw our catchers + // + for (i = 0; i <= splitscreen; i++) { - if (dedicated && i == 0) // While leaving blank spots for non-existent players is largely intentional, the first spot *always* being blank looks a tad silly :V - continue; - - if (Y_PlayerIDCanVote(i) == true && g_votes[i] != VOTE_NOT_PICKED) - { - if (!timer && i == voteclient.ranim) - { - V_DrawScaledPatch(x-18, y+9, V_SNAPTOLEFT, cursor); - if (voteendtic != -1 && !(votetic % 4)) - V_DrawFill(x-1, y-1, 42, 27, 0|V_SNAPTOLEFT); - else - V_DrawFill(x-1, y-1, 42, 27, levelinfo[g_votes[i]].gtc|V_SNAPTOLEFT); - } - - K_DrawMapThumbnail( - (x)< BASEVIDHEIGHT-40) - { - x += 60; - y = 10; - } + Y_DrawCatcher(&vote.players[i].catcher); } - */ +} + +static void Y_DrawVotePile(void) +{ + // TODO +} + +void Y_VoteDrawer(void) +{ + static angle_t rubyFloatTime = 0; + + // If we early return, skip drawing the 3D scene (software buffer) so it doesn't clobber the frame for the wipe + g_wipeskiprender = true; + + if (rendermode == render_none) + { + return; + } + + if (vote.tic >= vote.endtic && vote.endtic != -1) + { + return; + } + + if (vote.loaded == false) + { + return; + } + + g_wipeskiprender = false; + + vote_draw.ruby_height = FINESINE(rubyFloatTime >> ANGLETOFINESHIFT); + rubyFloatTime += FixedMul(ANGLE_MAX / NEWTICRATE, renderdeltatics); + + vote_draw.selectTransition += FixedMul( + (((g_pickedVote != VOTE_NOT_PICKED) ? FRACUNIT : 0) - vote_draw.selectTransition) / 2, + renderdeltatics + ); + + Y_DrawVoteBackground(); + Y_DrawVotePile(); + Y_DrawVoteSelection(vote_draw.selectTransition); if (vote.timer > 0) { @@ -474,6 +628,139 @@ static void Y_VoteStops(SINT8 pick, SINT8 level) deferencoremode = (g_voteLevels[level][1] & VOTE_MOD_ENCORE); } +static void Y_PlayerSendVote(const UINT8 localPlayer) +{ + y_vote_player *const player = &vote.players[localPlayer]; + y_vote_catcher *const catcher = &player->catcher; + + catcher->action = CATCHER_FG_LOWER; + + catcher->x = catcher->destX = SELECTION_X + (SELECTION_SPACING_W * player->selection); + catcher->y = CATCHER_OFFSCREEN; + catcher->destY = SELECTION_Y - SELECTION_HOP; + catcher->spr = 0; + catcher->level = VOTE_NOT_PICKED; + + S_StartSound(NULL, sfx_kc37); +} + +static void Y_TickPlayerCatcher(const UINT8 localPlayer) +{ + y_vote_player *const player = &vote.players[localPlayer]; + y_vote_catcher *const catcher = &player->catcher; + + fixed_t spd = CATCHER_SPEED; + fixed_t xDelta = catcher->destX - catcher->x; + + if (xDelta != 0) + { + // Move X position first + if (abs(xDelta) <= spd) + { + catcher->x = catcher->destX; + } + else + { + if (xDelta < 0) + { + catcher->x -= spd; + } + else + { + catcher->x += spd; + } + } + } + else + { + // Then start moving Y position + fixed_t yDelta = catcher->destY - catcher->y; + + if (abs(yDelta) <= spd) + { + catcher->y = catcher->destY; + } + else + { + if (yDelta < 0) + { + catcher->y -= spd; + } + else + { + catcher->y += spd; + } + } + } + + if (catcher->delay > 0) + { + catcher->delay--; + return; + } + + switch (catcher->action) + { + case CATCHER_FG_LOWER: + { + if (catcher->x == catcher->destX && catcher->y == catcher->destY) + { + catcher->action++; + + S_StopSoundByNum(sfx_kc37); + S_StartSound(NULL, sfx_kc68); + } + break; + } + + case CATCHER_FG_GRAB: + { + catcher->spr++; + + if (catcher->spr >= ARM_FRAMES-1) + { + catcher->action = CATCHER_FG_STRUGGLE; + catcher->level = vote.players[localPlayer].selection; + catcher->delay = 20; + } + break; + } + + case CATCHER_FG_STRUGGLE: + { + catcher->action = CATCHER_FG_POPUP; + catcher->destY -= SELECTION_HOP * 3; + catcher->delay = 15; + break; + } + + case CATCHER_FG_POPUP: + { + catcher->action = CATCHER_FG_RISE; + catcher->destY = CATCHER_OFFSCREEN; + S_StartSound(NULL, sfx_kc37); + break; + } + + case CATCHER_FG_RISE: + { + if (catcher->x == catcher->destX && catcher->y == catcher->destY) + { + D_ModifyClientVote(localPlayer, vote.players[localPlayer].selection); + catcher->action = CATCHER_NA; + S_StopSoundByNum(sfx_kc37); + } + break; + } + + default: + { + catcher->action = CATCHER_NA; + break; + } + } +} + // // Y_VoteTicker // @@ -523,15 +810,20 @@ void Y_VoteTicker(void) S_ShowMusicCredit(); } - if (vote.timer) + if (vote.timer > 0) { vote.timer--; } + for (i = 0; i <= splitscreen; i++) + { + Y_TickPlayerCatcher(i); + } + if (g_pickedVote != VOTE_NOT_PICKED) { vote.timer = 0; - vote.rsynctime++; + vote.roulette.syncTime++; if (vote.endtic == -1) { @@ -556,35 +848,37 @@ void Y_VoteTicker(void) return; } - vote.rtics--; - - if (vote.rtics <= 0) + if (vote.roulette.tics > 0) { - vote.roffset++; - vote.rtics = min(20, (3*vote.roffset/4)+5); + vote.roulette.tics--; + } + else + { + vote.roulette.offset++; + vote.roulette.tics = min(6, 9 * vote.roulette.offset / 40); S_StartSound(NULL, sfx_kc39); } - if (vote.rendoff == 0 || vote.roffset < vote.rendoff) + if (vote.roulette.endOffset == 0 || vote.roulette.offset < vote.roulette.endOffset) { - vote.ranim = tempvotes[((g_pickedVote + vote.roffset) % numvotes)]; + vote.roulette.anim = tempvotes[((g_pickedVote + vote.roulette.offset) % numvotes)]; } - if (vote.roffset >= 20) + if (vote.roulette.offset > 40) { - if (vote.rendoff == 0) + if (vote.roulette.endOffset == 0) { - if (vote.rsynctime % 51 == 0) // Song is 1.45 seconds long (sorry @ whoever wants to replace it in a music wad :V) + if (vote.roulette.syncTime % 51 == 0) // Song is 1.45 seconds long (sorry @ whoever wants to replace it in a music wad :V) { for (i = 5; i >= 3; i--) // Find a suitable place to stop { - if (tempvotes[((g_pickedVote + vote.roffset + i) % numvotes)] == g_pickedVote) + if (tempvotes[((g_pickedVote + vote.roulette.offset + i) % numvotes)] == g_pickedVote) { - vote.rendoff = vote.roffset + i; + vote.roulette.endOffset = vote.roulette.offset + i; if (M_RandomChance(FRACUNIT/32)) // Let it cheat occasionally~ { - vote.rendoff++; + vote.roulette.endOffset++; } S_ChangeMusicInternal("voteeb", false); @@ -593,7 +887,7 @@ void Y_VoteTicker(void) } } } - else if (vote.roffset >= vote.rendoff) + else if (vote.roulette.offset >= vote.roulette.endOffset) { vote.endtic = vote.tic + (3*TICRATE); Y_VoteStops(g_pickedVote, vote.deferredLevel); @@ -602,7 +896,7 @@ void Y_VoteTicker(void) } else { - vote.ranim = g_pickedVote; + vote.roulette.anim = g_pickedVote; } } else if (vote.notYetPicked) @@ -616,7 +910,7 @@ void Y_VoteTicker(void) The vote ended, but it will take at least a tic for that to reach us from the server. Don't let me change the vote now, it won't matter anyway! */ - if (vote.timer) + if (vote.timer != 0) { for (i = 0; i <= splitscreen; i++) { @@ -629,9 +923,10 @@ void Y_VoteTicker(void) } if (Y_PlayerIDCanVote(p) == true + && menuactive == false && vote.players[i].delay == 0 && g_pickedVote == VOTE_NOT_PICKED && g_votes[p] == VOTE_NOT_PICKED - && menuactive == false) + && vote.players[i].catcher.action == CATCHER_NA) { if (G_PlayerInputDown(i, gc_left, 0)) { @@ -657,7 +952,7 @@ void Y_VoteTicker(void) if (G_PlayerInputDown(i, gc_a, 0) && moved == false) { - D_ModifyClientVote(i, vote.players[i].selection); + Y_PlayerSendVote(i); moved = true; } } @@ -741,7 +1036,11 @@ void Y_StartVote(void) vote_draw.catcher_bulb[i] = W_CachePatchName(va("VT_BULB%d", i + 1), PU_STATIC); } +#ifdef VOTE_TIME_WAIT_FOR_VOTE + vote.timer = -1; // Timer is not set until the first vote is added +#else vote.timer = cv_votetime.value * TICRATE; +#endif g_pickedVote = VOTE_NOT_PICKED; vote.notYetPicked = true; @@ -750,15 +1049,13 @@ void Y_StartVote(void) { vote.players[i].selection = 0; vote.players[i].delay = 0; - vote.players[i].catcher.x = 10*FRACUNIT + (72*FRACUNIT/2); - vote.players[i].catcher.y = 144*FRACUNIT + (48*FRACUNIT/2); } - vote.ranim = 0; - vote.rtics = 1; - vote.roffset = 0; - vote.rsynctime = 0; - vote.rendoff = 0; + vote.roulette.anim = 0; + vote.roulette.tics = 0; + vote.roulette.offset = 0; + vote.roulette.endOffset = 0; + vote.roulette.syncTime = 0; for (i = 0; i < MAXPLAYERS; i++) { @@ -801,6 +1098,8 @@ void Y_StartVote(void) vote_draw.levels[i].str[sizeof vote_draw.levels[i].str - 1] = '\0'; } + vote_draw.selectTransition = FRACUNIT; + vote.loaded = true; Automate_Run(AEV_VOTESTART); } @@ -881,7 +1180,7 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level) SINT8 votecompare = VOTE_NOT_PICKED; INT32 endtype = VOTE_END_IMMEDIATE; - vote.rsynctime = 0; + vote.roulette.syncTime = 0; for (i = 0; i < MAXPLAYERS; i++) { @@ -920,6 +1219,7 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level) G_AfterIntermission(); return; } + /* case VOTE_END_QUICK: { // Only one unique vote, so just end it immediately. @@ -928,6 +1228,7 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level) Y_VoteStops(pick, level); break; } + */ default: { S_ChangeMusicInternal("voteea", true); @@ -938,5 +1239,5 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level) vote.deferredLevel = level; g_pickedVote = pick; - vote.timer = 0; + vote.timer = -1; } diff --git a/src/k_vote.h b/src/k_vote.h index 6705c994a..bf45c7688 100644 --- a/src/k_vote.h +++ b/src/k_vote.h @@ -24,7 +24,9 @@ extern "C" { #define VOTE_MOD_ENCORE (0x01) -boolean Y_PlayerIDCanVote(const UINT8 id); +boolean Y_PlayerIDCanVote(const UINT8 playerId); +void Y_SetPlayersVote(const UINT8 playerId, SINT8 vote); + void Y_VoteDrawer(void); void Y_VoteTicker(void); void Y_StartVote(void); diff --git a/src/v_video.cpp b/src/v_video.cpp index 674f7a3b5..f38e18616 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1307,7 +1307,7 @@ void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, U h *= dupy; // Center it if necessary - // adjustxy + V_AdjustXYWithSnap(&x, &y, c, dupx, dupy); } if (x >= vid.width || y >= vid.height) From 81871bc73b08d6a3d2d84379729e69d09ad01c66 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 4 Apr 2023 23:22:12 -0400 Subject: [PATCH 20/31] Rewrite random map buffer Each map now just has a countdown for when they'll reappear (stored in mapheader), which gets decremented each time a new map is played. This means it's now compatible across gametype switches, is a lot less complex, and is easy to retrieve the value for a specific map without needing to iterate constantly. Lots of the old unused code surrounding this function was also removed. Lastly, added a PARANOIA check for callAgainSoon being mishandled. --- src/d_netcmd.c | 14 ++- src/doomstat.h | 2 + src/f_finale.c | 2 +- src/g_game.c | 237 ++++++++++++++++++++--------------------------- src/g_game.h | 2 +- src/k_menudraw.c | 14 +-- src/k_vote.c | 2 +- 7 files changed, 123 insertions(+), 150 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index f70f556ae..65f59c5c4 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2617,15 +2617,23 @@ void D_SetupVote(void) { UINT8 buf[(VOTE_NUM_LEVELS * 2) + 2]; // four UINT16 maps (at twice the width of a UINT8), and two gametypes UINT8 *p = buf; + INT32 i; - INT16 votebuffer[VOTE_NUM_LEVELS] = {-1}; + + INT16 votebuffer[VOTE_NUM_LEVELS + 1] = {-1}; + votebuffer[VOTE_NUM_LEVELS] = 0; // End marker for G_RandMap WRITEUINT8(p, ((cv_kartencore.value == 1) && (gametyperules & GTR_ENCORE))); WRITEUINT8(p, G_SometimesGetDifferentEncore()); for (i = 0; i < VOTE_NUM_LEVELS; i++) { - UINT16 m = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, true, votebuffer); + UINT16 m = G_RandMap( + G_TOLFlag(gametype), + prevmap, false, + (i < VOTE_NUM_LEVELS-1), + votebuffer + ); votebuffer[i] = m; WRITEUINT16(p, m); } @@ -3202,7 +3210,7 @@ static void Command_RandomMap(void) oldmapnum = -1; } - newmapnum = G_RandMap(G_TOLFlag(newgametype), oldmapnum, 0, 0, false, NULL) + 1; + newmapnum = G_RandMap(G_TOLFlag(newgametype), oldmapnum, false, false, NULL) + 1; D_MapChange(newmapnum, newgametype, newencore, newresetplayers, 0, false, false); } diff --git a/src/doomstat.h b/src/doomstat.h index fd74129dc..80d7f3635 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -410,6 +410,8 @@ struct mapheader_t cupheader_t *cup; ///< Cached cup + size_t justPlayed; ///< Prevent this map from showing up in votes if it was recently picked. + // Titlecard information char lvlttl[22]; ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway) char subttl[33]; ///< Subtitle for level diff --git a/src/f_finale.c b/src/f_finale.c index 1d18eb9d2..281786109 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2250,7 +2250,7 @@ void F_TitleScreenTicker(boolean run) // prevent console spam if failed demoIdleLeft = demoIdleTime; - mapnum = G_RandMap(TOL_RACE|TOL_BATTLE, -2, 2, 0, false, NULL); + mapnum = G_RandMap(TOL_RACE|TOL_BATTLE, -2, true, false, NULL); if (mapnum == 0) // gotta have ONE { return; diff --git a/src/g_game.c b/src/g_game.c index 02c3cc682..1627c996d 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -319,23 +319,6 @@ boolean comebackshowninfo; // Have you already seen the "ATTACK OR PROTECT" mess tic_t curlap; // Current lap time tic_t bestlap; // Best lap time -typedef struct -{ - INT16 *mapbuffer; // Pointer to zone memory - INT32 lastnummapheaders; // Reset if nummapheaders != this -} randmaps_t; -static randmaps_t randmaps = {NULL, 0}; - -static void G_ResetRandMapBuffer(void) -{ - INT32 i; - Z_Free(randmaps.mapbuffer); - randmaps.lastnummapheaders = nummapheaders; - randmaps.mapbuffer = Z_Malloc(randmaps.lastnummapheaders * sizeof(INT16), PU_STATIC, NULL); - for (i = 0; i < randmaps.lastnummapheaders; i++) - randmaps.mapbuffer[i] = -1; -} - typedef struct joystickvector2_s { INT32 xaxis; @@ -3726,188 +3709,170 @@ static INT32 TOLMaps(UINT8 pgametype) * has those flags. * \author Graue */ -static INT16 *okmaps = NULL; -INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, UINT8 ignorebuffer, UINT8 maphell, boolean callagainsoon, INT16 *extbuffer) +static INT16 *g_allowedMaps = NULL; + +#ifdef PARANOIA +static INT32 g_randMapStack = 0; +#endif + +INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, INT16 *extBuffer) { - UINT32 numokmaps = 0; - INT16 ix, bufx; - UINT16 extbufsize = 0; + INT32 allowedMapsCount = 0; + INT32 extBufferCount = 0; + INT16 ret = 0; + INT32 i, j; - if (randmaps.lastnummapheaders != nummapheaders) +#ifdef PARANOIA + g_randMapStack++; +#endif + + if (g_allowedMaps == NULL) { - G_ResetRandMapBuffer(); + g_allowedMaps = Z_Malloc(nummapheaders * sizeof(INT16), PU_STATIC, NULL); } - if (!okmaps) + if (extBuffer != NULL) { - //CONS_Printf("(making okmaps)\n"); - okmaps = Z_Malloc(nummapheaders * sizeof(INT16), PU_STATIC, NULL); - } - - if (extbuffer != NULL) - { - bufx = 0; - - while (extbuffer[bufx]) + for (i = 0; extBuffer[i] != 0; i++) { - extbufsize++; - bufx++; + extBufferCount++; } } -tryagain: +tryAgain: - // Find all the maps that are ok and and put them in an array. - for (ix = 0; ix < nummapheaders; ix++) + for (i = 0; i < nummapheaders; i++) { - boolean isokmap = true; - - if (!mapheaderinfo[ix] || mapheaderinfo[ix]->lumpnum == LUMPERROR) + if (mapheaderinfo[i] == NULL || mapheaderinfo[i]->lumpnum == LUMPERROR) { + // Doesn't exist? continue; } - if (!(mapheaderinfo[ix]->typeoflevel & tolflags) - || ix == pprevmap - || M_MapLocked(ix+1) - || (mapheaderinfo[ix]->menuflags & LF2_HIDEINMENU)) // this is bad + if (i == pprevmap) { - continue; //isokmap = false; + // We were just here. + continue; + } + + if ((mapheaderinfo[i]->typeoflevel & tolflags) == 0) + { + // Doesn't match our gametype. + continue; } if (pprevmap == -2 // title demo hack - && mapheaderinfo[ix]->ghostCount == 0) + && mapheaderinfo[i]->ghostCount == 0) { + // Doesn't have any ghosts, so it's not suitable for title demos. continue; } - if (!ignorebuffer) + if ((mapheaderinfo[i]->menuflags & LF2_HIDEINMENU) == LF2_HIDEINMENU) { - if (extbufsize > 0) + // Not intended to be accessed in multiplayer. + continue; + } + + if (M_MapLocked(i + 1) == true) + { + // We haven't earned this one. + continue; + } + + if (ignoreBuffers == false) + { + if (mapheaderinfo[i]->justPlayed > 0) { - for (bufx = 0; bufx < extbufsize; bufx++) + // We just played this map, don't play it again. + continue; + } + + if (extBufferCount > 0) + { + // An optional additional buffer, + // to avoid duplicates on the voting screen. + for (j = 0; j < extBufferCount; j++) { - if (extbuffer[bufx] == -1) // Rest of buffer SHOULD be empty + if (extBuffer[j] < 0 || extBuffer[j] >= nummapheaders) { + // Rest of buffer SHOULD be empty. break; } - if (ix == extbuffer[bufx]) + if (i == extBuffer[j]) { - isokmap = false; + // Map is in this other buffer, don't duplicate. break; } } - if (!isokmap) + if (j < extBufferCount) { + // Didn't make it out of this buffer, so don't add this map. continue; } } - - for (bufx = 0; bufx < (maphell ? 3 : randmaps.lastnummapheaders); bufx++) - { - if (randmaps.mapbuffer[bufx] == -1) // Rest of buffer SHOULD be empty - { - break; - } - - if (ix == randmaps.mapbuffer[bufx]) - { - isokmap = false; - break; - } - } - - if (!isokmap) - continue; } - okmaps[numokmaps++] = ix; + // Got past the gauntlet, so we can allow this one. + g_allowedMaps[ allowedMapsCount++ ] = i; } - if (numokmaps == 0) // If there's no matches... (Goodbye, incredibly silly function chains :V) + if (allowedMapsCount == 0) { - if (!ignorebuffer) + // No maps are available. + if (ignoreBuffers == false) { - if (randmaps.mapbuffer[VOTE_NUM_LEVELS] == -1) // Is the buffer basically empty? - { - ignorebuffer = 1; // This will probably only help in situations where there's very few maps, but it's folly not to at least try it - //CONS_Printf("RANDMAP - ignoring buffer\n"); - goto tryagain; - } - - for (bufx = VOTE_NUM_LEVELS; bufx < randmaps.lastnummapheaders; bufx++) // Let's clear all but the three most recent maps... - { - randmaps.mapbuffer[bufx] = -1; - } - - //CONS_Printf("RANDMAP - emptying randmapbuffer\n"); - goto tryagain; + // Try again with ignoring the buffer before giving up. + ignoreBuffers = true; + goto tryAgain; } - //CONS_Printf("RANDMAP - defaulting to map01\n"); - ix = 0; // Sorry, none match. You get MAP01. - - if (ignorebuffer == 1) - { - //CONS_Printf("(emptying randmapbuffer entirely)\n"); - for (bufx = 0; bufx < randmaps.lastnummapheaders; bufx++) - { - randmaps.mapbuffer[bufx] = -1; // if we're having trouble finding a map we should probably clear it - } - } + // Nothing else actually worked. Welp! + // You just get whatever was added first. + ret = 0; } else { - //CONS_Printf("RANDMAP - %d maps available to grab\n", numokmaps); - ix = okmaps[M_RandomKey(numokmaps)]; + ret = g_allowedMaps[ M_RandomKey(allowedMapsCount) ]; } - if (!callagainsoon) + if (callAgainSoon == false) { - //CONS_Printf("(freeing okmaps)\n"); - Z_Free(okmaps); - okmaps = NULL; + Z_Free(g_allowedMaps); + g_allowedMaps = NULL; + +#ifdef PARANOIA + // Crash if callAgainSoon was mishandled. + I_Assert(g_randMapStack == 1); +#endif } - return ix; +#ifdef PARANOIA + g_randMapStack--; +#endif + + return ret; } void G_AddMapToBuffer(INT16 map) { - INT16 bufx; - INT16 refreshnum = (TOLMaps(gametype)) - VOTE_NUM_LEVELS; - - if (refreshnum < 0) + if (mapheaderinfo[map]->justPlayed == 0) // Started playing a new map. { - refreshnum = 0; - } - - if (nummapheaders != randmaps.lastnummapheaders) - { - G_ResetRandMapBuffer(); - } - else - { - for (bufx = randmaps.lastnummapheaders - 1; bufx > 0; bufx--) + // Decrement every maps' justPlayed value. + INT32 i; + for (i = 0; i < nummapheaders; i++) { - randmaps.mapbuffer[bufx] = randmaps.mapbuffer[bufx-1]; + if (mapheaderinfo[i]->justPlayed > 0) + { + mapheaderinfo[i]->justPlayed--; + } } } - randmaps.mapbuffer[0] = map; - - // We're getting pretty full, so lets flush this for future usage. - if (randmaps.mapbuffer[refreshnum] != -1) - { - // Clear all but the most recent maps. - for (bufx = VOTE_NUM_LEVELS; bufx < randmaps.lastnummapheaders; bufx++) - { - randmaps.mapbuffer[bufx] = -1; - } - //CONS_Printf("Random map buffer has been flushed.\n"); - } + // Set our map's justPlayed value. + mapheaderinfo[map]->justPlayed = TOLMaps(gametype) - VOTE_NUM_LEVELS; } // @@ -4234,7 +4199,7 @@ static void G_GetNextMap(void) } /* FALLTHRU */ case 2: // Go to random map. - nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, false, NULL); + nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, false, false, NULL); break; default: if (nextmap >= NEXTMAP_SPECIAL) // Loop back around @@ -5394,8 +5359,6 @@ void G_DeferedInitNew(boolean pencoremode, INT32 map, INT32 pickedchar, UINT8 ss G_FreeGhosts(); // TODO: do we actually need to do this? - G_ResetRandMapBuffer(); - // this leave the actual game if needed SV_StartSinglePlayerServer(gametype, false); diff --git a/src/g_game.h b/src/g_game.h index 90c19f440..46c93a5c1 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -255,7 +255,7 @@ FUNCMATH INT32 G_TicsToMilliseconds(tic_t tics); UINT32 G_TOLFlag(INT32 pgametype); INT16 G_GetFirstMapOfGametype(UINT8 pgametype); -INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, UINT8 ignorebuffer, UINT8 maphell, boolean callagainsoon, INT16 *extbuffer); +INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, INT16 *extBuffer); void G_AddMapToBuffer(INT16 map); #ifdef __cplusplus diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 3b63a5b97..c8c78f10d 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -5282,7 +5282,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) static UINT16 encoremapcache = NEXTMAP_INVALID; if (encoremapcache > nummapheaders) { - encoremapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, 2, 0, false, NULL); + encoremapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, true, false, NULL); } specialmap = encoremapcache; break; @@ -5292,7 +5292,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) static UINT16 tamapcache = NEXTMAP_INVALID; if (tamapcache > nummapheaders) { - tamapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, 2, 0, false, NULL); + tamapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, true, false, NULL); } specialmap = tamapcache; break; @@ -5302,7 +5302,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) static UINT16 btcmapcache = NEXTMAP_INVALID; if (btcmapcache > nummapheaders) { - btcmapcache = G_RandMap(G_TOLFlag(GT_BATTLE), -1, 2, 0, false, NULL); + btcmapcache = G_RandMap(G_TOLFlag(GT_BATTLE), -1, true, false, NULL); } specialmap = btcmapcache; break; @@ -5312,7 +5312,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) static UINT16 sscmapcache = NEXTMAP_INVALID; if (sscmapcache > nummapheaders) { - sscmapcache = G_RandMap(G_TOLFlag(GT_SPECIAL), -1, 2, 0, false, NULL); + sscmapcache = G_RandMap(G_TOLFlag(GT_SPECIAL), -1, true, false, NULL); } specialmap = sscmapcache; break; @@ -5322,7 +5322,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) static UINT16 spbmapcache = NEXTMAP_INVALID; if (spbmapcache > nummapheaders) { - spbmapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, 2, 0, false, NULL); + spbmapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, true, false, NULL); } specialmap = spbmapcache; break; @@ -5332,7 +5332,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) static UINT16 hardmapcache = NEXTMAP_INVALID; if (hardmapcache > nummapheaders) { - hardmapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, 2, 0, false, NULL); + hardmapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, true, false, NULL); } specialmap = hardmapcache; break; @@ -5342,7 +5342,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) static UINT16 mastermapcache = NEXTMAP_INVALID; if (mastermapcache > nummapheaders) { - mastermapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, 2, 0, false, NULL); + mastermapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, true, false, NULL); } specialmap = mastermapcache; break; diff --git a/src/k_vote.c b/src/k_vote.c index b5eefe7a9..1fe45dd23 100644 --- a/src/k_vote.c +++ b/src/k_vote.c @@ -76,7 +76,7 @@ #define BULB_FRAMES (4) #define CATCHER_SPEED (8*FRACUNIT) -#define CATCHER_Y_OFFSET (32*FRACUNIT) +#define CATCHER_Y_OFFSET (48*FRACUNIT) #define CATCHER_OFFSCREEN (-CATCHER_Y_OFFSET * 2) #define SELECTION_WIDTH (72*FRACUNIT) From 63fdd48b8fd0e6dca7d6ee98a07baddefc70e1c7 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Thu, 6 Apr 2023 02:23:43 -0400 Subject: [PATCH 21/31] Implement BG catchers --- src/k_vote.c | 729 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 514 insertions(+), 215 deletions(-) diff --git a/src/k_vote.c b/src/k_vote.c index 1fe45dd23..4af47426c 100644 --- a/src/k_vote.c +++ b/src/k_vote.c @@ -79,6 +79,8 @@ #define CATCHER_Y_OFFSET (48*FRACUNIT) #define CATCHER_OFFSCREEN (-CATCHER_Y_OFFSET * 2) +#define CATCHER_Y_OFFSET_SMALL (CATCHER_Y_OFFSET / 2) + #define SELECTION_WIDTH (72*FRACUNIT) #define SELECTION_HEIGHT ((SELECTION_WIDTH * BASEVIDHEIGHT) / BASEVIDWIDTH) #define SELECTION_X (10*FRACUNIT + (SELECTION_WIDTH >> 1)) @@ -88,6 +90,14 @@ #define SELECTION_SPACING_H (SELECTION_HEIGHT + SELECTION_SPACE) #define SELECTION_HOP (10*FRACUNIT) +#define PILE_WIDTH (46*FRACUNIT) +#define PILE_HEIGHT ((PILE_WIDTH * BASEVIDHEIGHT) / BASEVIDWIDTH) +#define PILE_SPACE (4*FRACUNIT) +#define PILE_SPACING_W (PILE_WIDTH + PILE_SPACE) +#define PILE_SPACING_H (PILE_HEIGHT + PILE_SPACE) + +//#define TEST_VOTES (11) + // Catcher data enum { @@ -117,6 +127,8 @@ typedef struct SINT8 level; UINT8 player; + + fixed_t anim; // UI scope variable } y_vote_catcher; // Clientside & splitscreen player info. @@ -177,10 +189,10 @@ typedef struct patch_t *bg_levelText; patch_t *bg_derrText; - patch_t *catcher_ufo; - patch_t *catcher_arms[ARM_FRAMES]; - patch_t *catcher_pole; - patch_t *catcher_bulb[BULB_FRAMES]; + patch_t *catcher_ufo[2]; + patch_t *catcher_arms[2][ARM_FRAMES]; + patch_t *catcher_pole[2]; + patch_t *catcher_bulb[2][BULB_FRAMES]; fixed_t selectTransition; y_vote_draw_level levels[VOTE_NUM_LEVELS]; @@ -207,8 +219,111 @@ boolean Y_PlayerIDCanVote(const UINT8 playerId) return true; } +static void Y_SortPile(void) +{ + UINT8 numVotes = 0; + UINT8 votesLeft = 0; + INT32 i; + +#ifdef TEST_VOTES + numVotes = TEST_VOTES; +#else + for (i = 0; i < MAXPLAYERS; i++) + { + if (g_votes[i] == VOTE_NOT_PICKED) + { + continue; + } + + numVotes++; + } +#endif + + if (numVotes == 0) + { + return; + } + + votesLeft = numVotes; + + for (i = 0; i < MAXPLAYERS; i++) + { + y_vote_pile *const pile = &vote.roulette.pile[i]; + +#ifndef TEST_VOTES + if (g_votes[i] == VOTE_NOT_PICKED) + { + continue; + } +#endif + + // Just center it for now. + pile->destX = BASEVIDWIDTH << FRACBITS >> 1; + pile->destY = BASEVIDHEIGHT << FRACBITS >> 1; + + if (numVotes <= 1) + { + ; // NOP + } + else if (numVotes == 2) + { + // Offset just a bit from the center. + if (votesLeft <= 1) + { + pile->destX += PILE_SPACING_W >> 1; + } + else + { + pile->destX -= PILE_SPACING_W >> 1; + } + } + else if (numVotes <= 12) + { + const boolean odd = ((numVotes % 2) != 0); + UINT8 rowSize = (numVotes + 1) / 2; + INT32 xOffset = 0; + + if (votesLeft > rowSize) + { + if (odd == true) + { + rowSize--; + } + + const SINT8 topRowIndex = (rowSize - ((votesLeft - 1) % rowSize)) - 1; + xOffset = -(rowSize - 1) + (topRowIndex << 1); + + pile->destY -= PILE_SPACING_H >> 1; + } + else + { + const SINT8 botRowIndex = votesLeft - 1; + xOffset = -(rowSize - 1) + (botRowIndex << 1); + + pile->destY += PILE_SPACING_H >> 1; + } + + pile->destX += (PILE_SPACING_W >> 1) * xOffset; + } + else + { + // TODO: 13+ votes + } + + votesLeft--; + + if (votesLeft == 0) + { + break; + } + } +} + void Y_SetPlayersVote(const UINT8 playerId, SINT8 newVote) { + y_vote_pile *const pile = &vote.roulette.pile[playerId]; + y_vote_catcher *const catcher = &pile->catcher; + if (gamestate != GS_VOTING) { return; @@ -221,6 +336,19 @@ void Y_SetPlayersVote(const UINT8 playerId, SINT8 newVote) g_votes[playerId] = newVote; + Y_SortPile(); + + pile->x = pile->destX; + pile->y = pile->destY; + + catcher->action = CATCHER_BG_LOWER; + + catcher->x = catcher->destX = pile->x; + catcher->y = CATCHER_OFFSCREEN; + catcher->destY = pile->y; + catcher->spr = ARM_FRAMES-1; + catcher->level = g_votes[playerId]; + #ifdef VOTE_TIME_WAIT_FOR_VOTE if (vote.timer == -1) { @@ -321,7 +449,7 @@ static void Y_DrawCatcher(y_vote_catcher *catcher) SKINCOLOR_LILAC, }; - static fixed_t anim = 0; + const UINT8 sizeOffset = (catcher->small == true) ? 1 : 0; tic_t colorTic = 0; fixed_t baseX = INT32_MAX; @@ -337,14 +465,14 @@ static void Y_DrawCatcher(y_vote_catcher *catcher) return; } - anim += renderdeltatics; - colorTic = (anim / 3) / FRACUNIT; + catcher->anim += renderdeltatics; + colorTic = (catcher->anim / 3) / FRACUNIT; baseX = catcher->x; if (catcher->action == CATCHER_FG_STRUGGLE) { - if ((anim / FRACUNIT) & 1) + if ((catcher->anim / FRACUNIT) & 1) { baseX += FRACUNIT; } @@ -354,8 +482,8 @@ static void Y_DrawCatcher(y_vote_catcher *catcher) } } - x = baseX - (vote_draw.catcher_ufo->width * FRACUNIT / 2); - y = catcher->y - (vote_draw.catcher_ufo->height * FRACUNIT) + CATCHER_Y_OFFSET; + x = baseX - (vote_draw.catcher_ufo[sizeOffset]->width * FRACUNIT / 2); + y = catcher->y - (vote_draw.catcher_ufo[sizeOffset]->height * FRACUNIT) + ((catcher->small == true) ? CATCHER_Y_OFFSET_SMALL : CATCHER_Y_OFFSET); craneColor = R_GetTranslationColormap(TC_DEFAULT, ufoColors[colorTic % NUM_UFO_COLORS], GTC_MENUCACHE); bulbColor = R_GetTranslationColormap(TC_DEFAULT, bulbColors[(colorTic / BULB_FRAMES) % NUM_BULB_COLORS], GTC_MENUCACHE); @@ -364,7 +492,7 @@ static void Y_DrawCatcher(y_vote_catcher *catcher) { Y_DrawVoteThumbnail( baseX, catcher->y, - SELECTION_WIDTH, 0, + ((catcher->small == true) ? PILE_WIDTH : SELECTION_WIDTH), 0, catcher->level, false ); } @@ -372,28 +500,28 @@ static void Y_DrawCatcher(y_vote_catcher *catcher) V_DrawFixedPatch( x, y, FRACUNIT, 0, - vote_draw.catcher_arms[catcher->spr % ARM_FRAMES], + vote_draw.catcher_arms[sizeOffset][catcher->spr % ARM_FRAMES], craneColor ); V_DrawFixedPatch( x, y, FRACUNIT, 0, - vote_draw.catcher_bulb[colorTic % BULB_FRAMES], + vote_draw.catcher_bulb[sizeOffset][colorTic % BULB_FRAMES], bulbColor ); V_DrawFixedPatch( x, y, FRACUNIT, 0, - vote_draw.catcher_ufo, + vote_draw.catcher_ufo[sizeOffset], craneColor ); V_DrawFixedPatch( x, y, FRACUNIT, 0, - vote_draw.catcher_pole, + vote_draw.catcher_pole[sizeOffset], NULL ); #undef NUM_UFO_COLORS @@ -554,7 +682,41 @@ static void Y_DrawVoteSelection(fixed_t offset) static void Y_DrawVotePile(void) { - // TODO + INT32 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + y_vote_pile *const pile = &vote.roulette.pile[i]; + y_vote_catcher *const catcher = &pile->catcher; + + if (catcher->level != VOTE_NOT_PICKED) + { + continue; + } + +#ifndef TEST_VOTES + if (g_votes[i] == VOTE_NOT_PICKED) + { + continue; + } +#endif + + Y_DrawVoteThumbnail( + pile->x, pile->y, + PILE_WIDTH, 0, +#ifdef TEST_VOTES + 0, +#else + g_votes[i], +#endif + (i != vote.roulette.anim || g_pickedVote == VOTE_NOT_PICKED) + ); + } + + for (i = 0; i < MAXPLAYERS; i++) + { + Y_DrawCatcher(&vote.roulette.pile[i].catcher); + } } void Y_VoteDrawer(void) @@ -584,10 +746,13 @@ void Y_VoteDrawer(void) vote_draw.ruby_height = FINESINE(rubyFloatTime >> ANGLETOFINESHIFT); rubyFloatTime += FixedMul(ANGLE_MAX / NEWTICRATE, renderdeltatics); - vote_draw.selectTransition += FixedMul( - (((g_pickedVote != VOTE_NOT_PICKED) ? FRACUNIT : 0) - vote_draw.selectTransition) / 2, - renderdeltatics - ); + if (vote.loaded == true) + { + vote_draw.selectTransition += FixedMul( + (((g_pickedVote != VOTE_NOT_PICKED) ? FRACUNIT : 0) - vote_draw.selectTransition) / 2, + renderdeltatics + ); + } Y_DrawVoteBackground(); Y_DrawVotePile(); @@ -644,11 +809,8 @@ static void Y_PlayerSendVote(const UINT8 localPlayer) S_StartSound(NULL, sfx_kc37); } -static void Y_TickPlayerCatcher(const UINT8 localPlayer) +static boolean Y_TickGenericCatcher(y_vote_catcher *const catcher) { - y_vote_player *const player = &vote.players[localPlayer]; - y_vote_catcher *const catcher = &player->catcher; - fixed_t spd = CATCHER_SPEED; fixed_t xDelta = catcher->destX - catcher->x; @@ -696,6 +858,19 @@ static void Y_TickPlayerCatcher(const UINT8 localPlayer) if (catcher->delay > 0) { catcher->delay--; + return false; + } + + return true; +} + +static void Y_TickPlayerCatcher(const UINT8 localPlayer) +{ + y_vote_player *const player = &vote.players[localPlayer]; + y_vote_catcher *const catcher = &player->catcher; + + if (Y_TickGenericCatcher(catcher) == false) + { return; } @@ -761,6 +936,278 @@ static void Y_TickPlayerCatcher(const UINT8 localPlayer) } } +static void Y_TickPileCatcher(const UINT8 playerId) +{ + y_vote_pile *const pile = &vote.roulette.pile[playerId]; + y_vote_catcher *const catcher = &pile->catcher; + + if (Y_TickGenericCatcher(catcher) == false) + { + return; + } + + switch (catcher->action) + { + case CATCHER_BG_LOWER: + { + if (catcher->x == catcher->destX && catcher->y == catcher->destY) + { + catcher->level = VOTE_NOT_PICKED; + catcher->action++; + } + break; + } + + case CATCHER_BG_RELEASE: + { + catcher->spr--; + + if (catcher->spr == 0) + { + catcher->destY = CATCHER_OFFSCREEN; + catcher->action = CATCHER_BG_RISE; + } + break; + } + + case CATCHER_BG_RISE: + { + if (catcher->x == catcher->destX && catcher->y == catcher->destY) + { + catcher->action = CATCHER_NA; + } + break; + } + + default: + { + catcher->action = CATCHER_NA; + break; + } + } +} + +static void Y_TickPlayerPile(const UINT8 playerId) +{ + y_vote_pile *const pile = &vote.roulette.pile[playerId]; + y_vote_catcher *const catcher = &pile->catcher; + + fixed_t movedX = 0; + fixed_t movedY = 0; + +#ifndef TEST_VOTES + if (g_votes[playerId] == VOTE_NOT_PICKED) + { + catcher->action = CATCHER_NA; + return; + } +#endif + + movedX = (pile->destX - pile->x) / 2; + movedY = (pile->destY - pile->y) / 2; + + if (movedX != 0 || movedY != 0) + { + pile->x += movedX; + pile->y += movedY; + + catcher->x += movedX; + catcher->y += movedY; + + catcher->destX += movedX; + catcher->destY += movedY; + } + + Y_TickPileCatcher(playerId); +} + +static void Y_TickVoteRoulette(void) +{ + INT32 i; + + vote.timer = 0; + vote.roulette.syncTime++; + + if (vote.endtic == -1) + { + UINT8 tempvotes[MAXPLAYERS]; + UINT8 numvotes = 0; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (g_votes[i] == VOTE_NOT_PICKED) + { + continue; + } + + tempvotes[numvotes] = i; + numvotes++; + } + + if (numvotes < 1) // Whoops! Get outta here. + { + Y_EndVote(); + G_AfterIntermission(); + return; + } + + if (vote.roulette.tics > 0) + { + vote.roulette.tics--; + } + else + { + vote.roulette.offset++; + vote.roulette.tics = min(6, 9 * vote.roulette.offset / 40); + S_StartSound(NULL, sfx_kc39); + } + + if (vote.roulette.endOffset == 0 || vote.roulette.offset < vote.roulette.endOffset) + { + vote.roulette.anim = tempvotes[((g_pickedVote + vote.roulette.offset) % numvotes)]; + } + + if (vote.roulette.offset > 30) + { + if (vote.roulette.endOffset == 0) + { + if (vote.roulette.syncTime % 51 == 0) // Song is 1.45 seconds long (sorry @ whoever wants to replace it in a music wad :V) + { + for (i = 5; i >= 3; i--) // Find a suitable place to stop + { + if (tempvotes[((g_pickedVote + vote.roulette.offset + i) % numvotes)] == g_pickedVote) + { + vote.roulette.endOffset = vote.roulette.offset + i; + + if (M_RandomChance(FRACUNIT/32)) // Let it cheat occasionally~ + { + vote.roulette.endOffset++; + } + + S_ChangeMusicInternal("voteeb", false); + break; + } + } + } + } + else if (vote.roulette.offset >= vote.roulette.endOffset) + { + vote.endtic = vote.tic + (3*TICRATE); + Y_VoteStops(g_pickedVote, vote.deferredLevel); + } + } + } + else + { + vote.roulette.anim = g_pickedVote; + } +} + +static void Y_TickVoteSelection(void) +{ + INT32 i; + + if (vote.tic < 3*(NEWTICRATE/7)) // give it some time before letting you control it :V + { + return; + } + + /* + The vote ended, but it will take at least a tic for that to reach us from + the server. Don't let me change the vote now, it won't matter anyway! + */ + if (vote.timer != 0) + { + for (i = 0; i <= splitscreen; i++) + { + const UINT8 p = g_localplayers[i]; + boolean moved = false; + + if (vote.players[i].delay) + { + vote.players[i].delay--; + } + + if (Y_PlayerIDCanVote(p) == true + && menuactive == false + && vote.players[i].delay == 0 + && g_pickedVote == VOTE_NOT_PICKED && g_votes[p] == VOTE_NOT_PICKED + && vote.players[i].catcher.action == CATCHER_NA) + { + if (G_PlayerInputDown(i, gc_left, 0)) + { + vote.players[i].selection--; + moved = true; + } + + if (G_PlayerInputDown(i, gc_right, 0)) + { + vote.players[i].selection++; + moved = true; + } + + if (vote.players[i].selection < 0) + { + vote.players[i].selection = VOTE_NUM_LEVELS - 1; + } + + if (vote.players[i].selection >= VOTE_NUM_LEVELS) + { + vote.players[i].selection = 0; + } + + if (G_PlayerInputDown(i, gc_a, 0) && moved == false) + { + Y_PlayerSendVote(i); + moved = true; + } + } + + if (moved) + { + S_StartSound(NULL, sfx_kc4a); + vote.players[i].delay = NEWTICRATE/7; + } + } + } + + if (server) + { + boolean everyone_voted = true;/* the default condition */ + + for (i = 0; i < MAXPLAYERS; i++) + { + if (Y_PlayerIDCanVote(i) == false) + { + continue; + } + + if (g_votes[i] == VOTE_NOT_PICKED) + { + if (vote.timer == 0) + { + g_votes[i] = 3; // RANDOMIZE LATER + } + else + { + everyone_voted = false; + } + } + } + + if (everyone_voted == true) + { + vote.timer = 0; + + if (vote.endtic == -1) + { + vote.notYetPicked = false; /* don't pick vote twice */ + D_PickVote(); + } + } + } +} + // // Y_VoteTicker // @@ -769,7 +1216,6 @@ static void Y_TickPlayerCatcher(const UINT8 localPlayer) void Y_VoteTicker(void) { INT32 i; - boolean everyone_voted; if (paused || P_AutoPause() || vote.loaded == false) { @@ -820,186 +1266,20 @@ void Y_VoteTicker(void) Y_TickPlayerCatcher(i); } + Y_SortPile(); + + for (i = 0; i < MAXPLAYERS; i++) + { + Y_TickPlayerPile(i); + } + if (g_pickedVote != VOTE_NOT_PICKED) { - vote.timer = 0; - vote.roulette.syncTime++; - - if (vote.endtic == -1) - { - UINT8 tempvotes[MAXPLAYERS]; - UINT8 numvotes = 0; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (g_votes[i] == VOTE_NOT_PICKED) - { - continue; - } - - tempvotes[numvotes] = i; - numvotes++; - } - - if (numvotes < 1) // Whoops! Get outta here. - { - Y_EndVote(); - G_AfterIntermission(); - return; - } - - if (vote.roulette.tics > 0) - { - vote.roulette.tics--; - } - else - { - vote.roulette.offset++; - vote.roulette.tics = min(6, 9 * vote.roulette.offset / 40); - S_StartSound(NULL, sfx_kc39); - } - - if (vote.roulette.endOffset == 0 || vote.roulette.offset < vote.roulette.endOffset) - { - vote.roulette.anim = tempvotes[((g_pickedVote + vote.roulette.offset) % numvotes)]; - } - - if (vote.roulette.offset > 40) - { - if (vote.roulette.endOffset == 0) - { - if (vote.roulette.syncTime % 51 == 0) // Song is 1.45 seconds long (sorry @ whoever wants to replace it in a music wad :V) - { - for (i = 5; i >= 3; i--) // Find a suitable place to stop - { - if (tempvotes[((g_pickedVote + vote.roulette.offset + i) % numvotes)] == g_pickedVote) - { - vote.roulette.endOffset = vote.roulette.offset + i; - - if (M_RandomChance(FRACUNIT/32)) // Let it cheat occasionally~ - { - vote.roulette.endOffset++; - } - - S_ChangeMusicInternal("voteeb", false); - break; - } - } - } - } - else if (vote.roulette.offset >= vote.roulette.endOffset) - { - vote.endtic = vote.tic + (3*TICRATE); - Y_VoteStops(g_pickedVote, vote.deferredLevel); - } - } - } - else - { - vote.roulette.anim = g_pickedVote; - } + Y_TickVoteRoulette(); } else if (vote.notYetPicked) { - if (vote.tic < 3*(NEWTICRATE/7)) // give it some time before letting you control it :V - { - return; - } - - /* - The vote ended, but it will take at least a tic for that to reach us from - the server. Don't let me change the vote now, it won't matter anyway! - */ - if (vote.timer != 0) - { - for (i = 0; i <= splitscreen; i++) - { - const UINT8 p = g_localplayers[i]; - boolean moved = false; - - if (vote.players[i].delay) - { - vote.players[i].delay--; - } - - if (Y_PlayerIDCanVote(p) == true - && menuactive == false - && vote.players[i].delay == 0 - && g_pickedVote == VOTE_NOT_PICKED && g_votes[p] == VOTE_NOT_PICKED - && vote.players[i].catcher.action == CATCHER_NA) - { - if (G_PlayerInputDown(i, gc_left, 0)) - { - vote.players[i].selection--; - moved = true; - } - - if (G_PlayerInputDown(i, gc_right, 0)) - { - vote.players[i].selection++; - moved = true; - } - - if (vote.players[i].selection < 0) - { - vote.players[i].selection = VOTE_NUM_LEVELS - 1; - } - - if (vote.players[i].selection >= VOTE_NUM_LEVELS) - { - vote.players[i].selection = 0; - } - - if (G_PlayerInputDown(i, gc_a, 0) && moved == false) - { - Y_PlayerSendVote(i); - moved = true; - } - } - - if (moved) - { - S_StartSound(NULL, sfx_kc4a); - vote.players[i].delay = NEWTICRATE/7; - } - } - } - - if (server) - { - everyone_voted = true;/* the default condition */ - - for (i = 0; i < MAXPLAYERS; i++) - { - if (Y_PlayerIDCanVote(i) == false) - { - continue; - } - - if (g_votes[i] == VOTE_NOT_PICKED) - { - if (vote.timer == 0) - { - g_votes[i] = 3; // RANDOMIZE LATER - } - else - { - everyone_voted = false; - } - } - } - - if (everyone_voted == true) - { - vote.timer = 0; - - if (vote.endtic == -1) - { - vote.notYetPicked = false; /* don't pick vote twice */ - D_PickVote(); - } - } - } + Y_TickVoteSelection(); } } @@ -1025,15 +1305,19 @@ void Y_StartVote(void) vote_draw.bg_levelText = W_CachePatchName("VT_WELC", PU_STATIC); vote_draw.bg_derrText = W_CachePatchName("VT_DERR", PU_STATIC); - vote_draw.catcher_ufo = W_CachePatchName("VT_UFO1", PU_STATIC); + vote_draw.catcher_ufo[0] = W_CachePatchName("VT_UFO1", PU_STATIC); + vote_draw.catcher_ufo[1] = W_CachePatchName("VS_UFO1", PU_STATIC); for (i = 0; i < ARM_FRAMES; i++) { - vote_draw.catcher_arms[i] = W_CachePatchName(va("VT_ARMS%d", i + 1), PU_STATIC); + vote_draw.catcher_arms[0][i] = W_CachePatchName(va("VT_ARMS%d", i + 1), PU_STATIC); + vote_draw.catcher_arms[1][i] = W_CachePatchName(va("VS_ARMS%d", i + 1), PU_STATIC); } - vote_draw.catcher_pole = W_CachePatchName("VT_POLE", PU_STATIC); + vote_draw.catcher_pole[0] = W_CachePatchName("VT_POLE", PU_STATIC); + vote_draw.catcher_pole[1] = W_CachePatchName("VS_POLE", PU_STATIC); for (i = 0; i < BULB_FRAMES; i++) { - vote_draw.catcher_bulb[i] = W_CachePatchName(va("VT_BULB%d", i + 1), PU_STATIC); + vote_draw.catcher_bulb[0][i] = W_CachePatchName(va("VT_BULB%d", i + 1), PU_STATIC); + vote_draw.catcher_bulb[1][i] = W_CachePatchName(va("VS_BULB%d", i + 1), PU_STATIC); } #ifdef VOTE_TIME_WAIT_FOR_VOTE @@ -1047,8 +1331,14 @@ void Y_StartVote(void) for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) { - vote.players[i].selection = 0; - vote.players[i].delay = 0; + y_vote_player *const player = &vote.players[i]; + y_vote_catcher *const catcher = &player->catcher; + + player->selection = 0; + player->delay = 0; + + catcher->action = CATCHER_NA; + catcher->small = false; } vote.roulette.anim = 0; @@ -1059,7 +1349,13 @@ void Y_StartVote(void) for (i = 0; i < MAXPLAYERS; i++) { + y_vote_pile *const pile = &vote.roulette.pile[i]; + y_vote_catcher *const catcher = &pile->catcher; + g_votes[i] = VOTE_NOT_PICKED; + + catcher->action = CATCHER_NA; + catcher->small = true; } for (i = 0; i < VOTE_NUM_LEVELS; i++) @@ -1109,7 +1405,7 @@ void Y_StartVote(void) // static void Y_UnloadVoteData(void) { - INT32 i; + INT32 i, j; vote.loaded = false; @@ -1128,15 +1424,18 @@ static void Y_UnloadVoteData(void) UNLOAD(vote_draw.bg_levelText); UNLOAD(vote_draw.bg_derrText); - UNLOAD(vote_draw.catcher_ufo); - for (i = 0; i < ARM_FRAMES; i++) + for (j = 0; j < 2; j++) { - UNLOAD(vote_draw.catcher_arms[i]); - } - UNLOAD(vote_draw.catcher_pole); - for (i = 0; i < BULB_FRAMES; i++) - { - UNLOAD(vote_draw.catcher_bulb[i]); + UNLOAD(vote_draw.catcher_ufo[j]); + for (i = 0; i < ARM_FRAMES; i++) + { + UNLOAD(vote_draw.catcher_arms[j][i]); + } + UNLOAD(vote_draw.catcher_pole[j]); + for (i = 0; i < BULB_FRAMES; i++) + { + UNLOAD(vote_draw.catcher_bulb[j][i]); + } } } From 11eadd4e75c48a666dc366fa6dc19d40ba345cb8 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 9 Apr 2023 16:58:30 -0400 Subject: [PATCH 22/31] Add player icon to BG votes --- src/k_vote.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/k_vote.c b/src/k_vote.c index 4af47426c..326ac09a4 100644 --- a/src/k_vote.c +++ b/src/k_vote.c @@ -348,6 +348,7 @@ void Y_SetPlayersVote(const UINT8 playerId, SINT8 newVote) catcher->destY = pile->y; catcher->spr = ARM_FRAMES-1; catcher->level = g_votes[playerId]; + catcher->player = playerId; #ifdef VOTE_TIME_WAIT_FOR_VOTE if (vote.timer == -1) @@ -358,7 +359,7 @@ void Y_SetPlayersVote(const UINT8 playerId, SINT8 newVote) #endif } -static void Y_DrawVoteThumbnail(fixed_t x, fixed_t y, fixed_t width, INT32 flags, SINT8 v, boolean dim) +static void Y_DrawVoteThumbnail(fixed_t x, fixed_t y, fixed_t width, INT32 flags, SINT8 v, boolean dim, SINT8 playerID) { const fixed_t height = (width * BASEVIDHEIGHT) / BASEVIDWIDTH; INT32 fx, fy, fw, fh; @@ -427,6 +428,25 @@ static void Y_DrawVoteThumbnail(fixed_t x, fixed_t y, fixed_t width, INT32 flags 31, 5 ); } + + if (playerID >= 0) + { + if (playerID < MAXPLAYERS) + { + UINT8 *playerMap = R_GetTranslationColormap(players[playerID].skin, players[playerID].skincolor, GTC_CACHE); + patch_t *playerPatch = faceprefix[players[playerID].skin][FACE_RANK]; + V_DrawFixedPatch( + x + width - (playerPatch->width * FRACUNIT) + FRACUNIT - 1, + y + height - (playerPatch->height * FRACUNIT) + FRACUNIT, + FRACUNIT, flags, + playerPatch, playerMap + ); + } + else + { + ; // angry level goes here + } + } } static void Y_DrawCatcher(y_vote_catcher *catcher) @@ -493,7 +513,8 @@ static void Y_DrawCatcher(y_vote_catcher *catcher) Y_DrawVoteThumbnail( baseX, catcher->y, ((catcher->small == true) ? PILE_WIDTH : SELECTION_WIDTH), 0, - catcher->level, false + catcher->level, false, + catcher->player ); } @@ -654,7 +675,7 @@ static void Y_DrawVoteSelection(fixed_t offset) Y_DrawVoteThumbnail( x, y - vote_draw.levels[i].hop, SELECTION_WIDTH, flags, - i, (selected == false) + i, (selected == false), -1 ); if (vote_draw.levels[i].encore == true) @@ -709,7 +730,8 @@ static void Y_DrawVotePile(void) #else g_votes[i], #endif - (i != vote.roulette.anim || g_pickedVote == VOTE_NOT_PICKED) + (i != vote.roulette.anim || g_pickedVote == VOTE_NOT_PICKED), + i ); } @@ -1339,6 +1361,7 @@ void Y_StartVote(void) catcher->action = CATCHER_NA; catcher->small = false; + catcher->player = -1; } vote.roulette.anim = 0; @@ -1356,6 +1379,7 @@ void Y_StartVote(void) catcher->action = CATCHER_NA; catcher->small = true; + catcher->player = i; } for (i = 0; i < VOTE_NUM_LEVELS; i++) From 2d8905c8160d3f5712ca9aead35ad9409aa8d994 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 9 Apr 2023 17:14:24 -0400 Subject: [PATCH 23/31] Handle Encore ruby in Y_DrawVoteThumbnail --- src/k_vote.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/k_vote.c b/src/k_vote.c index 326ac09a4..82dd24c10 100644 --- a/src/k_vote.c +++ b/src/k_vote.c @@ -361,6 +361,7 @@ void Y_SetPlayersVote(const UINT8 playerId, SINT8 newVote) static void Y_DrawVoteThumbnail(fixed_t x, fixed_t y, fixed_t width, INT32 flags, SINT8 v, boolean dim, SINT8 playerID) { + const boolean encore = vote_draw.levels[v].encore; const fixed_t height = (width * BASEVIDHEIGHT) / BASEVIDWIDTH; INT32 fx, fy, fw, fh; INT32 dupx, dupy; @@ -414,11 +415,22 @@ static void Y_DrawVoteThumbnail(fixed_t x, fixed_t y, fixed_t width, INT32 flags K_DrawMapThumbnail( x, y, - width, flags, + width, flags | ((encore == true) ? V_FLIP : 0), g_voteLevels[v][0], NULL ); + if (encore == true) + { + V_DrawFixedPatch( + x + (width / 2) - (vote_draw.ruby_icon->width * (FRACUNIT >> 1)), + y + (height / 2) - (vote_draw.ruby_icon->height * (FRACUNIT >> 1)) - (vote_draw.ruby_height << 1), + FRACUNIT, flags, + vote_draw.ruby_icon, + NULL + ); + } + if (dim == true) { V_DrawFadeFill( @@ -662,11 +674,6 @@ static void Y_DrawVoteSelection(fixed_t offset) destHop = SELECTION_HOP; } - if (vote_draw.levels[i].encore == true) - { - flags |= V_FLIP; - } - vote_draw.levels[i].hop += FixedMul( (destHop - vote_draw.levels[i].hop) / 2, renderdeltatics @@ -675,20 +682,10 @@ static void Y_DrawVoteSelection(fixed_t offset) Y_DrawVoteThumbnail( x, y - vote_draw.levels[i].hop, SELECTION_WIDTH, flags, - i, (selected == false), -1 + i, (selected == false), + -1 ); - if (vote_draw.levels[i].encore == true) - { - V_DrawFixedPatch( - x - (vote_draw.ruby_icon->width * (FRACUNIT >> 1)), - y - (vote_draw.ruby_icon->height * (FRACUNIT >> 1)) - (vote_draw.ruby_height << 1), - FRACUNIT, (flags & ~V_FLIP), - vote_draw.ruby_icon, - NULL - ); - } - x += SELECTION_SPACING_W; } From 505595b5d899c2b03e6c5a1e595d89be097c1717 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 9 Apr 2023 17:42:46 -0400 Subject: [PATCH 24/31] Fix ruby scale & position on vote screen --- src/k_vote.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/k_vote.c b/src/k_vote.c index 82dd24c10..30e865fe1 100644 --- a/src/k_vote.c +++ b/src/k_vote.c @@ -359,10 +359,12 @@ void Y_SetPlayersVote(const UINT8 playerId, SINT8 newVote) #endif } -static void Y_DrawVoteThumbnail(fixed_t x, fixed_t y, fixed_t width, INT32 flags, SINT8 v, boolean dim, SINT8 playerID) +static void Y_DrawVoteThumbnail(fixed_t center_x, fixed_t center_y, fixed_t width, INT32 flags, SINT8 v, boolean dim, SINT8 playerID) { const boolean encore = vote_draw.levels[v].encore; const fixed_t height = (width * BASEVIDHEIGHT) / BASEVIDWIDTH; + const fixed_t x = center_x - (width >> 1); + const fixed_t y = center_y - (height >> 1); INT32 fx, fy, fw, fh; INT32 dupx, dupy; @@ -371,9 +373,6 @@ static void Y_DrawVoteThumbnail(fixed_t x, fixed_t y, fixed_t width, INT32 flags return; } - x -= width / 2; - y -= height / 2; - dupx = vid.dupx; dupy = vid.dupy; @@ -422,10 +421,10 @@ static void Y_DrawVoteThumbnail(fixed_t x, fixed_t y, fixed_t width, INT32 flags if (encore == true) { + const fixed_t rubyScale = width / 72; V_DrawFixedPatch( - x + (width / 2) - (vote_draw.ruby_icon->width * (FRACUNIT >> 1)), - y + (height / 2) - (vote_draw.ruby_icon->height * (FRACUNIT >> 1)) - (vote_draw.ruby_height << 1), - FRACUNIT, flags, + center_x, center_y - FixedMul(vote_draw.ruby_height << 1, rubyScale), + rubyScale, flags, vote_draw.ruby_icon, NULL ); From 95540888ce25abdcd3ecc1da522492b3d19044d4 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 9 Apr 2023 20:53:49 -0400 Subject: [PATCH 25/31] Handle timed out votes properly again Instead of picking random, we ask the client for what their cursor is on. If it takes too long to arrive, then we ignore their vote. Also: fixed a crash if the nextmap was never set during voting (can happen via many 0-players fallbacks, and especially now that it needs to check for client responses on a time out), by always initializing to the first map in the vote. --- src/d_netcmd.c | 3 +- src/k_vote.c | 278 ++++++++++++++++++++++++++++--------------------- 2 files changed, 163 insertions(+), 118 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 65f59c5c4..87219af7f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2687,10 +2687,9 @@ void D_PickVote(void) } } - key = M_RandomKey(numvotes); - if (numvotes > 0) { + key = M_RandomKey(numvotes); WRITESINT8(p, temppicks[key]); WRITESINT8(p, templevels[key]); } diff --git a/src/k_vote.c b/src/k_vote.c index 30e865fe1..8db929bb6 100644 --- a/src/k_vote.c +++ b/src/k_vote.c @@ -96,6 +96,10 @@ #define PILE_SPACING_W (PILE_WIDTH + PILE_SPACE) #define PILE_SPACING_H (PILE_HEIGHT + PILE_SPACE) +// Give time for the animations to finish before finalizing the vote stages. +#define SELECT_DELAY_TIME (TICRATE*4) +#define PICK_DELAY_TIME (TICRATE/2) + //#define TEST_VOTES (11) // Catcher data @@ -137,6 +141,7 @@ typedef struct y_vote_catcher catcher; SINT8 selection; UINT8 delay; + boolean sentTimeOutVote; } y_vote_player; // Vote "pile" data. Objects for each vote scattered about. @@ -163,6 +168,7 @@ typedef struct { INT32 timer; INT32 tic, endtic; + INT32 selectFinalize, pickFinalize; boolean notYetPicked; boolean loaded; SINT8 deferredLevel; @@ -795,9 +801,15 @@ void Y_VoteDrawer(void) // // Vote screen's selection stops moving // -static void Y_VoteStops(SINT8 pick, SINT8 level) +static void Y_FinalizeVote(const SINT8 level) { nextmap = g_voteLevels[level][0]; + deferencoremode = (g_voteLevels[level][1] & VOTE_MOD_ENCORE); +} + +static void Y_VoteStops(SINT8 pick, SINT8 level) +{ + Y_FinalizeVote(level); if (netgame && P_IsLocalPlayer(&players[pick])) { @@ -807,8 +819,6 @@ static void Y_VoteStops(SINT8 pick, SINT8 level) { S_StartSound(NULL, sfx_kc48); // just a cool sound } - - deferencoremode = (g_voteLevels[level][1] & VOTE_MOD_ENCORE); } static void Y_PlayerSendVote(const UINT8 localPlayer) @@ -1121,8 +1131,31 @@ static void Y_TickVoteRoulette(void) } } +static boolean Y_PlayerCanSelect(const UINT8 localId) +{ + const UINT8 p = g_localplayers[localId]; + + if (g_pickedVote != VOTE_NOT_PICKED) + { + return false; + } + + if (g_votes[p] != VOTE_NOT_PICKED) + { + return false; + } + + if (vote.players[localId].catcher.action != CATCHER_NA) + { + return false; + } + + return Y_PlayerIDCanVote(p); +} + static void Y_TickVoteSelection(void) { + boolean everyone_voted = true;/* the default condition */ INT32 i; if (vote.tic < 3*(NEWTICRATE/7)) // give it some time before letting you control it :V @@ -1134,23 +1167,27 @@ static void Y_TickVoteSelection(void) The vote ended, but it will take at least a tic for that to reach us from the server. Don't let me change the vote now, it won't matter anyway! */ - if (vote.timer != 0) + for (i = 0; i <= splitscreen; i++) { - for (i = 0; i <= splitscreen; i++) + boolean moved = false; + + if (vote.players[i].delay) { - const UINT8 p = g_localplayers[i]; - boolean moved = false; + vote.players[i].delay--; + } - if (vote.players[i].delay) + if (Y_PlayerCanSelect(i) == true) + { + if (vote.timer == 0) { - vote.players[i].delay--; + // Time's up, send our vote ASAP. + if (vote.players[i].sentTimeOutVote == false) + { + Y_PlayerSendVote(i); + vote.players[i].sentTimeOutVote = true; + } } - - if (Y_PlayerIDCanVote(p) == true - && menuactive == false - && vote.players[i].delay == 0 - && g_pickedVote == VOTE_NOT_PICKED && g_votes[p] == VOTE_NOT_PICKED - && vote.players[i].catcher.action == CATCHER_NA) + else if (menuactive == false && vote.players[i].delay == 0) { if (G_PlayerInputDown(i, gc_left, 0)) { @@ -1180,50 +1217,68 @@ static void Y_TickVoteSelection(void) moved = true; } } + } - if (moved) - { - S_StartSound(NULL, sfx_kc4a); - vote.players[i].delay = NEWTICRATE/7; - } + if (moved == true) + { + S_StartSound(NULL, sfx_kc4a); + vote.players[i].delay = NEWTICRATE/7; } } - if (server) + for (i = 0; i < MAXPLAYERS; i++) { - boolean everyone_voted = true;/* the default condition */ - - for (i = 0; i < MAXPLAYERS; i++) + if (Y_PlayerIDCanVote(i) == false) { - if (Y_PlayerIDCanVote(i) == false) - { - continue; - } - - if (g_votes[i] == VOTE_NOT_PICKED) - { - if (vote.timer == 0) - { - g_votes[i] = 3; // RANDOMIZE LATER - } - else - { - everyone_voted = false; - } - } + continue; } - if (everyone_voted == true) + if (g_votes[i] == VOTE_NOT_PICKED) { - vote.timer = 0; + everyone_voted = false; + break; + } + } - if (vote.endtic == -1) + if (everyone_voted == true) + { + vote.timer = 0; + vote.selectFinalize = SELECT_DELAY_TIME; + } + + if (vote.timer == 0) + { + if (vote.selectFinalize < SELECT_DELAY_TIME) + { + vote.selectFinalize++; + } + } + else + { + vote.selectFinalize = 0; + } + + if (vote.selectFinalize >= SELECT_DELAY_TIME) + { + if (vote.pickFinalize < PICK_DELAY_TIME) + { + vote.pickFinalize++; + } + else if (vote.endtic == -1) + { + vote.notYetPicked = false; /* don't pick vote twice */ + + if (server) { - vote.notYetPicked = false; /* don't pick vote twice */ D_PickVote(); } } } + else if (vote.timer > 0) + { + vote.timer--; + vote.pickFinalize = 0; + } } // @@ -1257,10 +1312,6 @@ void Y_VoteTicker(void) { g_votes[i] = VOTE_NOT_PICKED; // Spectators are the lower class, and have effectively no voice in the government. Democracy sucks. } - else if (g_pickedVote != VOTE_NOT_PICKED && g_votes[i] == VOTE_NOT_PICKED) - { - g_votes[i] = 3; // Slow people get random values -- TODO: random vote doesn't exist anymore - } } if (server && g_pickedVote != VOTE_NOT_PICKED && g_votes[g_pickedVote] == VOTE_NOT_PICKED) // Uh oh! The person who got picked left! Recalculate, quick! @@ -1274,9 +1325,13 @@ void Y_VoteTicker(void) S_ShowMusicCredit(); } - if (vote.timer > 0) + if (g_pickedVote != VOTE_NOT_PICKED) { - vote.timer--; + Y_TickVoteRoulette(); + } + else if (vote.notYetPicked == true) + { + Y_TickVoteSelection(); } for (i = 0; i <= splitscreen; i++) @@ -1290,15 +1345,6 @@ void Y_VoteTicker(void) { Y_TickPlayerPile(i); } - - if (g_pickedVote != VOTE_NOT_PICKED) - { - Y_TickVoteRoulette(); - } - else if (vote.notYetPicked) - { - Y_TickVoteSelection(); - } } // @@ -1306,12 +1352,10 @@ void Y_VoteTicker(void) // // MK online style voting screen, appears after intermission // -void Y_StartVote(void) +static void Y_InitVoteDrawing(void) { INT32 i = 0; - vote.tic = vote.endtic = -1; - vote_draw.ruby_icon = W_CachePatchName("RUBYICON", PU_STATIC); for (i = 0; i < PLANET_FRAMES; i++) @@ -1338,46 +1382,6 @@ void Y_StartVote(void) vote_draw.catcher_bulb[1][i] = W_CachePatchName(va("VS_BULB%d", i + 1), PU_STATIC); } -#ifdef VOTE_TIME_WAIT_FOR_VOTE - vote.timer = -1; // Timer is not set until the first vote is added -#else - vote.timer = cv_votetime.value * TICRATE; -#endif - - g_pickedVote = VOTE_NOT_PICKED; - vote.notYetPicked = true; - - for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) - { - y_vote_player *const player = &vote.players[i]; - y_vote_catcher *const catcher = &player->catcher; - - player->selection = 0; - player->delay = 0; - - catcher->action = CATCHER_NA; - catcher->small = false; - catcher->player = -1; - } - - vote.roulette.anim = 0; - vote.roulette.tics = 0; - vote.roulette.offset = 0; - vote.roulette.endOffset = 0; - vote.roulette.syncTime = 0; - - for (i = 0; i < MAXPLAYERS; i++) - { - y_vote_pile *const pile = &vote.roulette.pile[i]; - y_vote_catcher *const catcher = &pile->catcher; - - g_votes[i] = VOTE_NOT_PICKED; - - catcher->action = CATCHER_NA; - catcher->small = true; - catcher->player = i; - } - for (i = 0; i < VOTE_NUM_LEVELS; i++) { // set up the encore @@ -1415,6 +1419,49 @@ void Y_StartVote(void) } vote_draw.selectTransition = FRACUNIT; +} + +void Y_StartVote(void) +{ + INT32 i = 0; + + memset(&vote, 0, sizeof(vote)); + memset(&vote_draw, 0, sizeof(vote_draw)); + + vote.tic = vote.endtic = -1; + +#ifdef VOTE_TIME_WAIT_FOR_VOTE + vote.timer = -1; // Timer is not set until the first vote is added +#else + vote.timer = cv_votetime.value * TICRATE; +#endif + + g_pickedVote = VOTE_NOT_PICKED; + vote.notYetPicked = true; + + for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) + { + y_vote_player *const player = &vote.players[i]; + y_vote_catcher *const catcher = &player->catcher; + + catcher->action = CATCHER_NA; + catcher->small = false; + catcher->player = -1; + } + + for (i = 0; i < MAXPLAYERS; i++) + { + y_vote_pile *const pile = &vote.roulette.pile[i]; + y_vote_catcher *const catcher = &pile->catcher; + + g_votes[i] = VOTE_NOT_PICKED; + + catcher->action = CATCHER_NA; + catcher->small = true; + catcher->player = i; + } + + Y_InitVoteDrawing(); vote.loaded = true; Automate_Run(AEV_VOTESTART); @@ -1464,6 +1511,14 @@ static void Y_UnloadVoteData(void) // void Y_EndVote(void) { + if (nextmap >= NEXTMAP_SPECIAL) + { + // Don't leave nextmap unset if the vote is ended through + // weird means! (such as a dedicated server becoming empty) + // If nextmap was left at NEXTMAP_VOTING, we'd crash! + Y_FinalizeVote(0); + } + Y_UnloadVoteData(); vote.endtic = -1; } @@ -1486,7 +1541,7 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level) return; } - if (pick == VOTE_NOT_PICKED) // No other votes? We gotta get out of here, then! + if (pick == VOTE_NOT_PICKED || level == VOTE_NOT_PICKED) // No other votes? We gotta get out of here, then! { Y_EndVote(); G_AfterIntermission(); @@ -1503,17 +1558,7 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level) for (i = 0; i < MAXPLAYERS; i++) { - if (Y_PlayerIDCanVote(i) == true && g_votes[i] == VOTE_NOT_PICKED) - { - g_votes[i] = 3; // RANDOMIZE - } - - if (g_votes[i] == VOTE_NOT_PICKED || endtype > VOTE_END_QUICK) // Don't need to go on - { - continue; - } - - if (endtype == VOTE_END_NORMAL) + if (g_votes[i] == VOTE_NOT_PICKED) { continue; } @@ -1526,6 +1571,7 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level) else if (g_votes[i] != votecompare) { endtype = VOTE_END_NORMAL; + break; } } @@ -1538,7 +1584,6 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level) G_AfterIntermission(); return; } - /* case VOTE_END_QUICK: { // Only one unique vote, so just end it immediately. @@ -1547,7 +1592,6 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level) Y_VoteStops(pick, level); break; } - */ default: { S_ChangeMusicInternal("voteea", true); @@ -1559,4 +1603,6 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level) vote.deferredLevel = level; g_pickedVote = pick; vote.timer = -1; + vote.selectFinalize = SELECT_DELAY_TIME; + vote.pickFinalize = PICK_DELAY_TIME; } From 9c4ace6fbcf8d874199c54d321ee54581f667304 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 10 Apr 2023 02:08:48 -0400 Subject: [PATCH 26/31] Map anger - Maps build anger every time a map isn't selected by anyone. - If a map is ignored for 4 votes in a row, then on the 5th vote it shows up it will be angry enough to vote for itself when everyone else finishes voting. - Once it gives its funny vote, or it gets played, it will calm down again. - 13P+ vote icons are implemented; it's just a basic circle though cuz lazy. - Made the roulette finish even faster. - Bots can vote again but now behind a debug cvar. --- src/d_netcmd.c | 81 ++++++++++++++++----- src/d_netcmd.h | 1 + src/doomstat.h | 5 +- src/g_game.c | 27 +++++-- src/k_kart.c | 1 + src/k_vote.c | 191 +++++++++++++++++++++++++++++++++++++++---------- src/p_saveg.c | 10 +-- src/p_setup.c | 3 + 8 files changed, 255 insertions(+), 64 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 87219af7f..76758aa41 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -468,6 +468,8 @@ consvar_t cv_reducevfx = CVAR_INIT ("reducevfx", "No", CV_SAVE, CV_YesNo, NULL); static CV_PossibleValue_t votetime_cons_t[] = {{10, "MIN"}, {3600, "MAX"}, {0, NULL}}; consvar_t cv_votetime = CVAR_INIT ("votetime", "20", CV_NETVAR, votetime_cons_t, NULL); +consvar_t cv_botscanvote = CVAR_INIT ("botscanvote", "No", CV_CHEAT, CV_YesNo, NULL); + consvar_t cv_gravity = CVAR_INIT ("gravity", "0.8", CV_CHEAT|CV_FLOAT|CV_CALL, NULL, Gravity_OnChange); // change DEFAULT_GRAVITY if you change this consvar_t cv_soundtest = CVAR_INIT ("soundtest", "0", CV_CALL, NULL, SoundTest_OnChange); @@ -2645,29 +2647,52 @@ void D_ModifyClientVote(UINT8 player, SINT8 voted) { char buf[2]; char *p = buf; + UINT8 sendPlayer = consoleplayer; - if (player >= MAXSPLITSCREENPLAYERS) + if (player == UINT8_MAX) { - return; + // Special game vote (map anger, duel) + if (!server) + { + return; + } + } + + if (player == UINT8_MAX) + { + // special vote + WRITEUINT8(p, UINT8_MAX); + } + else + { + INT32 i = 0; + WRITEUINT8(p, player); + + for (i = 0; i <= splitscreen; i++) + { + if (g_localplayers[i] == player) + { + sendPlayer = i; + } + } } - WRITEUINT8(p, g_localplayers[player]); WRITESINT8(p, voted); - SendNetXCmdForPlayer(player, XD_MODIFYVOTE, buf, p - buf); + SendNetXCmdForPlayer(sendPlayer, XD_MODIFYVOTE, buf, p - buf); } void D_PickVote(void) { char buf[2]; char* p = buf; - SINT8 temppicks[MAXPLAYERS]; - SINT8 templevels[MAXPLAYERS]; + SINT8 temppicks[VOTE_TOTAL]; + SINT8 templevels[VOTE_TOTAL]; SINT8 votecompare = VOTE_NOT_PICKED; UINT8 numvotes = 0, key = 0; INT32 i; - for (i = 0; i < MAXPLAYERS; i++) + for (i = 0; i < VOTE_TOTAL; i++) { if (Y_PlayerIDCanVote(i) == false) { @@ -5434,23 +5459,45 @@ static void Got_ModifyVotecmd(UINT8 **cp, INT32 playernum) UINT8 targetID = READUINT8(*cp); SINT8 vote = READSINT8(*cp); - if (targetID >= MAXPLAYERS - || playernode[targetID] != playernode[playernum]) + if (targetID == UINT8_MAX) { - CONS_Alert(CONS_WARNING, - M_GetText ("Illegal modify vote command received from %s\n"), - player_names[playernum] - ); - - if (server) + if (playernum != serverplayer) // server-only special vote { - SendKick(playernum, KICK_MSG_CON_FAIL); + goto fail; } - return; + targetID = VOTE_SPECIAL; + } + else if (playeringame[targetID] == true && players[targetID].bot == true) + { + if (targetID >= MAXPLAYERS + || playernum != serverplayer) + { + goto fail; + } + } + else + { + if (targetID >= MAXPLAYERS + || playernode[targetID] != playernode[playernum]) + { + goto fail; + } } Y_SetPlayersVote(targetID, vote); + return; + +fail: + CONS_Alert(CONS_WARNING, + M_GetText ("Illegal modify vote command received from %s\n"), + player_names[playernum] + ); + + if (server) + { + SendKick(playernum, KICK_MSG_CON_FAIL); + } } static void Got_PickVotecmd(UINT8 **cp, INT32 playernum) diff --git a/src/d_netcmd.h b/src/d_netcmd.h index d4c7d82a4..8cab1e10f 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -90,6 +90,7 @@ extern consvar_t cv_karteliminatelast; extern consvar_t cv_kartusepwrlv; extern consvar_t cv_votetime; +extern consvar_t cv_botscanvote; extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartdebugdistribution, cv_kartdebughuddrop; extern consvar_t cv_kartdebugnodes, cv_kartdebugcolorize, cv_kartdebugdirector; diff --git a/src/doomstat.h b/src/doomstat.h index 80d7f3635..e044ed0cf 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -411,6 +411,7 @@ struct mapheader_t cupheader_t *cup; ///< Cached cup size_t justPlayed; ///< Prevent this map from showing up in votes if it was recently picked. + size_t anger; ///< No one picked this map... it's mad now. // Titlecard information char lvlttl[22]; ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway) @@ -734,8 +735,10 @@ extern boolean legitimateexit; extern boolean comebackshowninfo; extern tic_t curlap, bestlap; +#define VOTE_SPECIAL (MAXPLAYERS) +#define VOTE_TOTAL (MAXPLAYERS+1) extern INT16 g_voteLevels[4][2]; -extern SINT8 g_votes[MAXPLAYERS]; +extern SINT8 g_votes[VOTE_TOTAL]; extern SINT8 g_pickedVote; // =========================== diff --git a/src/g_game.c b/src/g_game.c index 1627c996d..e9168df51 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -299,7 +299,7 @@ boolean franticitems; // Frantic items currently enabled? // Voting system INT16 g_voteLevels[4][2]; // Levels that were rolled by the host -SINT8 g_votes[MAXPLAYERS]; // Each player's vote +SINT8 g_votes[VOTE_TOTAL]; // Each player's vote SINT8 g_pickedVote; // What vote the host rolls // Server-sided, synched variables @@ -3687,14 +3687,33 @@ static INT32 TOLMaps(UINT8 pgametype) // Find all the maps that are ok for (i = 0; i < nummapheaders; i++) { - if (!mapheaderinfo[i]) + if (mapheaderinfo[i] == NULL) + { continue; + } + if (mapheaderinfo[i]->lumpnum == LUMPERROR) + { continue; - if (!(mapheaderinfo[i]->typeoflevel & tolflag)) + } + + if ((mapheaderinfo[i]->typeoflevel & tolflag) == 0) + { continue; - if (mapheaderinfo[i]->menuflags & LF2_HIDEINMENU) // Don't include Map Hell + } + + if (mapheaderinfo[i]->menuflags & LF2_HIDEINMENU) + { + // Don't include hidden continue; + } + + if (M_MapLocked(i + 1)) + { + // Don't include locked + continue; + } + num++; } diff --git a/src/k_kart.c b/src/k_kart.c index c06b15bd7..89d02517c 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -342,6 +342,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_karteliminatelast); CV_RegisterVar(&cv_kartusepwrlv); CV_RegisterVar(&cv_votetime); + CV_RegisterVar(&cv_botscanvote); CV_RegisterVar(&cv_kartdebugitem); CV_RegisterVar(&cv_kartdebugamount); diff --git a/src/k_vote.c b/src/k_vote.c index 8db929bb6..5e8f78b2d 100644 --- a/src/k_vote.c +++ b/src/k_vote.c @@ -96,11 +96,14 @@ #define PILE_SPACING_W (PILE_WIDTH + PILE_SPACE) #define PILE_SPACING_H (PILE_HEIGHT + PILE_SPACE) +#define LOTS_OF_VOTES_X (120*FRACUNIT) +#define LOTS_OF_VOTES_Y (80*FRACUNIT) + // Give time for the animations to finish before finalizing the vote stages. #define SELECT_DELAY_TIME (TICRATE*4) #define PICK_DELAY_TIME (TICRATE/2) -//#define TEST_VOTES (11) +#define MAP_ANGER_MAX (VOTE_NUM_LEVELS) // Catcher data enum @@ -155,7 +158,7 @@ typedef struct // Voting roulette variables. typedef struct { - y_vote_pile pile[MAXPLAYERS]; + y_vote_pile pile[VOTE_TOTAL]; UINT8 anim; UINT8 tics; UINT32 offset; @@ -211,17 +214,29 @@ boolean Y_PlayerIDCanVote(const UINT8 playerId) { player_t *player = NULL; + if (playerId == VOTE_SPECIAL) + { + // Special vote spot, always allow + return true; + } + if (playerId >= MAXPLAYERS || playeringame[playerId] == false) { return false; } player = &players[playerId]; - if (player->spectator == true || player->bot == true) + if (player->spectator == true) { return false; } + if (player->bot == true && cv_botscanvote.value == 0) + { + // Bots may only vote if the server allows it + return false; + } + return true; } @@ -231,10 +246,7 @@ static void Y_SortPile(void) UINT8 votesLeft = 0; INT32 i; -#ifdef TEST_VOTES - numVotes = TEST_VOTES; -#else - for (i = 0; i < MAXPLAYERS; i++) + for (i = 0; i < VOTE_TOTAL; i++) { if (g_votes[i] == VOTE_NOT_PICKED) { @@ -243,7 +255,6 @@ static void Y_SortPile(void) numVotes++; } -#endif if (numVotes == 0) { @@ -252,16 +263,14 @@ static void Y_SortPile(void) votesLeft = numVotes; - for (i = 0; i < MAXPLAYERS; i++) + for (i = 0; i < VOTE_TOTAL; i++) { y_vote_pile *const pile = &vote.roulette.pile[i]; -#ifndef TEST_VOTES if (g_votes[i] == VOTE_NOT_PICKED) { continue; } -#endif // Just center it for now. pile->destX = BASEVIDWIDTH << FRACBITS >> 1; @@ -313,7 +322,9 @@ static void Y_SortPile(void) } else { - // TODO: 13+ votes + angle_t a = ANGLE_90 + (ANGLE_MAX / numVotes) * (votesLeft - 1); + pile->destX += FixedMul(LOTS_OF_VOTES_X, FINECOSINE(a >> ANGLETOFINESHIFT)); + pile->destY += FixedMul(LOTS_OF_VOTES_Y, -FINESINE(a >> ANGLETOFINESHIFT)); } votesLeft--; @@ -448,20 +459,51 @@ static void Y_DrawVoteThumbnail(fixed_t center_x, fixed_t center_y, fixed_t widt if (playerID >= 0) { + const INT32 whiteSq = 16 * dupx; + if (playerID < MAXPLAYERS) { UINT8 *playerMap = R_GetTranslationColormap(players[playerID].skin, players[playerID].skincolor, GTC_CACHE); patch_t *playerPatch = faceprefix[players[playerID].skin][FACE_RANK]; + V_DrawFixedPatch( - x + width - (playerPatch->width * FRACUNIT) + FRACUNIT - 1, - y + height - (playerPatch->height * FRACUNIT) + FRACUNIT, - FRACUNIT, flags, + (fx + fw - whiteSq + dupx) * FRACUNIT, + (fy + fh - whiteSq + dupy) * FRACUNIT, + FRACUNIT, flags|V_NOSCALESTART, playerPatch, playerMap ); } else { - ; // angry level goes here + const fixed_t iconHeight = (14 << FRACBITS); + const fixed_t iconWidth = (iconHeight * 320) / 200; + + V_DrawFill( + fx + fw - whiteSq + dupx, + fy + fh - whiteSq + dupy, + whiteSq, + whiteSq, + 0|flags|V_NOSCALESTART + ); + + V_SetClipRect( + fx + fw - whiteSq + (2 * dupx), + fy + fh - whiteSq + (2 * dupy), + whiteSq - (2 * dupx), + whiteSq - (2 * dupy), + flags|V_NOSCALESTART + ); + + K_DrawMapThumbnail( + ((fx + fw - whiteSq + (2 * dupx)) * FRACUNIT) - (iconWidth - iconHeight), + (fy + fh - whiteSq + (2 * dupy)) * FRACUNIT, + iconWidth, + flags | V_NOSCALESTART | ((encore == true) ? V_FLIP : 0), + g_voteLevels[v][0], + NULL + ); + + V_ClearClipRect(); } } } @@ -707,7 +749,7 @@ static void Y_DrawVotePile(void) { INT32 i; - for (i = 0; i < MAXPLAYERS; i++) + for (i = 0; i < VOTE_TOTAL; i++) { y_vote_pile *const pile = &vote.roulette.pile[i]; y_vote_catcher *const catcher = &pile->catcher; @@ -717,27 +759,21 @@ static void Y_DrawVotePile(void) continue; } -#ifndef TEST_VOTES if (g_votes[i] == VOTE_NOT_PICKED) { continue; } -#endif Y_DrawVoteThumbnail( pile->x, pile->y, PILE_WIDTH, 0, -#ifdef TEST_VOTES - 0, -#else g_votes[i], -#endif (i != vote.roulette.anim || g_pickedVote == VOTE_NOT_PICKED), i ); } - for (i = 0; i < MAXPLAYERS; i++) + for (i = 0; i < VOTE_TOTAL; i++) { Y_DrawCatcher(&vote.roulette.pile[i].catcher); } @@ -949,7 +985,7 @@ static void Y_TickPlayerCatcher(const UINT8 localPlayer) { if (catcher->x == catcher->destX && catcher->y == catcher->destY) { - D_ModifyClientVote(localPlayer, vote.players[localPlayer].selection); + D_ModifyClientVote(g_localplayers[localPlayer], vote.players[localPlayer].selection); catcher->action = CATCHER_NA; S_StopSoundByNum(sfx_kc37); } @@ -1023,13 +1059,11 @@ static void Y_TickPlayerPile(const UINT8 playerId) fixed_t movedX = 0; fixed_t movedY = 0; -#ifndef TEST_VOTES if (g_votes[playerId] == VOTE_NOT_PICKED) { catcher->action = CATCHER_NA; return; } -#endif movedX = (pile->destX - pile->x) / 2; movedY = (pile->destY - pile->y) / 2; @@ -1058,10 +1092,10 @@ static void Y_TickVoteRoulette(void) if (vote.endtic == -1) { - UINT8 tempvotes[MAXPLAYERS]; + UINT8 tempvotes[VOTE_TOTAL]; UINT8 numvotes = 0; - for (i = 0; i < MAXPLAYERS; i++) + for (i = 0; i < VOTE_TOTAL; i++) { if (g_votes[i] == VOTE_NOT_PICKED) { @@ -1086,7 +1120,7 @@ static void Y_TickVoteRoulette(void) else { vote.roulette.offset++; - vote.roulette.tics = min(6, 9 * vote.roulette.offset / 40); + vote.roulette.tics = min(5, 7 * vote.roulette.offset / 40); S_StartSound(NULL, sfx_kc39); } @@ -1095,7 +1129,7 @@ static void Y_TickVoteRoulette(void) vote.roulette.anim = tempvotes[((g_pickedVote + vote.roulette.offset) % numvotes)]; } - if (vote.roulette.offset > 30) + if (vote.roulette.offset > 20) { if (vote.roulette.endOffset == 0) { @@ -1107,7 +1141,7 @@ static void Y_TickVoteRoulette(void) { vote.roulette.endOffset = vote.roulette.offset + i; - if (M_RandomChance(FRACUNIT/32)) // Let it cheat occasionally~ + if (M_RandomChance(FRACUNIT/4)) // Let it cheat occasionally~ { vote.roulette.endOffset++; } @@ -1153,6 +1187,74 @@ static boolean Y_PlayerCanSelect(const UINT8 localId) return Y_PlayerIDCanVote(p); } +static void Y_TryMapAngerVote(void) +{ + SINT8 angryMaps[VOTE_NUM_LEVELS] = { -1 }; + size_t angryMapsCount = 0; + + boolean mapVoted[VOTE_NUM_LEVELS] = { false }; + INT32 pick = 0; + + INT32 numPlayers = 0; + INT32 i = 0; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (Y_PlayerIDCanVote(i) == false) + { + continue; + } + + numPlayers++; + + if (g_votes[i] != VOTE_NOT_PICKED) + { + mapVoted[ g_votes[i] ] = true; + } + } + + if (numPlayers < 3) + { + // Don't handle map anger if there's not enough players. + return; + } + + for (i = 0; i < VOTE_NUM_LEVELS; i++) + { + const INT16 mapID = g_voteLevels[i][0]; + + if (mapVoted[i] == true) + { + // Someone voted for us, no need to be angry anymore :) + mapheaderinfo[ mapID ]->anger = 0; + } + else + { + // Increment map anger for maps that weren't picked by a single soul. + mapheaderinfo[ mapID ]->anger++; + + if (mapheaderinfo[ mapID ]->anger > MAP_ANGER_MAX) + { + // If they are angry enough, then it can vote for itself! + angryMaps[ angryMapsCount ] = i; + angryMapsCount++; + } + } + } + + if (angryMapsCount == 0) + { + return; + } + + // Set the special vote to a random angry map. + pick = M_RandomKey(angryMapsCount); + D_ModifyClientVote(UINT8_MAX, angryMaps[pick]); + + // Make it not angry anymore. + mapheaderinfo[ g_voteLevels[ angryMaps[pick] ][0] ]->anger = 0; +} + static void Y_TickVoteSelection(void) { boolean everyone_voted = true;/* the default condition */ @@ -1233,10 +1335,18 @@ static void Y_TickVoteSelection(void) continue; } + if (players[i].bot == true && g_votes[i] == VOTE_NOT_PICKED) + { + if (( M_RandomFixed() % 100 ) == 0) + { + // bots vote randomly + D_ModifyClientVote(i, M_RandomKey(VOTE_NUM_LEVELS)); + } + } + if (g_votes[i] == VOTE_NOT_PICKED) { everyone_voted = false; - break; } } @@ -1270,6 +1380,7 @@ static void Y_TickVoteSelection(void) if (server) { + Y_TryMapAngerVote(); D_PickVote(); } } @@ -1306,11 +1417,15 @@ void Y_VoteTicker(void) return; } - for (i = 0; i < MAXPLAYERS; i++) // Correct votes as early as possible, before they're processed by the game at all + // Correct invalid votes as early as possible, + // before they're processed by the rest of the ticker + for (i = 0; i < MAXPLAYERS; i++) { if (Y_PlayerIDCanVote(i) == false) { - g_votes[i] = VOTE_NOT_PICKED; // Spectators are the lower class, and have effectively no voice in the government. Democracy sucks. + // Spectators are the lower class, and have + // effectively no voice in the government. Democracy sucks. + g_votes[i] = VOTE_NOT_PICKED; } } @@ -1341,7 +1456,7 @@ void Y_VoteTicker(void) Y_SortPile(); - for (i = 0; i < MAXPLAYERS; i++) + for (i = 0; i < VOTE_TOTAL; i++) { Y_TickPlayerPile(i); } @@ -1449,7 +1564,7 @@ void Y_StartVote(void) catcher->player = -1; } - for (i = 0; i < MAXPLAYERS; i++) + for (i = 0; i < VOTE_TOTAL; i++) { y_vote_pile *const pile = &vote.roulette.pile[i]; y_vote_catcher *const catcher = &pile->catcher; @@ -1556,7 +1671,7 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level) vote.roulette.syncTime = 0; - for (i = 0; i < MAXPLAYERS; i++) + for (i = 0; i < VOTE_TOTAL; i++) { if (g_votes[i] == VOTE_NOT_PICKED) { diff --git a/src/p_saveg.c b/src/p_saveg.c index 05c55e0ea..081eceffe 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4997,14 +4997,16 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) WRITEINT16(save->p, lastmap); WRITEUINT16(save->p, bossdisabled); - for (i = 0; i < 4; i++) + for (i = 0; i < VOTE_NUM_LEVELS; i++) { WRITEINT16(save->p, g_voteLevels[i][0]); WRITEINT16(save->p, g_voteLevels[i][1]); } - for (i = 0; i < MAXPLAYERS; i++) + for (i = 0; i < VOTE_TOTAL; i++) + { WRITESINT8(save->p, g_votes[i]); + } WRITESINT8(save->p, g_pickedVote); @@ -5169,13 +5171,13 @@ static inline boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading) lastmap = READINT16(save->p); bossdisabled = READUINT16(save->p); - for (i = 0; i < 4; i++) + for (i = 0; i < VOTE_NUM_LEVELS; i++) { g_voteLevels[i][0] = READINT16(save->p); g_voteLevels[i][1] = READINT16(save->p); } - for (i = 0; i < MAXPLAYERS; i++) + for (i = 0; i < VOTE_TOTAL; i++) { g_votes[i] = READSINT8(save->p); } diff --git a/src/p_setup.c b/src/p_setup.c index 6de8c86b1..232be6670 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -429,6 +429,9 @@ static void P_ClearSingleMapHeaderInfo(INT16 num) Z_Free(mapheaderinfo[num]->mainrecord); mapheaderinfo[num]->mainrecord = NULL; + mapheaderinfo[num]->justPlayed = 0; + mapheaderinfo[num]->anger = 0; + mapheaderinfo[num]->customopts = NULL; mapheaderinfo[num]->numCustomOptions = 0; } From 31728166cab6a1b202511bad7deb296ef97d307b Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 10 Apr 2023 02:27:48 -0400 Subject: [PATCH 27/31] Adjust map anger conditions Don't reset map anger when it votes for itself -- wait until the map gets played or it gets a genuine vote from someone. --- src/g_game.c | 1 + src/k_vote.c | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index e9168df51..5988ce3bb 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3892,6 +3892,7 @@ void G_AddMapToBuffer(INT16 map) // Set our map's justPlayed value. mapheaderinfo[map]->justPlayed = TOLMaps(gametype) - VOTE_NUM_LEVELS; + mapheaderinfo[map]->anger = 0; // Reset voting anger now that we're playing it } // diff --git a/src/k_vote.c b/src/k_vote.c index 5e8f78b2d..0f9c17520 100644 --- a/src/k_vote.c +++ b/src/k_vote.c @@ -1250,9 +1250,6 @@ static void Y_TryMapAngerVote(void) // Set the special vote to a random angry map. pick = M_RandomKey(angryMapsCount); D_ModifyClientVote(UINT8_MAX, angryMaps[pick]); - - // Make it not angry anymore. - mapheaderinfo[ g_voteLevels[ angryMaps[pick] ][0] ]->anger = 0; } static void Y_TickVoteSelection(void) From d2960ce93da9b814a706a4ca98663b25504eccc9 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 10 Apr 2023 23:12:08 -0400 Subject: [PATCH 28/31] Don't allow resending vote if you have delay --- src/k_vote.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/k_vote.c b/src/k_vote.c index 0f9c17520..05db3d48d 100644 --- a/src/k_vote.c +++ b/src/k_vote.c @@ -1270,23 +1270,23 @@ static void Y_TickVoteSelection(void) { boolean moved = false; - if (vote.players[i].delay) - { - vote.players[i].delay--; - } - if (Y_PlayerCanSelect(i) == true) { - if (vote.timer == 0) + if (vote.players[i].delay > 0) + { + vote.players[i].delay--; + } + else if (vote.timer == 0) { // Time's up, send our vote ASAP. if (vote.players[i].sentTimeOutVote == false) { Y_PlayerSendVote(i); vote.players[i].sentTimeOutVote = true; + vote.players[i].delay = NEWTICRATE/7; } } - else if (menuactive == false && vote.players[i].delay == 0) + else if (menuactive == false) { if (G_PlayerInputDown(i, gc_left, 0)) { From 9de36ce2a92e6933c212c7acb4bce40934de2ce9 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 10 Apr 2023 23:14:25 -0400 Subject: [PATCH 29/31] Slide out votes when you're done voting --- src/k_vote.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/k_vote.c b/src/k_vote.c index 05db3d48d..afdd40491 100644 --- a/src/k_vote.c +++ b/src/k_vote.c @@ -808,8 +808,20 @@ void Y_VoteDrawer(void) if (vote.loaded == true) { + boolean slideOut = true; + INT32 i; + + for (i = 0; i <= splitscreen; i++) + { + if (g_votes[ g_localplayers[i] ] == VOTE_NOT_PICKED) + { + slideOut = false; + break; + } + } + vote_draw.selectTransition += FixedMul( - (((g_pickedVote != VOTE_NOT_PICKED) ? FRACUNIT : 0) - vote_draw.selectTransition) / 2, + ((slideOut ? FRACUNIT : 0) - vote_draw.selectTransition) / 2, renderdeltatics ); } From 16df36b65b1de74f449c4e9d8fc7bfb71c17a63b Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 10 Apr 2023 23:52:37 -0400 Subject: [PATCH 30/31] Draw fill instead of BG for Ivo until RHI bug fix --- src/k_vote.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/k_vote.c b/src/k_vote.c index afdd40491..96c4c590f 100644 --- a/src/k_vote.c +++ b/src/k_vote.c @@ -625,6 +625,18 @@ static void Y_DrawVoteBackground(void) const UINT8 planetFrame = (bgTimer / FRACUNIT) % PLANET_FRAMES; + if (cv_reducevfx.value) + { + // REMOVE ONCE THE RHI BUG IS FIXED, + // BUT UNTIL THEN, IVO NEEDS TO NOT DIE + V_DrawFill( + 0, 0, + BASEVIDWIDTH, BASEVIDHEIGHT, + 31 + ); + return; + } + V_DrawFixedPatch( 0, 0, FRACUNIT, 0, From 198672c8455d37e063e5104ee68994b7c99458a9 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 11 Apr 2023 01:19:30 -0400 Subject: [PATCH 31/31] Fix vote buffer for G_RandMap being broken --- src/d_netcmd.c | 4 ++-- src/doomstat.h | 2 +- src/f_finale.c | 2 +- src/g_game.c | 27 ++++++++++++++++----------- src/g_game.h | 4 ++-- src/k_menudraw.c | 14 +++++++------- src/p_saveg.c | 8 ++++---- src/p_setup.c | 2 -- 8 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 76758aa41..4f595411e 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2622,8 +2622,8 @@ void D_SetupVote(void) INT32 i; - INT16 votebuffer[VOTE_NUM_LEVELS + 1] = {-1}; - votebuffer[VOTE_NUM_LEVELS] = 0; // End marker for G_RandMap + UINT16 votebuffer[VOTE_NUM_LEVELS + 1]; + memset(votebuffer, UINT16_MAX, sizeof(votebuffer)); WRITEUINT8(p, ((cv_kartencore.value == 1) && (gametyperules & GTR_ENCORE))); WRITEUINT8(p, G_SometimesGetDifferentEncore()); diff --git a/src/doomstat.h b/src/doomstat.h index e044ed0cf..a16e5baa8 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -737,7 +737,7 @@ extern tic_t curlap, bestlap; #define VOTE_SPECIAL (MAXPLAYERS) #define VOTE_TOTAL (MAXPLAYERS+1) -extern INT16 g_voteLevels[4][2]; +extern UINT16 g_voteLevels[4][2]; extern SINT8 g_votes[VOTE_TOTAL]; extern SINT8 g_pickedVote; diff --git a/src/f_finale.c b/src/f_finale.c index 281786109..aef80562e 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2250,7 +2250,7 @@ void F_TitleScreenTicker(boolean run) // prevent console spam if failed demoIdleLeft = demoIdleTime; - mapnum = G_RandMap(TOL_RACE|TOL_BATTLE, -2, true, false, NULL); + mapnum = G_RandMap(TOL_RACE|TOL_BATTLE, UINT16_MAX-1, true, false, NULL); if (mapnum == 0) // gotta have ONE { return; diff --git a/src/g_game.c b/src/g_game.c index 5988ce3bb..f5173e642 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -298,7 +298,7 @@ boolean prevencoremode; boolean franticitems; // Frantic items currently enabled? // Voting system -INT16 g_voteLevels[4][2]; // Levels that were rolled by the host +UINT16 g_voteLevels[4][2]; // Levels that were rolled by the host SINT8 g_votes[VOTE_TOTAL]; // Each player's vote SINT8 g_pickedVote; // What vote the host rolls @@ -3728,17 +3728,17 @@ static INT32 TOLMaps(UINT8 pgametype) * has those flags. * \author Graue */ -static INT16 *g_allowedMaps = NULL; +static UINT16 *g_allowedMaps = NULL; #ifdef PARANOIA -static INT32 g_randMapStack = 0; +static size_t g_randMapStack = 0; #endif -INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, INT16 *extBuffer) +UINT16 G_RandMap(UINT32 tolflags, UINT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, UINT16 *extBuffer) { INT32 allowedMapsCount = 0; INT32 extBufferCount = 0; - INT16 ret = 0; + UINT16 ret = 0; INT32 i, j; #ifdef PARANOIA @@ -3747,12 +3747,12 @@ INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, boolean ignoreBuffers, boolean if (g_allowedMaps == NULL) { - g_allowedMaps = Z_Malloc(nummapheaders * sizeof(INT16), PU_STATIC, NULL); + g_allowedMaps = Z_Malloc(nummapheaders * sizeof(UINT16), PU_STATIC, NULL); } if (extBuffer != NULL) { - for (i = 0; extBuffer[i] != 0; i++) + for (i = 0; extBuffer[i] != UINT16_MAX; i++) { extBufferCount++; } @@ -3780,7 +3780,7 @@ tryAgain: continue; } - if (pprevmap == -2 // title demo hack + if (pprevmap == UINT16_MAX-1 // title demo hack (FUCK YOU, MAKE IT A BOOL) && mapheaderinfo[i]->ghostCount == 0) { // Doesn't have any ghosts, so it's not suitable for title demos. @@ -3809,11 +3809,13 @@ tryAgain: if (extBufferCount > 0) { + boolean inExt = false; + // An optional additional buffer, // to avoid duplicates on the voting screen. for (j = 0; j < extBufferCount; j++) { - if (extBuffer[j] < 0 || extBuffer[j] >= nummapheaders) + if (extBuffer[j] >= nummapheaders) { // Rest of buffer SHOULD be empty. break; @@ -3822,11 +3824,12 @@ tryAgain: if (i == extBuffer[j]) { // Map is in this other buffer, don't duplicate. + inExt = true; break; } } - if (j < extBufferCount) + if (inExt == true) { // Didn't make it out of this buffer, so don't add this map. continue; @@ -3875,7 +3878,7 @@ tryAgain: return ret; } -void G_AddMapToBuffer(INT16 map) +void G_AddMapToBuffer(UINT16 map) { if (mapheaderinfo[map]->justPlayed == 0) // Started playing a new map. { @@ -5507,6 +5510,8 @@ void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skippr } CON_LogMessage("\"\n"); } + + G_AddMapToBuffer(gamemap - 1); } diff --git a/src/g_game.h b/src/g_game.h index 46c93a5c1..9fe875c09 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -255,8 +255,8 @@ FUNCMATH INT32 G_TicsToMilliseconds(tic_t tics); UINT32 G_TOLFlag(INT32 pgametype); INT16 G_GetFirstMapOfGametype(UINT8 pgametype); -INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, INT16 *extBuffer); -void G_AddMapToBuffer(INT16 map); +UINT16 G_RandMap(UINT32 tolflags, UINT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, UINT16 *extBuffer); +void G_AddMapToBuffer(UINT16 map); #ifdef __cplusplus } // extern "C" diff --git a/src/k_menudraw.c b/src/k_menudraw.c index c8c78f10d..33cbf3aec 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -5282,7 +5282,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) static UINT16 encoremapcache = NEXTMAP_INVALID; if (encoremapcache > nummapheaders) { - encoremapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, true, false, NULL); + encoremapcache = G_RandMap(G_TOLFlag(GT_RACE), UINT16_MAX, true, false, NULL); } specialmap = encoremapcache; break; @@ -5292,7 +5292,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) static UINT16 tamapcache = NEXTMAP_INVALID; if (tamapcache > nummapheaders) { - tamapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, true, false, NULL); + tamapcache = G_RandMap(G_TOLFlag(GT_RACE), UINT16_MAX, true, false, NULL); } specialmap = tamapcache; break; @@ -5302,7 +5302,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) static UINT16 btcmapcache = NEXTMAP_INVALID; if (btcmapcache > nummapheaders) { - btcmapcache = G_RandMap(G_TOLFlag(GT_BATTLE), -1, true, false, NULL); + btcmapcache = G_RandMap(G_TOLFlag(GT_BATTLE), UINT16_MAX, true, false, NULL); } specialmap = btcmapcache; break; @@ -5312,7 +5312,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) static UINT16 sscmapcache = NEXTMAP_INVALID; if (sscmapcache > nummapheaders) { - sscmapcache = G_RandMap(G_TOLFlag(GT_SPECIAL), -1, true, false, NULL); + sscmapcache = G_RandMap(G_TOLFlag(GT_SPECIAL), UINT16_MAX, true, false, NULL); } specialmap = sscmapcache; break; @@ -5322,7 +5322,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) static UINT16 spbmapcache = NEXTMAP_INVALID; if (spbmapcache > nummapheaders) { - spbmapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, true, false, NULL); + spbmapcache = G_RandMap(G_TOLFlag(GT_RACE), UINT16_MAX, true, false, NULL); } specialmap = spbmapcache; break; @@ -5332,7 +5332,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) static UINT16 hardmapcache = NEXTMAP_INVALID; if (hardmapcache > nummapheaders) { - hardmapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, true, false, NULL); + hardmapcache = G_RandMap(G_TOLFlag(GT_RACE), UINT16_MAX, true, false, NULL); } specialmap = hardmapcache; break; @@ -5342,7 +5342,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) static UINT16 mastermapcache = NEXTMAP_INVALID; if (mastermapcache > nummapheaders) { - mastermapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, true, false, NULL); + mastermapcache = G_RandMap(G_TOLFlag(GT_RACE), UINT16_MAX, true, false, NULL); } specialmap = mastermapcache; break; diff --git a/src/p_saveg.c b/src/p_saveg.c index 081eceffe..d66ea3f20 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4999,8 +4999,8 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) for (i = 0; i < VOTE_NUM_LEVELS; i++) { - WRITEINT16(save->p, g_voteLevels[i][0]); - WRITEINT16(save->p, g_voteLevels[i][1]); + WRITEUINT16(save->p, g_voteLevels[i][0]); + WRITEUINT16(save->p, g_voteLevels[i][1]); } for (i = 0; i < VOTE_TOTAL; i++) @@ -5173,8 +5173,8 @@ static inline boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading) for (i = 0; i < VOTE_NUM_LEVELS; i++) { - g_voteLevels[i][0] = READINT16(save->p); - g_voteLevels[i][1] = READINT16(save->p); + g_voteLevels[i][0] = READUINT16(save->p); + g_voteLevels[i][1] = READUINT16(save->p); } for (i = 0; i < VOTE_TOTAL; i++) diff --git a/src/p_setup.c b/src/p_setup.c index 232be6670..35010f715 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8045,8 +8045,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) G_SaveGameData(); } - G_AddMapToBuffer(gamemap-1); - P_MapEnd(); // tm.thing is no longer needed from this point onwards // Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap...