mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-05-30 08:40:54 +00:00
439 lines
9.6 KiB
C
439 lines
9.6 KiB
C
|
|
//**************************************************************************
|
|
//**
|
|
//** ct_chat.c : Heretic 2 : Raven Software, Corp.
|
|
//**
|
|
//** $RCSfile: ct_chat.c,v $
|
|
//** $Revision: 1.12 $
|
|
//** $Date: 96/01/16 10:35:26 $
|
|
//** $Author: bgokey $
|
|
//**
|
|
//**************************************************************************
|
|
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include "doomdef.h"
|
|
#include "z_zone.h"
|
|
#include "m_swap.h"
|
|
#include "hu_stuff.h"
|
|
#include "w_wad.h"
|
|
#include "s_sound.h"
|
|
#include "doomstat.h"
|
|
#include "st_stuff.h"
|
|
#include "dstrings.h"
|
|
#include "c_consol.h"
|
|
#include "c_dispch.h"
|
|
#include "c_cvars.h"
|
|
#include "v_text.h"
|
|
#include "v_video.h"
|
|
|
|
#define QUEUESIZE 128
|
|
#define MESSAGESIZE 128
|
|
#define MESSAGELEN 265
|
|
#define HU_INPUTX 0
|
|
#define HU_INPUTY (0 + (SHORT(hu_font[0]->height) +1))
|
|
|
|
extern cvar_t *con_scaletext;
|
|
|
|
// Public data
|
|
|
|
void CT_Init (void);
|
|
void CT_Drawer (void);
|
|
BOOL CT_Responder (event_t *ev);
|
|
void Cmd_MessageMode (player_t *plyr, int argc, char **argv);
|
|
void Cmd_Say (player_t *plyr, int argc, char **argv);
|
|
void Cmd_MessageMode2 (player_t *plyr, int argc, char **argv);
|
|
void Cmd_Say_Team (player_t *plyr, int argc, char **argv);
|
|
void HU_DrawScores (player_t *plyr);
|
|
|
|
int chatmodeon;
|
|
|
|
patch_t *hu_font[HU_FONTSIZE];
|
|
|
|
// Private data
|
|
|
|
static void CT_ClearChatMessage (void);
|
|
static void CT_AddChar (char c);
|
|
static void CT_BackSpace (void);
|
|
static void ShoveChatStr (const char *str, int who);
|
|
|
|
static int len;
|
|
static byte ChatQueue[QUEUESIZE];
|
|
|
|
BOOL altdown;
|
|
|
|
cvar_t *chat_macros[10];
|
|
|
|
//===========================================================================
|
|
//
|
|
// CT_Init
|
|
//
|
|
// Initialize chat mode data
|
|
//===========================================================================
|
|
|
|
void CT_Init (void)
|
|
{
|
|
int i, j, sub;
|
|
char *tplate, buffer[12];
|
|
|
|
len = 0; // initialize the queue index
|
|
chatmodeon = 0;
|
|
ChatQueue[0] = 0;
|
|
|
|
// load the heads-up font
|
|
j = HU_FONTSTART;
|
|
|
|
// [RH] Quick hack to handle the FONTA of Heretic and Hexen
|
|
if (W_CheckNumForName ("FONTA01") >= 0) {
|
|
tplate = "FONTA%02u";
|
|
sub = HU_FONTSTART - 1;
|
|
} else {
|
|
tplate = "STCFN%.3d";
|
|
sub = 0;
|
|
}
|
|
|
|
for (i = 0; i < HU_FONTSIZE; i++)
|
|
{
|
|
sprintf (buffer, tplate, j++ - sub);
|
|
hu_font[i] = (patch_t *) W_CacheLumpName(buffer, PU_STATIC);
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// CT_Stop
|
|
//
|
|
//===========================================================================
|
|
|
|
void CT_Stop (void)
|
|
{
|
|
chatmodeon = 0;
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// CT_Responder
|
|
//
|
|
//===========================================================================
|
|
|
|
BOOL CT_Responder (event_t *ev)
|
|
{
|
|
unsigned char c;
|
|
|
|
if (ev->data1 == KEY_RALT || ev->data1 == KEY_LALT)
|
|
{
|
|
altdown = (ev->type == ev_keydown);
|
|
return false;
|
|
}
|
|
else if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT)
|
|
{
|
|
return false;
|
|
}
|
|
else if (gamestate != GS_LEVEL || ev->type != ev_keydown)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (chatmodeon)
|
|
{
|
|
c = ev->data3; // [RH] Use localized keymap
|
|
|
|
// send a macro
|
|
if (altdown)
|
|
{
|
|
if (ev->data2 >= '0' && ev->data2 <= '9')
|
|
{
|
|
ShoveChatStr (chat_macros[ev->data2 - '0']->string, chatmodeon - 1);
|
|
CT_Stop ();
|
|
return true;
|
|
}
|
|
}
|
|
if (ev->data1 == KEY_ENTER)
|
|
{
|
|
ShoveChatStr (ChatQueue, chatmodeon - 1);
|
|
CT_Stop ();
|
|
return true;
|
|
}
|
|
else if (ev->data1 == KEY_ESCAPE)
|
|
{
|
|
CT_Stop ();
|
|
return true;
|
|
}
|
|
else if (ev->data1 == KEY_BACKSPACE)
|
|
{
|
|
CT_BackSpace ();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
CT_AddChar (c);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// CT_Drawer
|
|
//
|
|
//===========================================================================
|
|
|
|
void CT_Drawer (void)
|
|
{
|
|
if (chatmodeon)
|
|
{
|
|
static const char *prompt = "Say: ";
|
|
void (*drawfunc)(int,int,int,screen_t*,patch_t*);
|
|
int i, x, c, scalex, y, promptwidth;
|
|
|
|
if (con_scaletext->value)
|
|
{
|
|
scalex = CleanXfac;
|
|
y = (!viewactive ? -30 : -10) * CleanYfac;
|
|
drawfunc = V_DrawCNMWrapper;
|
|
} else {
|
|
scalex = 1;
|
|
y = (!viewactive ? -30 : -10);
|
|
drawfunc = V_DrawWrapper;
|
|
}
|
|
|
|
y += (screen.height == realviewheight && viewactive) ? screen.height : ST_Y;
|
|
|
|
promptwidth = V_StringWidth (prompt) * scalex;
|
|
x = SHORT(hu_font['_' - HU_FONTSTART]->width) * scalex * 2 + promptwidth;
|
|
|
|
// figure out if the text is wider than the screen.
|
|
// if so, only draw the right-most portion of it.
|
|
for (i = len - 1; i >= 0 && x < screen.width; i--)
|
|
{
|
|
c = toupper(ChatQueue[i] & 0x7f) - HU_FONTSTART;
|
|
if (c < 0 || c >= HU_FONTSIZE)
|
|
{
|
|
x += 4 * scalex;
|
|
}
|
|
else
|
|
{
|
|
x += SHORT(hu_font[c]->width) * scalex;
|
|
}
|
|
}
|
|
|
|
if (i >= 0)
|
|
{
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
i = 0;
|
|
}
|
|
|
|
// draw the prompt, text, and cursor
|
|
ChatQueue[len] = '_';
|
|
ChatQueue[len+1] = '\0';
|
|
if (con_scaletext->value)
|
|
{
|
|
V_DrawTextClean (CR_RED, 0, y, prompt);
|
|
V_DrawTextClean (CR_GREY, promptwidth, y, ChatQueue + i);
|
|
}
|
|
else
|
|
{
|
|
V_DrawText (CR_RED, 0, y, prompt);
|
|
V_DrawText (CR_GREY, promptwidth, y, ChatQueue + i);
|
|
}
|
|
ChatQueue[len] = '\0';
|
|
|
|
BorderTopRefresh = true;
|
|
}
|
|
|
|
if (deathmatch->value &&
|
|
((Actions & ACTION_SHOWSCORES) ||
|
|
players[consoleplayer].camera->health <= 0))
|
|
{
|
|
HU_DrawScores (&players[consoleplayer]);
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// CT_AddChar
|
|
//
|
|
//===========================================================================
|
|
|
|
static void CT_AddChar (char c)
|
|
{
|
|
if (len < QUEUESIZE-2)
|
|
{
|
|
ChatQueue[len++] = c;
|
|
ChatQueue[len] = 0;
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// CT_BackSpace
|
|
//
|
|
// Backs up a space, when the user hits (obviously) backspace
|
|
//===========================================================================
|
|
|
|
static void CT_BackSpace (void)
|
|
{
|
|
if (len)
|
|
{
|
|
ChatQueue[--len] = 0;
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// CT_ClearChatMessage
|
|
//
|
|
// Clears out the data for the chat message.
|
|
//===========================================================================
|
|
|
|
static void CT_ClearChatMessage (void)
|
|
{
|
|
ChatQueue[0] = 0;
|
|
len = 0;
|
|
}
|
|
|
|
static void ShoveChatStr (const char *str, int who)
|
|
{
|
|
Net_WriteByte (DEM_SAY);
|
|
Net_WriteByte ((byte)who);
|
|
Net_WriteString (str);
|
|
}
|
|
|
|
void Cmd_MessageMode (player_t *plyr, int argc, char **argv)
|
|
{
|
|
chatmodeon = 1;
|
|
C_HideConsole ();
|
|
CT_ClearChatMessage ();
|
|
}
|
|
|
|
void Cmd_Say (player_t *plyr, int argc, char **argv)
|
|
{
|
|
if (argc > 1)
|
|
{
|
|
ShoveChatStr (BuildString (argc - 1, argv + 1), 0);
|
|
}
|
|
}
|
|
|
|
void Cmd_MessageMode2 (player_t *plyr, int argc, char **argv)
|
|
{
|
|
chatmodeon = 2;
|
|
C_HideConsole ();
|
|
CT_ClearChatMessage ();
|
|
}
|
|
|
|
void Cmd_Say_Team (player_t *plyr, int argc, char **argv)
|
|
{
|
|
if (argc > 1)
|
|
{
|
|
ShoveChatStr (BuildString (argc - 1, argv + 1), 1);
|
|
}
|
|
}
|
|
|
|
static int STACK_ARGS compare (const void *arg1, const void *arg2)
|
|
{
|
|
return players[*(int *)arg2].fragcount - players[*(int *)arg1].fragcount;
|
|
}
|
|
|
|
extern cvar_t *timelimit;
|
|
|
|
void HU_DrawScores (player_t *plyr)
|
|
{
|
|
char str[80];
|
|
int sortedplayers[MAXPLAYERS];
|
|
int i, j, x, y, maxwidth, margin;
|
|
int player;
|
|
|
|
if (plyr->camera->player)
|
|
player = plyr->camera->player - players;
|
|
else
|
|
player = plyr - players;
|
|
|
|
sortedplayers[MAXPLAYERS-1] = player;
|
|
for (i = 0, j = 0; j < MAXPLAYERS - 1; i++, j++) {
|
|
if (i == player)
|
|
i++;
|
|
sortedplayers[j] = i;
|
|
}
|
|
|
|
qsort (sortedplayers, MAXPLAYERS, sizeof(int), compare);
|
|
|
|
maxwidth = 0;
|
|
for (i = 0; i < MAXPLAYERS; i++) {
|
|
if (playeringame[i]) {
|
|
int width = V_StringWidth (players[i].userinfo.netname);
|
|
if (teamplay->value)
|
|
width += V_StringWidth (players[i].userinfo.team) + 24;
|
|
if (width > maxwidth)
|
|
maxwidth = width;
|
|
}
|
|
}
|
|
|
|
x = (screen.width >> 1) - (((maxwidth + 32 + 32 + 16) * CleanXfac) >> 1);
|
|
margin = x + 40 * CleanXfac;
|
|
|
|
y = (ST_Y >> 1) - (MAXPLAYERS * 6);
|
|
if (y < 48) y = 48;
|
|
|
|
if (deathmatch->value && timelimit->value && gamestate == GS_LEVEL) {
|
|
int timeleft = (int)(timelimit->value * TICRATE * 60) - level.time;
|
|
int hours, minutes, seconds;
|
|
|
|
if (timeleft < 0)
|
|
timeleft = 0;
|
|
|
|
hours = timeleft / (TICRATE * 3600);
|
|
timeleft -= hours * TICRATE * 3600;
|
|
minutes = timeleft / (TICRATE * 60);
|
|
timeleft -= minutes * TICRATE * 60;
|
|
seconds = timeleft / TICRATE;
|
|
|
|
if (hours)
|
|
sprintf (str, "Level ends in %02d:%02d:%02d", hours, minutes, seconds);
|
|
else
|
|
sprintf (str, "Level ends in %02d:%02d", minutes, seconds);
|
|
|
|
V_DrawTextClean (CR_GREY, screen.width/2 - V_StringWidth (str)/2*CleanXfac, y - 12 * CleanYfac, str);
|
|
}
|
|
|
|
for (i = 0; i < MAXPLAYERS && y < ST_Y - 12 * CleanYfac; i++) {
|
|
int color = players[sortedplayers[i]].userinfo.color;
|
|
|
|
if (playeringame[sortedplayers[i]]) {
|
|
if (screen.is8bit)
|
|
color = BestColor (DefaultPalette->basecolors,
|
|
RPART(color), GPART(color), BPART(color),
|
|
DefaultPalette->numcolors);
|
|
|
|
V_Clear (x, y, x + 24 * CleanXfac, y + SHORT(hu_font[0]->height) * CleanYfac, &screen, color);
|
|
|
|
sprintf (str, "%d", players[sortedplayers[i]].fragcount);
|
|
V_DrawTextClean (sortedplayers[i] == player ? CR_GREEN : CR_BRICK,
|
|
margin, y, str);
|
|
|
|
if (teamplay->value && players[sortedplayers[i]].userinfo.team[0])
|
|
sprintf (str, "%s (%s)", players[sortedplayers[i]].userinfo.netname,
|
|
players[sortedplayers[i]].userinfo.team);
|
|
else
|
|
strcpy (str, players[sortedplayers[i]].userinfo.netname);
|
|
|
|
if (sortedplayers[i] != player) {
|
|
if (demoplayback && sortedplayers[i] == consoleplayer)
|
|
color = CR_GOLD;
|
|
else
|
|
color = CR_GREY;
|
|
} else {
|
|
color = CR_GREEN;
|
|
}
|
|
|
|
V_DrawTextClean (color, margin + 32 * CleanXfac, y, str);
|
|
|
|
y += 10 * CleanYfac;
|
|
}
|
|
}
|
|
BorderNeedRefresh = true;
|
|
}
|