Index | FAQ | Search | Memberlist | Usergroups | Profile | Log in to check your private messages | Log in | Register

CSQC Chat Messages

| Inside3d Forums Forum Index -> QuakeC Programming

View previous topic :: View next topic
Author | Message
--- | ---
GiffE Joined: 08 Oct 2006 Posts: 141 Location: USA, CT |

Posted: Fri Oct 10, 2008 3:23 pm Post subject: CSQC Chat Messages |

Something I did a few days ago: This is not the most effective way of doing things but it sure is easy. Also NOTE: I did not put any "flood control" on this yet, so it is not exactly secure. It makes csqc and ssqc handle the chat messages, csqc draws it in the bottom left hand corner. It also fades after 10 seconds of no new messages.
This is a more cosmetic addition but it helps separate chat from death and server messages.
A similar approach can be done for the actual typing of say messages. This would require you to check for "say" in csqc then accept all keyboard strokes and draw a string.
I have tested this in Darkplaces only, I may have missed something when writing this although.
Here's the result:
First the server:
credit: Parts of this were taken from Nexiuz.
in client.qc

Code:
#define FOR_EACH_CLIENT(v) for(v = world; (v = findflags(v, flags, FL_CLIENT)) != world; ) #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL) void Say(entity source, string msgin) { local string msgstr;
local entity head;
msgstr = strzone(strcat("(say_msg)\{1}", source.netname, "^7: ", msgin, "\n"));
FOR_EACH_REALCLIENT(head) if(head.classname == "player")
{
//sprint(head, msgstr);
centerprint(head, msgstr);
}
strunzone(msgstr);
}
void(string s) SV_ParseClientCommand
{
// Acquire Command
local string strCmd;
tokenize(s);
strCmd = argv(0);
switch(strCmd)
{
case "say":
Say(self, substring(s, 4, strlen(s) - 1));
break;
default:
clientcommand(self,s);
break;
}
}

It takes the message, tacks on "(say_msg)" and your name to the beginning, then centerprints it to the client.
Thats it for the server. Once again it lacks flood protection.
The rest of this is in CSQC:
At the top of Main.qc add:

Code:
float MAX_CHATMSG = 6; string messagestack[MAX_CHATMSG]; float messagestack_fade; float msg_alpha; void push_message(string msg)
{
local float i;
i=MAX_CHATMSG-1;
while (i>0)
{
messagestack[i]=messagestack[i-1];
i--;
}
messagestack[i]=msg;
msg_alpha = 1;
messagestack_fade = time + 10;
}

All the messages will be stored in the messagestack array. So on a new message we can push out the old message to make room for the new.
in function: CSQC_Parse_CenterPrint(string strMessage) found in Main.qc:

Code:
// CSQC_Parse_CenterPrint : Provides the centerprint string in the first parameter that the server provided. To execute standard behavior, simply execute cprint with the string. void CSQC_Parse_CenterPrint(string strMessage) { string msg,saymsg;
saymsg = substring(strMessage,0,9);
if(saymsg == "(say_msg)")
{
msg = substring(strMessage,9,strlen(strMessage));
push_message(strzone(msg));
}
else
cprint(strMessage);
}

The idea is server accepts the say command and puts "(say_msg)" in front of it. It then centerprints it to all the clients.
CSQC has the ability to parse centerprints so we can check if its a "say"
Now open up View.qc and at the top add the following function:

Code:
void DrawChat(void) { local vector pos; local float i; pos_x = 20;
pos_y = vid_conheight - 30;
if(messagestack_fade < time && msg_alpha >0)
msg_alpha -= 0.02;
for(i=0;i<MAX_CHATMSG;i++)
{
if(messagestack[i] != "")
drawcolorcodedstring(pos - ('0 10 0' * i), messagestack[i], '7 7', msg_alpha, FALSE);
}
}

Find the function void CSQC_UpdateView(void). After:

Code:
R_RenderScene();

add:

Code:
DrawChat();

And you are done
If your having trouble getting the parse centerprint function to work this is because the csqc base code by default has it commented out.
make sure you:
#define USE_CSQC_OPTIONALFUNCTIONS
Also this method lacks the talk sound, this can be easily solved by adding a pointsound of "sound/misc/talk.wav"
Its more of a method than anything else, and still needs work (say_team and flood). But, Hope it helps anyone
_________________
http://www.giffe-bin.net/

Back to top |

Spike Joined: 05 Nov 2004 Posts: 944 Location: UK |

Posted: Fri Oct 10, 2008 10:14 pm Post subject: |

Does it still work if they're chatting in the console, and not using message mode stuff? Other than that, cool! Don't forget to add support for smilies! :D _________________ What's a signature?

Back to top |

Wazat Joined: 15 Oct 2004 Posts: 732 Location: Middle 'o the desert, USA |

Posted: Fri Oct 10, 2008 11:44 pm Post subject: |

This is cool. It adds shiny new pvp talk that stands out from all the other chatter and server messages. _________________ When my computer inevitably explodes and kills me, my cat inherits everything I own. He may be the only one capable of continuing my work.

Back to top |

GiffE Joined: 08 Oct 2006 Posts: 141 Location: USA, CT |

Posted: Sat Oct 11, 2008 12:06 am Post subject: |

Spike wrote:
Does it still work if they're chatting in the console, and not using message mode stuff? Other than that, cool! Don't forget to add support for smilies!

Never tested but I don't see why it wouldn't work. It uses the say command.
_________________
http://www.giffe-bin.net/

Back to top |

GiffE Joined: 08 Oct 2006 Posts: 141 Location: USA, CT |

Posted: Thu Jun 17, 2010 3:38 am Post subject: |

Here's an update to this code if anyone still wants to use it I ported over the flood protect control from Nexuiz. I also added a rudimentary word wrap. NOTE: I changed the cvars to hard coded values. Obviously you can uncomment these and make them work via cvar.
Replace the Say method with:

Code:
#define WORDWRAP_MAX 50 .float floodcontrol_chat; void Say(entity source, string msgin) { local string msgstr;
local entity head;
local float flood;
if(msgin == "" || msgin == " ")
return;
msgstr = strzone(strcat("(say_msg)", source.netname, "^7: ", msgin));
// FLOOD CONTROL
flood = 0;
{
float flood_spl, flood_burst, flood_lmax,lines;
flood_spl = 3;//cvar("g_chat_flood_spl");
flood_burst = 2;//max(0,cvar("g_chat_flood_burst") - 1);
flood_lmax = 2; //cvar("g_chat_flood_lmax");
// to match explanation in default.cfg, a value of 3 must allow three-line bursts and not four!
lines = ceil(strlennocol(msgstr) / WORDWRAP_MAX);
if(lines > flood_lmax )
flood = 2;
else if(time >= self.floodcontrol_chat)
self.floodcontrol_chat = max(time - flood_burst * flood_spl, self.floodcontrol_chat) + lines * flood_spl;
else
flood = 1;
}
if(flood)
{
if(flood == 1)
sprint(self, strcat("^3FLOOD CONTROL: ^7wait ^1", ftos(self.floodcontrol_chat - time), "^3 seconds\n"));
else if(flood == 2)
sprint(self, "^3FLOOD CONTROL: ^7message too long\n");
}
else {
FOR_EACH_REALCLIENT(head) if(head.classname == "player" || head.classname == "spectator")
{
centerprint(head, msgstr);
}
}
strunzone(msgstr);
}

Then replace CSQC_Parse_CenterPrint with:

Code:
#define WORDWRAP_MAX 50 void CSQC_Parse_CenterPrint(string strMessage) { string msg; float f,i;
f = strstrofs(strMessage,"(say_msg)",0);
if(f != -1) //right at the begining
{
msg = substring(strMessage,f+9,strlen(strMessage));
f = ceil(strlennocol(msg) / WORDWRAP_MAX);
for(i=0;i<f;i++) {
if(strlennocol(msg) > WORDWRAP_MAX)
push_message(strzone(substring(msg,i*WORDWRAP_MAX,WORDWRAP_MAX)));
else
push_message(strzone(substring(msg,i*WORDWRAP_MAX,-1)));
}
}
else
cprint(strMessage);
}

_________________
http://www.giffe-bin.net/

Back to top |

GiffE Joined: 08 Oct 2006 Posts: 141 Location: USA, CT |

Posted: Sat Jun 19, 2010 3:11 pm Post subject: |

To have csqc handle the message mode, a good amount of work has to be done to get the keypresses to translate into their character, as holding shift does not change the key value you have to do it manually.

Code:
float shiftheld; float capslock; string toUpper(float chr) { string ltr; if(chr > 96 && chr < 122)
ltr = strtoupper(chr2str(chr));
else if(chr > 43 && chr <= 57)
ltr = substring("<_>?)!@#$%^&*(",chr - 44,1);
else {
switch(chr) {
case 61: ltr = "+"; break;
case 92: ltr = "|"; break;
case 96: ltr = "~"; break;
case 91: ltr = "{"; break;
case 93: ltr = "}"; break;
case 59: ltr = ":"; break;
case 39: ltr = "\""; break;
case 32: ltr = " "; break;
}
}
return ltr;
}
string lowerChr(float chr) {
if(chr > 126 && chr < 134)
return string_null;
if(chr > 146 && chr < 154)
return string_null;
switch(chr) {
case 9:
return string_null;
}
return chr2str(chr);
}
// CSQC_InputEvent : Used to perform actions based on any key pressed or released by the client.
// Return value should be 1 if CSQC handled the key press, otherwise return 0 to have the key passed to the engine.
float CSQC_InputEvent(float bKeyReleased, float nKey)
{
local float bSkipKey;
bSkipKey = false;
if(messagemode) {
bSkipKey = true;
if(nKey == 27 || nKey == 13) { // ESC
messagemode = false;
if(nKey == 13) {
localcmd("cmd say ",msg_txt,"\n");
msg_txt = string_null;
}
return bSkipKey;
}
if(nKey == 127 && !bKeyReleased) {
msg_txt = strzone(substring(msg_txt,0,-2));
}
if(nKey == 134) // Shift
shiftheld = (!bKeyReleased);
if(nKey == 0 && (!bKeyReleased))
capslock = (capslock) ? 0 : 1;
if(!bKeyReleased) {
string chr;
chr = (shiftheld || (capslock && nKey > 96 && nKey < 122)) ? toUpper(nKey) : lowerChr(nKey);
chr = strcat(msg_txt,chr);
if(msg_txt)
strunzone(msg_txt);
msg_txt = strzone(chr);
}
}
return bSkipKey;
}

Then for the drawing:

Code:
void DrawMessageMode(void) { local vector pos; pos = Vec2f(15,vid_size_y*0.5); drawfill(pos, Vec2f(vid_size_x - 30,15), COLOR_BLACK, 0.7, 0);
pos_y = pos_y + 3.5;
drawfont = FONT_INFOBAR;
drawstring(pos + '3.5 0', "Say:", '8 8', COLOR_WHITE, 1, 0);
pos_x = pos_x + 35.5;
drawcolorcodedstring(pos, msg_txt, '8 8', 1, FALSE);
drawfont = FONT_DEFAULT;
};

This code needs support for scrolling or a hard limit, as if his sentence gets longer it will just keep on going off the screen and not scroll with it. This should be handled in the draw function
Also, this code doesn't have support for a cursor so you can only backspace from the end and cannot go back otherwise.
Also, I noticed my old code for chat messages doesn't ever unzone the strings.
add:

Code:
if(messagestack[MAX_CHATMSG-1]) strunzone(messagestack[MAX_CHATMSG-1]);

to void push_message(string msg)
right above

Code:
messagestack[i]=msg; msg_alpha = 1;

_________________
http://www.giffe-bin.net/

Back to top |

Display posts from previous:

| Inside3d Forums Forum Index -> QuakeC Programming | All times are GMT
Page 1 of 1

Jump to:

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

Powered by phpBB © 2004 phpBB Group