Splitscreen Director HUD; replace freecam HUD

This commit is contained in:
James R 2023-10-03 20:25:02 -07:00
parent 9fa2e3da5f
commit 1f3a9a4758
5 changed files with 253 additions and 124 deletions

View file

@ -1,4 +1,5 @@
target_sources(SRB2SDL2 PRIVATE
powerup.cpp
spectator.cpp
timer.cpp
)

247
src/hud/spectator.cpp Normal file
View file

@ -0,0 +1,247 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#include <initializer_list>
#include <optional>
#include <utility>
#include <fmt/format.h>
#include "../v_draw.hpp"
#include "../command.h"
#include "../d_clisrv.h"
#include "../d_player.h"
#include "../doomdef.h"
#include "../doomstat.h"
#include "../g_game.h"
#include "../g_party.h"
#include "../i_time.h"
#include "../k_director.h"
#include "../k_hud.h"
#include "../p_local.h"
#include "../r_fps.h"
extern "C" consvar_t cv_maxplayers;
using srb2::Draw;
namespace
{
struct List
{
struct Field
{
Field(const char* label, Draw::Button button, std::optional<bool> pressed = {}) :
label_(Draw::TextElement(label).font(Draw::Font::kThin)),
button_(button),
pressed_(pressed)
{
}
int width() const { return label_.width() + kButtonWidth + kButtonMargin + kFieldSpacing; }
void draw(const Draw& row, bool left) const
{
Draw col = row.x(left ? kButtonWidth + kButtonMargin : kFieldSpacing);
col.text(label_);
col = col.x(left ? -(kButtonWidth + kButtonMargin) : width() - (kButtonWidth + kFieldSpacing));
if (r_splitscreen)
{
auto small_button_offset = [&]
{
switch (button_)
{
case Draw::Button::l:
case Draw::Button::r:
return -4;
default:
return -2;
}
};
col.y(small_button_offset()).small_button(button_, pressed_);
}
else
{
col.y(-4).button(button_, pressed_);
}
}
private:
static constexpr int kButtonWidth = 14;
static constexpr int kButtonMargin = 2;
static constexpr int kFieldSpacing = 8;
Draw::TextElement label_;
Draw::Button button_;
std::optional<bool> pressed_;
};
List(int x, int y) : row_(split_draw(x, y, left_)) {}
void insert(std::initializer_list<Field> fields)
{
auto total_width = [&fields]
{
int width = 0;
for (const Field& field : fields)
{
width += field.width();
}
return width;
};
Draw col = left_ ? row_ : row_.x(-total_width());
for (const Field& field : fields)
{
field.draw(col, left_);
col = col.x(field.width());
}
row_ = row_.y(r_splitscreen ? -13 : -17);
}
private:
bool left_ = r_splitscreen > 1 && R_GetViewNumber() & 1;
Draw row_;
static Draw split_draw(int x, int y, bool left)
{
return Draw(
left ? x : (BASEVIDWIDTH / (r_splitscreen > 1 ? 2 : 1)) - x,
(BASEVIDHEIGHT / (r_splitscreen ? 2 : 1)) - y
)
.align(Draw::Align::kLeft)
.flags(
V_SNAPTOBOTTOM |
(left ? V_SNAPTOLEFT : V_SNAPTORIGHT) |
(r_splitscreen > 1 ? V_HUDTRANS : V_SLIDEIN) |
V_SPLITSCREEN
);
}
};
}; // namespace
void K_drawSpectatorHUD(boolean director)
{
const UINT8 viewnum = R_GetViewNumber();
UINT8 numingame = 0;
for (UINT8 i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && !players[i].spectator)
{
numingame++;
}
}
player_t* player = [viewnum]() -> player_t*
{
if (viewnum >= G_PartySize(consoleplayer))
{
return nullptr;
}
UINT8 p = G_PartyMember(consoleplayer, viewnum);
if (!playeringame[p] || players[p].spectator == false)
{
return nullptr;
}
return &players[p];
}();
List list = [director]
{
switch (r_splitscreen)
{
case 0:
return List(director ? 80 : 20, 20);
case 1:
return List(40, 20);
default:
return List(10, 20);
}
}();
if (player)
{
std::string label = [player]
{
if (player->flashing)
{
return ". . .";
}
else if (player->pflags & PF_WANTSTOJOIN)
{
return "Cancel Join";
}
else
{
return "Join";
}
}();
if (cv_maxplayers.value)
{
label += fmt::format(" [{}/{}]", numingame, cv_maxplayers.value);
}
list.insert({{label.c_str(), Draw::Button::l}});
}
if (director || camera[viewnum].freecam)
{
// Not locked into freecam -- can toggle it.
if (director)
{
list.insert({{"Freecam", Draw::Button::c}});
}
else
{
bool press = D_LocalTiccmd(viewnum)->buttons & BT_RESPAWN;
const char* label = (press && I_GetTime() % 16 < 8) ? "> <" : ">< ";
list.insert({{label, Draw::Button::y, press}, {"Exit", Draw::Button::c}});
}
}
if (director)
{
if (numingame > 1)
{
list.insert({{"+", Draw::Button::a}, {"-", Draw::Button::x}});
}
if (player)
{
list.insert({{K_DirectorIsEnabled(viewnum) ? "\x82" "Director" : "Director", Draw::Button::r}});
}
}
else
{
auto bt = D_LocalTiccmd(viewnum)->buttons;
list.insert({{"", Draw::Button::r, bt & BT_DRIFT}, {"Pivot", Draw::Button::b, bt & BT_LOOKBACK}});
list.insert({{"+", Draw::Button::a, bt & BT_ACCELERATE}, {"-", Draw::Button::x, bt & BT_BRAKE}});
}
}

View file

@ -5169,77 +5169,6 @@ void K_drawButtonAnim(INT32 x, INT32 y, INT32 flags, patch_t *button[2], tic_t a
K_drawButton(x << FRACBITS, y << FRACBITS, flags, button, anim);
}
static void K_DrawDirectorButton(INT32 idx, const char *label, patch_t *kp[2], INT32 textflags)
{
INT32 flags = V_SNAPTORIGHT | V_SLIDEIN | V_SPLITSCREEN;
INT32 x = (BASEVIDWIDTH/2) - 10;
INT32 y = (idx * 16);
if (r_splitscreen <= 1)
{
x = BASEVIDWIDTH - 60;
if (r_splitscreen == 0)
{
y += BASEVIDHEIGHT - 78;
}
}
textflags |= flags;
K_drawButtonAnim(x, y - 4, flags, kp, leveltime);
V_DrawRightAlignedThinString(x - 2, y, textflags, label);
}
static void K_drawDirectorHUD(void)
{
const UINT8 viewnum = R_GetViewNumber();
const INT32 p = viewnum < G_PartySize(consoleplayer) ? G_PartyMember(consoleplayer, viewnum) : -1;
const char *itemtxt = "Join";
UINT8 offs = 0;
UINT8 numingame = 0;
UINT8 i;
if (!LUA_HudEnabled(hud_textspectator))
{
return;
}
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && !players[i].spectator)
numingame++;
if (numingame > 1 && r_splitscreen == 0) // simplifies things a lot
{
K_DrawDirectorButton(1, "Next Player", kp_button_a[0], 0);
K_DrawDirectorButton(2, "Prev Player", kp_button_x[0], 0);
offs = 2;
}
K_DrawDirectorButton(offs + 1, "Freecam", kp_button_c[0], 0);
if (p == -1 || !playeringame[p] || players[p].spectator == false)
{
return;
}
// TODO: this is too close to the screen bottom
K_DrawDirectorButton(offs + 2, "Director", kp_button_r,
(K_DirectorIsEnabled(viewnum) ? V_YELLOWMAP : 0));
if (players[p].flashing)
itemtxt = ". . .";
else if (players[p].pflags & PF_WANTSTOJOIN)
itemtxt = "Cancel Join";
if (cv_maxplayers.value)
{
itemtxt = va("%s [%d/%d]", itemtxt, numingame, cv_maxplayers.value);
}
K_DrawDirectorButton(0, itemtxt, kp_button_l, 0);
}
static void K_drawDistributionDebugger(void)
{
itemroulette_t rouletteData = {0};
@ -5666,9 +5595,9 @@ void K_drawKartHUD(void)
if (stplyr->karthud[khud_trickcool])
K_drawTrickCool();
if (freecam)
if ((freecam || stplyr->spectator) && LUA_HudEnabled(hud_textspectator))
{
K_DrawDirectorButton(3, "Freecam", kp_button_c[0], 0);
K_drawSpectatorHUD(false);
}
if (modeattacking || freecam) // everything after here is MP and debug only
@ -5687,9 +5616,9 @@ void K_drawKartHUD(void)
K_drawKartPowerUps();
if (K_DirectorIsAvailable(viewnum) == true)
if (K_DirectorIsAvailable(viewnum) == true && LUA_HudEnabled(hud_textspectator))
{
K_drawDirectorHUD();
K_drawSpectatorHUD(true);
}
if (cv_kartdebugdistribution.value)

View file

@ -43,6 +43,7 @@ void K_LoadKartHUDGraphics(void);
void K_drawKartHUD(void);
void K_drawKartFreePlay(void);
void K_drawKartPowerUps(void);
void K_drawSpectatorHUD(boolean director);
void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, UINT8 mode);
void K_drawKart2PTimestamp(void);
void K_drawKart4PTimestamp(void);

View file

@ -1215,55 +1215,6 @@ static void ST_overlayDrawer(void)
}
}
if (!hu_showscores && netgame && !mapreset)
{
if (stplyr->spectator && displayplayers[viewnum] == g_localplayers[viewnum] && LUA_HudEnabled(hud_textspectator))
{
const char *itemtxt = M_GetText("Item - Join Game");
if (stplyr->flashing)
itemtxt = M_GetText("Item - . . .");
else if (stplyr->pflags & PF_WANTSTOJOIN)
itemtxt = M_GetText("Item - Cancel Join");
else if (G_GametypeHasTeams())
itemtxt = M_GetText("Item - Join Team");
if (cv_maxplayers.value)
{
UINT8 numingame = 0;
UINT8 i;
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && !players[i].spectator)
numingame++;
itemtxt = va("%s (%s: %d)", itemtxt, M_GetText("Slots left"), max(0, cv_maxplayers.value - numingame));
}
// SRB2kart: changed positions & text
if (r_splitscreen)
{
V_DrawThinString(2, (BASEVIDHEIGHT/2)-20, V_YELLOWMAP|V_HUDTRANSHALF|V_SPLITSCREEN|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("- SPECTATING -"));
V_DrawThinString(2, (BASEVIDHEIGHT/2)-10, V_HUDTRANSHALF|V_SPLITSCREEN|V_SNAPTOLEFT|V_SNAPTOBOTTOM, itemtxt);
}
else
{
V_DrawString(2, BASEVIDHEIGHT-40, V_HUDTRANSHALF|V_SPLITSCREEN|V_YELLOWMAP|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("- SPECTATING -"));
V_DrawString(2, BASEVIDHEIGHT-30, V_HUDTRANSHALF|V_SPLITSCREEN|V_SNAPTOLEFT|V_SNAPTOBOTTOM, itemtxt);
if (stplyr->cmd.buttons & BT_LOOKBACK)
{
V_DrawString(2, BASEVIDHEIGHT-20, V_HUDTRANSHALF|V_SPLITSCREEN|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("Lookback - Camera pivot"));
V_DrawString(2, BASEVIDHEIGHT-10, V_HUDTRANSHALF|V_SPLITSCREEN|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("Aim forward/backward"));
}
else
{
V_DrawString(2, BASEVIDHEIGHT-20, V_HUDTRANSHALF|V_SPLITSCREEN|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("Accelerate - Float"));
V_DrawString(2, BASEVIDHEIGHT-10, V_HUDTRANSHALF|V_SPLITSCREEN|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("Brake - Sink"));
}
}
}
}
K_DrawMidVote();
K_DrawDialogue();