From 155a5d0f17f9c50485fc3cc7fb81bb2f57c5352a Mon Sep 17 00:00:00 2001 From: Roman Fomin Date: Sat, 18 May 2024 21:26:27 +0700 Subject: [PATCH 1/2] switch to ubuntu-24.04, add extra-options for Linux build --- .github/workflows/main.yml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f4c7cfe2..0554cc04 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,8 +22,9 @@ jobs: matrix: config: - name: Linux GCC - os: ubuntu-latest + os: ubuntu-24.04 compiler: gcc + extra-options: -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_FIND_PACKAGE_PREFER_CONFIG=OFF shell: bash - name: macOS Clang @@ -51,11 +52,6 @@ jobs: libsndfile1-dev \ libfluidsynth-dev \ libxmp-dev - sudo sed -e 's/jammy/lunar/g;s/22/23/g' -i /etc/apt/sources.list /etc/apt/sources.list.d/* - sudo apt-get update - sudo apt-get install \ - libflac-dev \ - libsndfile1-dev - name: Install dependencies (macOS) if: runner.os == 'macOS' @@ -95,8 +91,8 @@ jobs: CC: ${{ matrix.config.compiler }} run: | cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=/usr \ - -DENABLE_WERROR=ON -DENABLE_HARDENING=ON -DENABLE_LTO=ON + -DENABLE_WERROR=ON -DENABLE_HARDENING=ON -DENABLE_LTO=ON \ + ${{ matrix.config.extra-options }} - name: Build run: cmake --build build From c7ad1193d1bff469d7132865d1d0979dcd1ad7de Mon Sep 17 00:00:00 2001 From: ceski <56656010+ceski-1@users.noreply.github.com> Date: Sun, 19 May 2024 08:22:20 -0700 Subject: [PATCH 2/2] Add command history widget (#1692) --- autoload/all-all/woofhud.lmp | 8 +- docs/woofhud.md | 15 +- src/CMakeLists.txt | 1 + src/g_game.c | 5 + src/hu_command.c | 279 +++++++++++++++++++++++++++++++++++ src/hu_command.h | 38 +++++ src/hu_lib.c | 23 ++- src/hu_lib.h | 3 +- src/hu_stuff.c | 56 ++++++- src/hu_stuff.h | 3 +- src/mn_setup.c | 4 + src/wi_stuff.c | 2 +- 12 files changed, 417 insertions(+), 20 deletions(-) create mode 100644 src/hu_command.c create mode 100644 src/hu_command.h diff --git a/autoload/all-all/woofhud.lmp b/autoload/all-all/woofhud.lmp index 5e1c6388..e8c3fe81 100644 --- a/autoload/all-all/woofhud.lmp +++ b/autoload/all-all/woofhud.lmp @@ -1,11 +1,14 @@ hud 0 +title bottomleft rate topleft monsec topleft sttime topleft coord topright fps topright +cmd bottomright hud 1 +title bottomleft rate topleft armor bottomleft health bottomleft @@ -16,8 +19,10 @@ monsec bottomleft sttime bottomleft coord topright fps topright +cmd bottomright hud 2 +title bottomleft rate topleft health topright armor topright @@ -26,5 +31,6 @@ weapon bottomright keys bottomleft monsec bottomleft sttime bottomleft -coord topright +coord topright fps topright +cmd bottomright diff --git a/docs/woofhud.md b/docs/woofhud.md index a5b3aac9..bfcc8d47 100644 --- a/docs/woofhud.md +++ b/docs/woofhud.md @@ -17,8 +17,8 @@ The following lines start with the name of the HUD widget which is to be positio Possible values for the HUD widget names: * "title" or "levelname" - * "message" (new in Woof! 12.0.0) - * "secret" (new in Woof! 12.0.0) + * "message" + * "secret" * "armor" * "health" * "ammo" @@ -28,6 +28,7 @@ Possible values for the HUD widget names: * "sttime" or "time" * "coord" or "coords" * "fps" or "rate" + * "cmd" or "commands" Possible values for the widget position keywords: @@ -49,13 +50,16 @@ The following example represents the current default alignments of the Boom HUD ``` hud 0 title bottomleft -monsec bottomleft -sttime bottomleft +rate topleft +monsec topleft +sttime topleft coord topright fps topright +cmd bottomright hud 1 title bottomleft +rate topleft armor bottomleft health bottomleft ammo bottomleft @@ -65,9 +69,11 @@ monsec bottomleft sttime bottomleft coord topright fps topright +cmd bottomright hud 2 title bottomleft +rate topleft health topright armor topright ammo bottomright @@ -77,6 +83,7 @@ monsec bottomleft sttime bottomleft coord topright fps topright +cmd bottomright ``` An alternative approach to the distributed HUD, using absolute screen coordinates, could look like this: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3caf8f6d..21c0f52a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -28,6 +28,7 @@ set(WOOF_SOURCES f_wipe.c f_wipe.h font.h g_game.c g_game.h + hu_command.c hu_command.h hu_lib.c hu_lib.h hu_obituary.c hu_obituary.h hu_stuff.c hu_stuff.h diff --git a/src/g_game.c b/src/g_game.c index 1352e952..2f6c5257 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1055,6 +1055,7 @@ static void G_DoLoadLevel(void) P_SetupLevel (gameepisode, gamemap, 0, gameskill); MN_UpdateFreeLook(); + HU_UpdateTurnFormat(); // [Woof!] Do not reset chosen player view across levels in multiplayer // demo playback. However, it must be reset when starting a new game. @@ -2823,6 +2824,8 @@ void G_Ticker(void) if (demoplayback) ++playback_tic; + HU_UpdateCommandHistory(&players[displayplayer].cmd); + // check for special buttons for (i=0; i + +#include "d_event.h" +#include "doomstat.h" +#include "hu_command.h" +#include "i_printf.h" +#include "m_misc.h" +#include "v_video.h" + +boolean hud_command_history; +int hud_command_history_size; +boolean hud_hide_empty_commands; + +typedef struct +{ + signed char forwardmove; + signed char sidemove; + short angleturn; + boolean attack; + boolean use; + byte change; +} hud_cmd_t; + +typedef struct hud_cmd_item_s +{ + struct hud_cmd_item_s *prev, *next; + char buf[HU_MAXLINELENGTH]; + hud_cmd_t hud_cmd; + int count; +} hud_cmd_item_t; + +static hud_cmd_item_t hud_cmd_items[HU_MAXMESSAGES]; +static hud_cmd_item_t *current = hud_cmd_items; +static boolean lowres_turn_format; + +void HU_UpdateTurnFormat(void) +{ + const boolean playdemo = (gameaction == ga_playdemo || demoplayback); + lowres_turn_format = (!playdemo && lowres_turn) || (playdemo && !longtics); +} + +void HU_InitCommandHistory(void) +{ + for (int i = 1; i < HU_MAXMESSAGES; i++) + { + hud_cmd_items[i].prev = &hud_cmd_items[i - 1]; + hud_cmd_items[i - 1].next = &hud_cmd_items[i]; + } + + hud_cmd_items[0].prev = &hud_cmd_items[HU_MAXMESSAGES - 1]; + hud_cmd_items[HU_MAXMESSAGES - 1].next = &hud_cmd_items[0]; +} + +void HU_ResetCommandHistory(void) +{ + for (int i = 0; i < HU_MAXMESSAGES; i++) + { + memset(&hud_cmd_items[i].hud_cmd, 0, sizeof(hud_cmd_t)); + hud_cmd_items[i].count = 0; + hud_cmd_items[i].buf[0] = '\0'; + } +} + +static void TicToHudCmd(hud_cmd_t *hud_cmd, const ticcmd_t *cmd) +{ + hud_cmd->forwardmove = cmd->forwardmove; + hud_cmd->sidemove = cmd->sidemove; + + if (lowres_turn_format) + { + hud_cmd->angleturn = (cmd->angleturn + 128) >> 8; + } + else + { + hud_cmd->angleturn = cmd->angleturn; + } + + if (cmd->buttons && !(cmd->buttons & BT_SPECIAL)) + { + hud_cmd->attack = (cmd->buttons & BT_ATTACK) > 0; + hud_cmd->use = (cmd->buttons & BT_USE) > 0; + + if (cmd->buttons & BT_CHANGE) + { + hud_cmd->change = + 1 + ((cmd->buttons & BT_WEAPONMASK) >> BT_WEAPONSHIFT); + } + else + { + hud_cmd->change = 0; + } + } + else + { + hud_cmd->attack = false; + hud_cmd->use = false; + hud_cmd->change = 0; + } +} + +static boolean IsEmpty(const hud_cmd_t *hud_cmd) +{ + return (hud_cmd->forwardmove == 0 + && hud_cmd->sidemove == 0 + && hud_cmd->angleturn == 0 + && hud_cmd->attack == false + && hud_cmd->use == false + && hud_cmd->change == 0); +} + +static boolean IsEqual(const hud_cmd_t *hud_cmd1, const hud_cmd_t *hud_cmd2) +{ + return (hud_cmd1->forwardmove == hud_cmd2->forwardmove + && hud_cmd1->sidemove == hud_cmd2->sidemove + && hud_cmd1->angleturn == hud_cmd2->angleturn + && hud_cmd1->attack == hud_cmd2->attack + && hud_cmd1->use == hud_cmd2->use + && hud_cmd1->change == hud_cmd2->change); +} + +static void UpdateHudCmdText(hud_cmd_item_t *cmd_disp) +{ + const hud_cmd_t *hud_cmd = &cmd_disp->hud_cmd; + char *buf = cmd_disp->buf; + const int len = sizeof(cmd_disp->buf); + int i = M_snprintf(buf, len, "\x1b%c", '0' + CR_GRAY); + + if (cmd_disp->count) + { + i += M_snprintf(buf + i, len - i, "x%-3d ", cmd_disp->count + 1); + } + else + { + i += M_snprintf(buf + i, len - i, " "); + } + + if (hud_cmd->forwardmove > 0) + { + i += M_snprintf(buf + i, len - i, "MF%2d ", hud_cmd->forwardmove); + } + else if (hud_cmd->forwardmove < 0) + { + i += M_snprintf(buf + i, len - i, "MB%2d ", -hud_cmd->forwardmove); + } + else + { + i += M_snprintf(buf + i, len - i, " "); + } + + if (hud_cmd->sidemove > 0) + { + i += M_snprintf(buf + i, len - i, "SR%2d ", hud_cmd->sidemove); + } + else if (hud_cmd->sidemove < 0) + { + i += M_snprintf(buf + i, len - i, "SL%2d ", -hud_cmd->sidemove); + } + else + { + i += M_snprintf(buf + i, len - i, " "); + } + + if (lowres_turn_format) + { + if (hud_cmd->angleturn > 0) + { + i += M_snprintf(buf + i, len - i, "TL%2d ", hud_cmd->angleturn); + } + else if (hud_cmd->angleturn < 0) + { + i += M_snprintf(buf + i, len - i, "TR%2d ", -hud_cmd->angleturn); + } + else + { + i += M_snprintf(buf + i, len - i, " "); + } + } + else + { + if (hud_cmd->angleturn > 0) + { + i += M_snprintf(buf + i, len - i, "TL%5d ", hud_cmd->angleturn); + } + else if (hud_cmd->angleturn < 0) + { + i += M_snprintf(buf + i, len - i, "TR%5d ", -hud_cmd->angleturn); + } + else + { + i += M_snprintf(buf + i, len - i, " "); + } + } + + if (hud_cmd->attack) + { + i += M_snprintf(buf + i, len - i, "A "); + } + else + { + i += M_snprintf(buf + i, len - i, " "); + } + + if (hud_cmd->use) + { + i += M_snprintf(buf + i, len - i, "U "); + } + else + { + i += M_snprintf(buf + i, len - i, " "); + } + + if (hud_cmd->change) + { + i += M_snprintf(buf + i, len - i, "C%d", hud_cmd->change); + } + else + { + i += M_snprintf(buf + i, len - i, " "); + } +} + +void HU_UpdateCommandHistory(const ticcmd_t *cmd) +{ + hud_cmd_t hud_cmd; + + if (!STRICTMODE(hud_command_history)) + { + return; + } + + TicToHudCmd(&hud_cmd, cmd); + + if (hud_hide_empty_commands && IsEmpty(&hud_cmd)) + { + return; + } + + if (IsEqual(&hud_cmd, ¤t->hud_cmd)) + { + current->count++; + } + else + { + current->count = 0; + current = current->next; + current->hud_cmd = hud_cmd; + } + + UpdateHudCmdText(current); +} + +void HU_BuildCommandHistory(hu_multiline_t *const multiline) +{ + hud_cmd_item_t *hud_cmd = current; + + for (int i = 0; i < hud_command_history_size; i++) + { + HUlib_add_string_keep_space(multiline, hud_cmd->buf); + hud_cmd = hud_cmd->prev; + } +} diff --git a/src/hu_command.h b/src/hu_command.h new file mode 100644 index 00000000..8ed1a420 --- /dev/null +++ b/src/hu_command.h @@ -0,0 +1,38 @@ +// +// Copyright(C) 2022 Ryan Krafnick +// Copyright(C) 2024 ceski +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Command History HUD Widget +// + +#ifndef __HU_COMMAND__ +#define __HU_COMMAND__ + +#include "doomtype.h" +#include "hu_lib.h" + +struct hu_multiline_s; +struct ticcmd_s; + +extern boolean hud_command_history; +extern int hud_command_history_size; +extern boolean hud_hide_empty_commands; + +void HU_UpdateTurnFormat(void); +void HU_InitCommandHistory(void); +void HU_ResetCommandHistory(void); +void HU_UpdateCommandHistory(const struct ticcmd_s *cmd); +void HU_BuildCommandHistory(struct hu_multiline_s *const multiline); + +#endif diff --git a/src/hu_lib.c b/src/hu_lib.c index 28ecf47e..416aa64e 100644 --- a/src/hu_lib.c +++ b/src/hu_lib.c @@ -160,7 +160,8 @@ static inline void inc_cur_line (hu_multiline_t *const m) // [FG] add string to line, increasing its (length and) width -static void add_string_to_line (hu_line_t *const l, const hu_font_t *const f, const char *s) +static void add_string_to_line(hu_line_t *const l, const hu_font_t *const f, + const char *s, boolean keep_space) { int w = 0; unsigned char c; @@ -189,8 +190,11 @@ static void add_string_to_line (hu_line_t *const l, const hu_font_t *const f, co add_char_to_line(l, c); } - while (*--s == ' ') - w -= f->space_width; + if (!keep_space) + { + while (*--s == ' ') + w -= f->space_width; + } l->width += w; } @@ -205,10 +209,10 @@ void HUlib_add_strings_to_cur_line (hu_multiline_t *const m, const char *prefix, if (prefix) { - add_string_to_line(l, *m->font, prefix); + add_string_to_line(l, *m->font, prefix, false); } - add_string_to_line(l, *m->font, s); + add_string_to_line(l, *m->font, s, false); inc_cur_line(m); } @@ -218,6 +222,15 @@ void HUlib_add_string_to_cur_line (hu_multiline_t *const m, const char *s) HUlib_add_strings_to_cur_line(m, NULL, s); } +void HUlib_add_string_keep_space(hu_multiline_t *const m, const char *s) +{ + hu_line_t *const l = m->lines[m->curline]; + + HUlib_clear_line(l); + add_string_to_line(l, *m->font, s, true); + inc_cur_line(m); +} + // [FG] horizontal and vertical alignment static int horz_align_widget(const hu_widget_t *const w, const hu_line_t *const l, const align_t h_align) diff --git a/src/hu_lib.h b/src/hu_lib.h index 580f5c67..88507806 100644 --- a/src/hu_lib.h +++ b/src/hu_lib.h @@ -53,7 +53,7 @@ extern struct patch_s **hu_font; #define HU_MAXLINELENGTH 120 //jff 2/26/98 maximum number of messages allowed in refresh list -#define HU_MAXMESSAGES 8 +#define HU_MAXMESSAGES 20 typedef enum { @@ -134,6 +134,7 @@ void HUlib_clear_all_lines (hu_multiline_t *const m); void HUlib_add_string_to_cur_line (hu_multiline_t *const m, const char *s); void HUlib_add_strings_to_cur_line (hu_multiline_t *const m, const char *prefix, const char *s); +void HUlib_add_string_keep_space(hu_multiline_t *const m, const char *s); void HUlib_draw_widget (const hu_widget_t *const w); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index fc1022fa..bb338a53 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -110,6 +110,7 @@ static player_t *plr; static hu_font_t big_font = {.space_width = 4, .tab_width = 15, .tab_mask = ~15}, sml_font = {.space_width = 5, .tab_width = 7, .tab_mask = ~7}; static hu_font_t *doom_font = &big_font, *boom_font = &sml_font; +static hu_font_t *cmd_font = &sml_font; patch_t **hu_font = big_font.patches; static int CR_BLUE = CR_BLUE1; @@ -139,6 +140,7 @@ static hu_multiline_t w_sttime; // time above status bar static hu_multiline_t w_coord; static hu_multiline_t w_fps; static hu_multiline_t w_rate; +static hu_multiline_t w_cmd; #define MAX_HUDS 3 #define MAX_WIDGETS 16 @@ -429,6 +431,8 @@ void HU_Init(void) // [FG] support crosshair patches from extras.wad HU_InitCrosshair(); + HU_InitCommandHistory(); + HU_InitObituaries(); HU_ParseHUD(); @@ -496,6 +500,7 @@ static void HU_widget_build_armor (void); static void HU_widget_build_coord (void); static void HU_widget_build_fps (void); static void HU_widget_build_rate (void); +static void HU_widget_build_cmd(void); static void HU_widget_build_health (void); static void HU_widget_build_keys (void); static void HU_widget_build_frag (void); @@ -607,6 +612,12 @@ void HU_Start(void) // [FG] draw the IDRATE widget exclusively w_rate.exclusive = true; + HUlib_init_multiline(&w_cmd, hud_command_history_size, + &cmd_font, colrngs[hudcolor_xyco], + NULL, HU_widget_build_cmd); + // Draw command history bottom up. + w_cmd.bottomup = true; + HU_set_centered_message(); HU_disable_all_widgets(); @@ -1237,6 +1248,11 @@ static void HU_widget_build_rate (void) } } +static void HU_widget_build_cmd(void) +{ + HU_BuildCommandHistory(&w_cmd); +} + // Crosshair static boolean hud_crosshair_health; @@ -1439,17 +1455,35 @@ void HU_Drawer(void) } // [FG] draw Time widget on intermission screen -void WI_DrawTimeWidget(void) +void WI_DrawWidgets(void) { - const hu_widget_t w = {&w_sttime, align_left, align_top}; + HUlib_reset_align_offsets(); if (hud_level_time & HUD_WIDGET_HUD) { - HUlib_reset_align_offsets(); + const hu_widget_t w = {&w_sttime, align_left, align_top}; // leveltime is already added to totalleveltimes before WI_Start() //HU_widget_build_sttime(); HUlib_draw_widget(&w); } + + if (STRICTMODE(hud_command_history)) + { + hu_widget_t *w = widgets[hud_active]; + + while (w->multiline) + { + if (w->multiline == &w_cmd + && ((w->multiline->on && *w->multiline->on) || w->multiline->built)) + { + w_cmd.built = false; + HU_cond_build_widget(&w_cmd, true); + HUlib_draw_widget(w); + break; + } + w++; + } + } } // @@ -1627,6 +1661,7 @@ void HU_Ticker(void) HU_cond_build_widget(&w_fps, plr->cheats & CF_SHOWFPS); HU_cond_build_widget(&w_rate, plr->cheats & CF_RENDERSTATS); + HU_cond_build_widget(&w_cmd, STRICTMODE(hud_command_history)); if (hud_displayed && scaledviewheight == SCREENHEIGHT && @@ -1880,6 +1915,7 @@ static const struct { {"coord", "coords", &w_coord}, {"fps", NULL, &w_fps}, {"rate", NULL, &w_rate}, + {"cmd", "commands", &w_cmd}, {NULL}, }; @@ -2138,10 +2174,6 @@ void HU_BindHUDVariables(void) "Display HUD"); M_BindNum("hud_active", &hud_active, NULL, 2, 0, 2, ss_stat, wad_yes, "HUD layout (by default: 0 = Minimal; 1 = Compact; 2 = Distributed)"); - M_BindNum("hud_player_coords", &hud_player_coords, NULL, - HUD_WIDGET_AUTOMAP, HUD_WIDGET_OFF, HUD_WIDGET_ALWAYS, - ss_stat, wad_no, - "Show player coordinates widget (1 = On automap; 2 = On HUD; 3 = Always)"); M_BindNum("hud_level_stats", &hud_level_stats, NULL, HUD_WIDGET_OFF, HUD_WIDGET_OFF, HUD_WIDGET_ALWAYS, ss_stat, wad_no, @@ -2151,6 +2183,16 @@ void HU_BindHUDVariables(void) HUD_WIDGET_OFF, HUD_WIDGET_OFF, HUD_WIDGET_ALWAYS, ss_stat, wad_no, "Show level time widget (1 = On automap, 2 = On HUD, 3 = Always)"); + M_BindNum("hud_player_coords", &hud_player_coords, NULL, + HUD_WIDGET_AUTOMAP, HUD_WIDGET_OFF, HUD_WIDGET_ALWAYS, + ss_stat, wad_no, + "Show player coordinates widget (1 = On automap; 2 = On HUD; 3 = Always)"); + M_BindBool("hud_command_history", &hud_command_history, NULL, false, ss_stat, + wad_no, "Show command history widget"); + BIND_NUM(hud_command_history_size, 10, 1, HU_MAXMESSAGES, + "Number of commands to display for command history widget"); + BIND_BOOL(hud_hide_empty_commands, true, + "Hide empty commands from command history widget"); M_BindBool("hud_time_use", &hud_time_use, NULL, false, ss_stat, wad_no, "Show split time when pressing the use-button"); M_BindNum("hud_type", &hud_type, NULL, diff --git a/src/hu_stuff.h b/src/hu_stuff.h index 98f65084..23fef0a8 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -21,6 +21,7 @@ #include "doomdef.h" #include "doomtype.h" +#include "hu_command.h" struct event_s; struct mobj_s; @@ -48,7 +49,7 @@ boolean HU_DemoProgressBar(boolean force); void HU_ResetMessageColors(void); -void WI_DrawTimeWidget(void); +void WI_DrawWidgets(void); // killough 5/2/98: moved from m_misc.c: diff --git a/src/mn_setup.c b/src/mn_setup.c index d7feb429..bdfa2fa1 100644 --- a/src/mn_setup.c +++ b/src/mn_setup.c @@ -1436,6 +1436,10 @@ static setup_menu_t stat_settings2[] = { {"Show Player Coords", S_CHOICE | S_STRICT, M_X, M_SPC, {"hud_player_coords"}, m_null, input_null, str_show_widgets}, + {"Show Command History", S_ONOFF | S_STRICT, M_X, M_SPC, + {"hud_command_history"}, m_null, input_null, str_empty, + HU_ResetCommandHistory}, + {"Use-Button Timer", S_ONOFF, M_X, M_SPC, {"hud_time_use"}}, MI_GAP, diff --git a/src/wi_stuff.c b/src/wi_stuff.c index 8a71c497..586d97c8 100644 --- a/src/wi_stuff.c +++ b/src/wi_stuff.c @@ -2139,7 +2139,7 @@ void WI_Drawer (void) else WI_drawStats(); // [FG] draw Time widget on intermission screen - WI_DrawTimeWidget(); + WI_DrawWidgets(); break; case ShowNextLoc: