mirror of
https://github.com/nzp-team/quakec.git
synced 2024-11-22 11:51:11 +00:00
CLIENT: Handle chat in CSQC
This commit is contained in:
parent
fe547187e0
commit
bee0e764fc
6 changed files with 202 additions and 5 deletions
|
@ -8,4 +8,5 @@
|
||||||
../source/client/menu.qc
|
../source/client/menu.qc
|
||||||
../source/client/achievements.qc
|
../source/client/achievements.qc
|
||||||
../source/client/hud.qc
|
../source/client/hud.qc
|
||||||
|
../source/client/chat.qc
|
||||||
../source/client/main.qc
|
../source/client/main.qc
|
||||||
|
|
143
source/client/chat.qc
Normal file
143
source/client/chat.qc
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
client/chat.qc
|
||||||
|
|
||||||
|
Chat interception and custom drawing, based on Nuclide.
|
||||||
|
|
||||||
|
Copyright (C) 2021-2023 NZ:P Team
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to:
|
||||||
|
|
||||||
|
Free Software Foundation, Inc.
|
||||||
|
59 Temple Place - Suite 330
|
||||||
|
Boston, MA 02111-1307, USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
var float autocvar_cg_chatEnabled = true;
|
||||||
|
|
||||||
|
#define CHAT_LINES 10
|
||||||
|
#define CHAT_TIME 7
|
||||||
|
|
||||||
|
var int g_chatpos[2];
|
||||||
|
var float g_chattime;
|
||||||
|
var int g_chatlines = -1;
|
||||||
|
string g_chatbuffer[CHAT_LINES];
|
||||||
|
string g_chatbuffer_final;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* called every frame pretty much and prints whatever is in the chatbuffer.
|
||||||
|
* removes lines after some time, one at a time.
|
||||||
|
*/
|
||||||
|
void Chat_Draw()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (autocvar_cg_chatEnabled == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_chatpos[0] = GetUltraWideOffset() + 5;
|
||||||
|
g_chatpos[1] = 170;
|
||||||
|
|
||||||
|
if (g_chatlines < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove messages after a g_chattime has passed */
|
||||||
|
if (g_chattime < time) {
|
||||||
|
g_chatbuffer_final = "";
|
||||||
|
for (i = 0; i < g_chatlines; i++) {
|
||||||
|
if (g_chatbuffer[i+1] != __NULL__) {
|
||||||
|
g_chatbuffer[i] = g_chatbuffer[i+1];
|
||||||
|
}
|
||||||
|
if (i == 0)
|
||||||
|
g_chatbuffer_final = g_chatbuffer[i];
|
||||||
|
else
|
||||||
|
g_chatbuffer_final = sprintf("%s\n%s", g_chatbuffer_final, g_chatbuffer[i]);
|
||||||
|
}
|
||||||
|
g_chatbuffer[g_chatlines] = __NULL__;
|
||||||
|
g_chatlines--;
|
||||||
|
g_chattime = time + CHAT_TIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
int barlines = 0;
|
||||||
|
for(i = 0; i <= g_chatlines; i++) {
|
||||||
|
if (g_chatbuffer[i] == __NULL__)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strlen(g_chatbuffer[i]) > 48) {
|
||||||
|
barlines += strlen(g_chatbuffer[i])/48 + 2;
|
||||||
|
} else {
|
||||||
|
barlines++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drawfill ([g_chatpos[0] - 2, g_chatpos[1] - 2], [290, (barlines) * 8 + 4], [0, 0, 0], 0.65, 0);
|
||||||
|
drawtextfield([g_chatpos[0], g_chatpos[1]], [290, 280], 1 | 2, g_chatbuffer_final);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Chat_GetHexCodeForPlayer(player_id)
|
||||||
|
// Returns a hex string for the Player Name color
|
||||||
|
//
|
||||||
|
string Chat_GetHexCodeForPlayer(float player_id)
|
||||||
|
{
|
||||||
|
switch(player_id) {
|
||||||
|
case 1: return "^xFFF";
|
||||||
|
case 2: return "^x07E";
|
||||||
|
case 3: return "^xCA0";
|
||||||
|
case 4: return "^x5D0";
|
||||||
|
}
|
||||||
|
return "^xFFF";
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Chat_Register(sender, player_id, message)
|
||||||
|
// Adds the chat message to the chat struct to be
|
||||||
|
// drawn.
|
||||||
|
//
|
||||||
|
void Chat_Register(int sender, int player_id, string message)
|
||||||
|
{
|
||||||
|
// Append name+color to the message
|
||||||
|
string player_hex = Chat_GetHexCodeForPlayer(player_id);
|
||||||
|
string player_name = getplayerkeyvalue(sender, "name");
|
||||||
|
message = strcat(player_hex, player_name, "^xCCC: ", message);
|
||||||
|
|
||||||
|
if (g_chatlines < (CHAT_LINES - 1)) {
|
||||||
|
g_chatbuffer[g_chatlines + 1] = message;
|
||||||
|
g_chatlines++;
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < (CHAT_LINES - 1); i++) {
|
||||||
|
g_chatbuffer[i] = g_chatbuffer[i + 1];
|
||||||
|
}
|
||||||
|
g_chatbuffer[CHAT_LINES - 1] = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_chattime = time + CHAT_TIME;
|
||||||
|
|
||||||
|
/* we need to be silent */
|
||||||
|
if (autocvar_cg_chatEnabled == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
localsound("sounds/misc/talk2.wav");
|
||||||
|
|
||||||
|
g_chatbuffer_final = "";
|
||||||
|
|
||||||
|
for (int i = 0; i < CHAT_LINES; i++) {
|
||||||
|
if (i == 0)
|
||||||
|
g_chatbuffer_final = g_chatbuffer[i];
|
||||||
|
else
|
||||||
|
g_chatbuffer_final = sprintf("%s\n%s", g_chatbuffer_final, g_chatbuffer[i]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
main csqc code
|
main csqc code
|
||||||
|
|
||||||
Copyright (C) 2021 NZ:P Team
|
Copyright (C) 2021-2023 NZ:P Team
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
This program is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU General Public License
|
modify it under the terms of the GNU General Public License
|
||||||
|
@ -1086,6 +1086,7 @@ noref void(float width, float height, float menushown) CSQC_UpdateView =
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
HUD_Draw(g_width, g_height);
|
HUD_Draw(g_width, g_height);
|
||||||
|
Chat_Draw();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1367,6 +1368,12 @@ noref void() CSQC_Parse_Event =
|
||||||
pointparticles(particleeffectnum("blood.gibs"), gloc, '0 0 0', 1);
|
pointparticles(particleeffectnum("blood.gibs"), gloc, '0 0 0', 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case EVENT_CHATMESSAGE:
|
||||||
|
int sender = readbyte();
|
||||||
|
int player_id = readbyte();
|
||||||
|
string message = readstring();
|
||||||
|
Chat_Register(sender, player_id, message);
|
||||||
|
break;
|
||||||
case EVENT_WEAPONCHANGE:
|
case EVENT_WEAPONCHANGE:
|
||||||
local float to;
|
local float to;
|
||||||
to = readbyte();
|
to = readbyte();
|
||||||
|
|
|
@ -536,6 +536,15 @@ void (float achievement_id, optional entity who) GiveAchievement =
|
||||||
|
|
||||||
#ifdef FTE
|
#ifdef FTE
|
||||||
|
|
||||||
|
void CSQC_SendChatMessage(float player_id, string message) {
|
||||||
|
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
|
||||||
|
WriteByte(MSG_MULTICAST, EVENT_CHATMESSAGE);
|
||||||
|
WriteByte(MSG_MULTICAST, num_for_edict(self) - 1);
|
||||||
|
WriteByte(MSG_MULTICAST, player_id);
|
||||||
|
WriteString(MSG_MULTICAST, message);
|
||||||
|
multicast('0 0 0', MULTICAST_ALL);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
Player_SendEntity
|
Player_SendEntity
|
||||||
|
|
|
@ -180,6 +180,26 @@ float(string params) Command_tracedmgmultiplier =
|
||||||
return COMMAND_SUCCESS;
|
return COMMAND_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Command_say()
|
||||||
|
// Sends message via CSQC to other clients (FTE-only)
|
||||||
|
//
|
||||||
|
float(string params) Command_say =
|
||||||
|
{
|
||||||
|
// Grab parameters.
|
||||||
|
tokenize(params);
|
||||||
|
string value = argv(0);
|
||||||
|
|
||||||
|
#ifdef FTE
|
||||||
|
|
||||||
|
CSQC_SendChatMessage(self.playernum, params);
|
||||||
|
|
||||||
|
#endif // FTE
|
||||||
|
|
||||||
|
client_parse_override = false;
|
||||||
|
return COMMAND_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Server command table
|
// Server command table
|
||||||
// command_name : Command string entered into developer console.
|
// command_name : Command string entered into developer console.
|
||||||
|
@ -201,15 +221,31 @@ var struct {
|
||||||
{"god", Command_godmode, false, "Toggles God Mode.\n"},
|
{"god", Command_godmode, false, "Toggles God Mode.\n"},
|
||||||
{"noclip", Command_noclip, false, "Toggles No Clip.\n"},
|
{"noclip", Command_noclip, false, "Toggles No Clip.\n"},
|
||||||
{"sv_tracedmgmultiplier", Command_tracedmgmultiplier, true, "Multiplies damage output with weapons that fire Traces.\n"},
|
{"sv_tracedmgmultiplier", Command_tracedmgmultiplier, true, "Multiplies damage output with weapons that fire Traces.\n"},
|
||||||
{"spawn_pu", Command_powerup, true, "Spawns a Power-Up of a given ID in front of you. -1 for random.\n"}
|
{"spawn_pu", Command_powerup, true, "Usage: spawn_pu <powerup>\n Spawns a Power-Up of a given ID in front of you. -1 for random.\n"},
|
||||||
|
{"say", Command_say, true, "Usage: say <message>\n Sends a chat message to CSQC for other clients.\n"}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// SV_IsCommand(command_string)
|
||||||
|
// Takes a single string and references if it is a
|
||||||
|
// registered command, returns true if it is. Useful
|
||||||
|
// for cl_chatmode interferring with custom commands.
|
||||||
|
//
|
||||||
|
float(string command_string) SV_IsCommand =
|
||||||
|
{
|
||||||
|
for (float i = 0; i < server_commands.length; i++) {
|
||||||
|
if (command_string == server_commands[i].command_name)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// SV_ParseClientCommand(command_string)
|
// SV_ParseClientCommand(command_string)
|
||||||
// Server-Side client command parser to add special
|
// Server-Side client command parser to add special
|
||||||
// gameplay commands that interact with QuakeC.
|
// gameplay commands that interact with QuakeC.
|
||||||
//
|
//
|
||||||
|
|
||||||
void(string command_string) SV_ParseClientCommand =
|
void(string command_string) SV_ParseClientCommand =
|
||||||
{
|
{
|
||||||
// If true, we will avoid sending the command info
|
// If true, we will avoid sending the command info
|
||||||
|
@ -225,10 +261,10 @@ void(string command_string) SV_ParseClientCommand =
|
||||||
// Check for 'say' prefix (`cl_chatmode 2` will append it
|
// Check for 'say' prefix (`cl_chatmode 2` will append it
|
||||||
// to everything unregistered by the client). Re-tokenize
|
// to everything unregistered by the client). Re-tokenize
|
||||||
// if found.
|
// if found.
|
||||||
if (command == "say") {
|
if (command == "say" && SV_IsCommand(argv(1))) {
|
||||||
string fixed_command_string = argv(1);
|
string fixed_command_string = argv(1);
|
||||||
tokenize(fixed_command_string);
|
tokenize(fixed_command_string);
|
||||||
command = argv(0);
|
command = argv(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now iterate over our commands
|
// Now iterate over our commands
|
||||||
|
|
|
@ -58,6 +58,7 @@ const float EVENT_SONGPLAY = 41;
|
||||||
const float EVENT_GRENADEPULSE = 42;
|
const float EVENT_GRENADEPULSE = 42;
|
||||||
const float EVENT_BETTYPROMPT = 43;
|
const float EVENT_BETTYPROMPT = 43;
|
||||||
const float EVENT_LIMBGIB = 44;
|
const float EVENT_LIMBGIB = 44;
|
||||||
|
const float EVENT_CHATMESSAGE = 45;
|
||||||
|
|
||||||
// Define our FTE platform
|
// Define our FTE platform
|
||||||
#ifndef STANDARD
|
#ifndef STANDARD
|
||||||
|
|
Loading…
Reference in a new issue