mirror of
https://github.com/nzp-team/fteqw.git
synced 2025-02-16 17:01:44 +00:00
Better compat with QE. EX_PROMPT now supported serverside (emulated for non-qe clients). Per-client localisation now works. Scoreboards are now a little nicer when running mods with well-defined teams (eg NQ ssqc).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@6309 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
3a6f22d05c
commit
df6b651eeb
15 changed files with 714 additions and 155 deletions
|
@ -4166,12 +4166,14 @@ void CL_LinkPacketEntities (void)
|
||||||
if (state->effects & EF_BRIGHTLIGHT)
|
if (state->effects & EF_BRIGHTLIGHT)
|
||||||
{
|
{
|
||||||
radius = max(radius,r_brightlight_colour.vec4[3]);
|
radius = max(radius,r_brightlight_colour.vec4[3]);
|
||||||
VectorAdd(colour, r_brightlight_colour.vec4, colour);
|
if (!(state->effects & (EF_RED|EF_GREEN|EF_BLUE)))
|
||||||
|
VectorAdd(colour, r_brightlight_colour.vec4, colour);
|
||||||
}
|
}
|
||||||
if (state->effects & EF_DIMLIGHT)
|
if (state->effects & EF_DIMLIGHT)
|
||||||
{
|
{
|
||||||
radius = max(radius,r_dimlight_colour.vec4[3]);
|
radius = max(radius,r_dimlight_colour.vec4[3]);
|
||||||
VectorAdd(colour, r_dimlight_colour.vec4, colour);
|
if (!(state->effects & (EF_RED|EF_GREEN|EF_BLUE)))
|
||||||
|
VectorAdd(colour, r_dimlight_colour.vec4, colour);
|
||||||
}
|
}
|
||||||
if (state->effects & EF_BLUE)
|
if (state->effects & EF_BLUE)
|
||||||
{
|
{
|
||||||
|
@ -5398,12 +5400,14 @@ void CL_LinkPlayers (void)
|
||||||
if (state->effects & EF_BRIGHTLIGHT)
|
if (state->effects & EF_BRIGHTLIGHT)
|
||||||
{
|
{
|
||||||
radius = max(radius,r_brightlight_colour.vec4[3]);
|
radius = max(radius,r_brightlight_colour.vec4[3]);
|
||||||
VectorAdd(colour, r_brightlight_colour.vec4, colour);
|
if (!(state->effects & (EF_RED|EF_GREEN|EF_BLUE)))
|
||||||
|
VectorAdd(colour, r_brightlight_colour.vec4, colour);
|
||||||
}
|
}
|
||||||
if (state->effects & EF_DIMLIGHT)
|
if (state->effects & EF_DIMLIGHT)
|
||||||
{
|
{
|
||||||
radius = max(radius,r_dimlight_colour.vec4[3]);
|
radius = max(radius,r_dimlight_colour.vec4[3]);
|
||||||
VectorAdd(colour, r_dimlight_colour.vec4, colour);
|
if (!(state->effects & (EF_RED|EF_GREEN|EF_BLUE)))
|
||||||
|
VectorAdd(colour, r_dimlight_colour.vec4, colour);
|
||||||
}
|
}
|
||||||
if (state->effects & EF_BLUE)
|
if (state->effects & EF_BLUE)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1837,7 +1837,7 @@ void CLNQ_SendMove (usercmd_t *cmd, int pnum, sizebuf_t *buf)
|
||||||
MSG_WriteFloat (buf, cmd->fservertime); // use latest time. because ping reports!
|
MSG_WriteFloat (buf, cmd->fservertime); // use latest time. because ping reports!
|
||||||
|
|
||||||
if (cls.qex)
|
if (cls.qex)
|
||||||
MSG_WriteByte(buf, 4);
|
MSG_WriteByte(buf, 1);
|
||||||
|
|
||||||
for (i=0 ; i<3 ; i++)
|
for (i=0 ; i<3 ; i++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4048,8 +4048,8 @@ void CLNQ_ConnectionlessPacket(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length == 5 && net_from.prot == NP_DTLS)
|
if (length == 5)
|
||||||
{
|
{ //QE strips the port entirely.
|
||||||
cls.proquake_angles_hack = false;
|
cls.proquake_angles_hack = false;
|
||||||
cls.protocol_nq = CPNQ_ID;
|
cls.protocol_nq = CPNQ_ID;
|
||||||
Con_DPrintf("QuakeEx server...\n");
|
Con_DPrintf("QuakeEx server...\n");
|
||||||
|
|
|
@ -4136,11 +4136,11 @@ static void CLQEX_ParsePrompt(void)
|
||||||
SCR_CenterPrint(0, NULL, true);
|
SCR_CenterPrint(0, NULL, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
*message = 0;
|
||||||
s = MSG_ReadString();
|
s = MSG_ReadString();
|
||||||
Q_strncatz(message+ofs, "/S/C/.", sizeof(message)-ofs);
|
Q_strncatz(message+ofs, "/S/C/.", sizeof(message)-ofs);
|
||||||
ofs += strlen(message+ofs);
|
ofs += strlen(message+ofs);
|
||||||
TL_Reformat(message+ofs, sizeof(message)-ofs, 1, &s);
|
TL_Reformat(com_language, message+ofs, sizeof(message)-ofs, 1, &s);
|
||||||
ofs += strlen(message+ofs);
|
ofs += strlen(message+ofs);
|
||||||
|
|
||||||
Q_strncatz(message+ofs, "\n", sizeof(message)-ofs);
|
Q_strncatz(message+ofs, "\n", sizeof(message)-ofs);
|
||||||
|
@ -4151,7 +4151,7 @@ static void CLQEX_ParsePrompt(void)
|
||||||
imp = MSG_ReadByte();
|
imp = MSG_ReadByte();
|
||||||
Q_strncatz(message+ofs, "^[[", sizeof(message)-ofs);
|
Q_strncatz(message+ofs, "^[[", sizeof(message)-ofs);
|
||||||
ofs += strlen(message+ofs);
|
ofs += strlen(message+ofs);
|
||||||
TL_Reformat(message+ofs, sizeof(message)-ofs, 1, &s);
|
TL_Reformat(com_language, message+ofs, sizeof(message)-ofs, 1, &s);
|
||||||
ofs += strlen(message+ofs);
|
ofs += strlen(message+ofs);
|
||||||
Q_strncatz(message+ofs, va("]\\impulse\\%i^]\n", imp), sizeof(message)-ofs);
|
Q_strncatz(message+ofs, va("]\\impulse\\%i^]\n", imp), sizeof(message)-ofs);
|
||||||
ofs += strlen(message+ofs);
|
ofs += strlen(message+ofs);
|
||||||
|
@ -4175,7 +4175,7 @@ static char *CLQEX_ReadStrings(void)
|
||||||
for (; a < count; a++)
|
for (; a < count; a++)
|
||||||
MSG_ReadString(); //don't lose space, though we can't buffer it.
|
MSG_ReadString(); //don't lose space, though we can't buffer it.
|
||||||
|
|
||||||
TL_Reformat(formatted, sizeof(formatted), a, arg);
|
TL_Reformat(com_language, formatted, sizeof(formatted), a, arg);
|
||||||
return formatted;
|
return formatted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7606,7 +7606,7 @@ void CLQW_ParseServerMessage (void)
|
||||||
cl.completed_time = cl.gametime;
|
cl.completed_time = cl.gametime;
|
||||||
}
|
}
|
||||||
cl.intermissionmode = IM_NQFINALE;
|
cl.intermissionmode = IM_NQFINALE;
|
||||||
SCR_CenterPrint (destsplit, TL_Translate(MSG_ReadString ()), false);
|
SCR_CenterPrint (destsplit, TL_Translate(com_language, MSG_ReadString ()), false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case svc_sellscreen:
|
case svc_sellscreen:
|
||||||
|
@ -8784,8 +8784,8 @@ void CLNQ_ParseServerMessage (void)
|
||||||
//FIXME: figure out the player index so we can kickban/mute/etc them.
|
//FIXME: figure out the player index so we can kickban/mute/etc them.
|
||||||
qbyte plcolour = MSG_ReadByte();
|
qbyte plcolour = MSG_ReadByte();
|
||||||
qbyte chatcolour = MSG_ReadByte();
|
qbyte chatcolour = MSG_ReadByte();
|
||||||
char *pcols[] = {S_COLOR_WHITE,S_COLOR_RED,S_COLOR_YELLOW, S_COLOR_CYAN};
|
char *pcols[] = {S_COLOR_WHITE,S_COLOR_GREEN,S_COLOR_CYAN, S_COLOR_YELLOW};
|
||||||
char *ccols[] = {S_COLOR_WHITE,S_COLOR_CYAN};
|
char *ccols[] = {S_COLOR_WHITE,S_COLOR_CYAN}; //say, say_team
|
||||||
Con_Printf("^[%s%s"/*"\\player\\%i"*/"^]: ", pcols[plcolour%countof(pcols)], MSG_ReadString());
|
Con_Printf("^[%s%s"/*"\\player\\%i"*/"^]: ", pcols[plcolour%countof(pcols)], MSG_ReadString());
|
||||||
Con_Printf("%s%s\n", ccols[chatcolour%countof(ccols)], MSG_ReadString());
|
Con_Printf("%s%s\n", ccols[chatcolour%countof(ccols)], MSG_ReadString());
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -327,6 +327,8 @@ typedef struct {
|
||||||
float time_off;
|
float time_off;
|
||||||
int erase_lines;
|
int erase_lines;
|
||||||
int erase_center;
|
int erase_center;
|
||||||
|
|
||||||
|
int oldmousex, oldmousey; //so the cursorchar can be changed by keyboard without constantly getting stomped on.
|
||||||
} cprint_t;
|
} cprint_t;
|
||||||
|
|
||||||
cprint_t scr_centerprint[MAX_SPLITS];
|
cprint_t scr_centerprint[MAX_SPLITS];
|
||||||
|
@ -682,7 +684,7 @@ int SCR_DrawCenterString (vrect_t *playerrect, cprint_t *p, struct font_s *font)
|
||||||
int remaining;
|
int remaining;
|
||||||
shader_t *pic;
|
shader_t *pic;
|
||||||
int ch;
|
int ch;
|
||||||
int mousex,mousey;
|
int mousex,mousey, mousemoved;
|
||||||
|
|
||||||
conchar_t *line_start[MAX_CPRINT_LINES];
|
conchar_t *line_start[MAX_CPRINT_LINES];
|
||||||
conchar_t *line_end[MAX_CPRINT_LINES];
|
conchar_t *line_end[MAX_CPRINT_LINES];
|
||||||
|
@ -741,6 +743,10 @@ int SCR_DrawCenterString (vrect_t *playerrect, cprint_t *p, struct font_s *font)
|
||||||
Font_BeginString(font, rect.x+rect.width, rect.y+rect.height, &right, &bottom);
|
Font_BeginString(font, rect.x+rect.width, rect.y+rect.height, &right, &bottom);
|
||||||
linecount = Font_LineBreaks(p->string, p->string + p->charcount, (p->flags & CPRINT_NOWRAP)?0x7fffffff:(right - left), MAX_CPRINT_LINES, line_start, line_end);
|
linecount = Font_LineBreaks(p->string, p->string + p->charcount, (p->flags & CPRINT_NOWRAP)?0x7fffffff:(right - left), MAX_CPRINT_LINES, line_start, line_end);
|
||||||
|
|
||||||
|
mousemoved = mousex != p->oldmousex || mousey != p->oldmousey;
|
||||||
|
p->oldmousex = mousex;
|
||||||
|
p->oldmousey = mousey;
|
||||||
|
|
||||||
ch = Font_CharHeight();
|
ch = Font_CharHeight();
|
||||||
|
|
||||||
if (p->flags & CPRINT_TALIGN)
|
if (p->flags & CPRINT_TALIGN)
|
||||||
|
@ -791,9 +797,27 @@ int SCR_DrawCenterString (vrect_t *playerrect, cprint_t *p, struct font_s *font)
|
||||||
else
|
else
|
||||||
x = left + (right - left - Font_LineWidth(line_start[l], line_end[l]))/2;
|
x = left + (right - left - Font_LineWidth(line_start[l], line_end[l]))/2;
|
||||||
|
|
||||||
if (mousey >= y && mousey < y+ch)
|
if (mousemoved && mousey >= y && mousey < y+ch)
|
||||||
{
|
{
|
||||||
p->cursorchar = Font_CharAt(mousex - x, line_start[l], line_end[l]);
|
conchar_t *linkstart;
|
||||||
|
linkstart = Font_CharAt(mousex - x, line_start[l], line_end[l]);
|
||||||
|
|
||||||
|
//scan backwards to find any link enclosure
|
||||||
|
if (linkstart)
|
||||||
|
for(linkstart = linkstart-1; linkstart >= line_start[l]; linkstart--)
|
||||||
|
{
|
||||||
|
if (*linkstart == CON_LINKSTART)
|
||||||
|
{
|
||||||
|
//found one
|
||||||
|
p->cursorchar = linkstart;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*linkstart == CON_LINKEND)
|
||||||
|
{
|
||||||
|
//some other link ended here. don't use its start.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
remaining -= line_end[l]-line_start[l];
|
remaining -= line_end[l]-line_start[l];
|
||||||
|
@ -803,6 +827,25 @@ int SCR_DrawCenterString (vrect_t *playerrect, cprint_t *p, struct font_s *font)
|
||||||
if (line_end[l] <= line_start[l])
|
if (line_end[l] <= line_start[l])
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p->cursorchar && p->cursorchar >= line_start[l] && p->cursorchar < line_end[l] && *p->cursorchar == CON_LINKSTART)
|
||||||
|
{
|
||||||
|
conchar_t *linkend;
|
||||||
|
int s, e;
|
||||||
|
for (linkend = p->cursorchar; linkend < line_end[l]; linkend++)
|
||||||
|
if (*linkend == CON_LINKEND)
|
||||||
|
break;
|
||||||
|
|
||||||
|
s = x+Font_LineWidth(line_start[l], p->cursorchar);
|
||||||
|
e = x+Font_LineWidth(line_start[l], linkend);
|
||||||
|
|
||||||
|
//draw a 2-pixel underscore (behind the text).
|
||||||
|
R2D_ImageColours(SRGBA(0.3,0.3,0.3, 1)); //mouseover.
|
||||||
|
R2D_FillBlock((s*vid.width)/(float)vid.rotpixelwidth, ((y+Font_CharHeight()-2)*vid.height)/(float)vid.rotpixelheight, ((e - s)*vid.width)/(float)vid.rotpixelwidth, (2*vid.height)/(float)vid.rotpixelheight);
|
||||||
|
R2D_Flush();
|
||||||
|
R2D_ImageColours(SRGBA(1, 1, 1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
Font_LineDraw(x, y, line_start[l], line_end[l]);
|
Font_LineDraw(x, y, line_start[l], line_end[l]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -811,11 +854,59 @@ int SCR_DrawCenterString (vrect_t *playerrect, cprint_t *p, struct font_s *font)
|
||||||
return linecount;
|
return linecount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void Key_CenterPrintActivate(int pnum)
|
||||||
|
{
|
||||||
|
char *link;
|
||||||
|
cprint_t *p = &scr_centerprint[pnum];
|
||||||
|
link = SCR_CopyCenterPrint(p);
|
||||||
|
if (link)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (link[0] == '^' && link[1] == '[')
|
||||||
|
{
|
||||||
|
//looks like it might be a link!
|
||||||
|
char *end = NULL;
|
||||||
|
char *info;
|
||||||
|
for (info = link + 2; *info; )
|
||||||
|
{
|
||||||
|
if (info[0] == '^' && info[1] == ']')
|
||||||
|
break; //end of tag, with no actual info, apparently
|
||||||
|
if (*info == '\\')
|
||||||
|
break;
|
||||||
|
else if (info[0] == '^' && info[1] == '^')
|
||||||
|
info+=2;
|
||||||
|
else
|
||||||
|
info++;
|
||||||
|
}
|
||||||
|
for(end = info; *end; )
|
||||||
|
{
|
||||||
|
if (end[0] == '^' && end[1] == ']')
|
||||||
|
{
|
||||||
|
//okay, its a valid link that they clicked
|
||||||
|
*end = 0;
|
||||||
|
|
||||||
|
#ifdef PLUGINS
|
||||||
|
if (!Plug_ConsoleLink(link+2, info, ""))
|
||||||
|
#endif
|
||||||
|
#ifdef CSQC_DAT
|
||||||
|
if (!CSQC_ConsoleLink(link+2, info))
|
||||||
|
#endif
|
||||||
|
Key_DefaultLinkClicked(NULL, link+2, info);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (end[0] == '^' && end[1] == '^')
|
||||||
|
end+=2;
|
||||||
|
else
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
qboolean Key_Centerprint(int key, int unicode, unsigned int devid)
|
qboolean Key_Centerprint(int key, int unicode, unsigned int devid)
|
||||||
{
|
{
|
||||||
int pnum;
|
int pnum;
|
||||||
cprint_t *p;
|
cprint_t *p;
|
||||||
char *link;
|
|
||||||
|
|
||||||
if (key == K_MOUSE1)
|
if (key == K_MOUSE1)
|
||||||
{
|
{
|
||||||
|
@ -824,52 +915,7 @@ qboolean Key_Centerprint(int key, int unicode, unsigned int devid)
|
||||||
{
|
{
|
||||||
p = &scr_centerprint[pnum];
|
p = &scr_centerprint[pnum];
|
||||||
if (cl.playerview[pnum].gamerectknown == cls.framecount)
|
if (cl.playerview[pnum].gamerectknown == cls.framecount)
|
||||||
{
|
Key_CenterPrintActivate(pnum);
|
||||||
link = SCR_CopyCenterPrint(p);
|
|
||||||
if (link)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (link[0] == '^' && link[1] == '[')
|
|
||||||
{
|
|
||||||
//looks like it might be a link!
|
|
||||||
char *end = NULL;
|
|
||||||
char *info;
|
|
||||||
for (info = link + 2; *info; )
|
|
||||||
{
|
|
||||||
if (info[0] == '^' && info[1] == ']')
|
|
||||||
break; //end of tag, with no actual info, apparently
|
|
||||||
if (*info == '\\')
|
|
||||||
break;
|
|
||||||
else if (info[0] == '^' && info[1] == '^')
|
|
||||||
info+=2;
|
|
||||||
else
|
|
||||||
info++;
|
|
||||||
}
|
|
||||||
for(end = info; *end; )
|
|
||||||
{
|
|
||||||
if (end[0] == '^' && end[1] == ']')
|
|
||||||
{
|
|
||||||
//okay, its a valid link that they clicked
|
|
||||||
*end = 0;
|
|
||||||
|
|
||||||
#ifdef PLUGINS
|
|
||||||
if (!Plug_ConsoleLink(link+2, info, ""))
|
|
||||||
#endif
|
|
||||||
#ifdef CSQC_DAT
|
|
||||||
if (!CSQC_ConsoleLink(link+2, info))
|
|
||||||
#endif
|
|
||||||
Key_DefaultLinkClicked(NULL, link+2, info);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (end[0] == '^' && end[1] == '^')
|
|
||||||
end+=2;
|
|
||||||
else
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true; //handled
|
return true; //handled
|
||||||
}
|
}
|
||||||
|
@ -882,6 +928,52 @@ qboolean Key_Centerprint(int key, int unicode, unsigned int devid)
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else if ((key == K_ENTER ||
|
||||||
|
key == K_KP_ENTER ||
|
||||||
|
key == K_GP_DIAMOND_RIGHT) && devid < countof(scr_centerprint))
|
||||||
|
{
|
||||||
|
p = &scr_centerprint[devid];
|
||||||
|
if (p->cursorchar)
|
||||||
|
Key_CenterPrintActivate(devid);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if ((key == K_UPARROW ||
|
||||||
|
key == K_LEFTARROW ||
|
||||||
|
key == K_KP_UPARROW ||
|
||||||
|
key == K_KP_LEFTARROW ||
|
||||||
|
key == K_GP_DPAD_UP ||
|
||||||
|
key == K_GP_DPAD_LEFT) && devid < countof(scr_centerprint))
|
||||||
|
{
|
||||||
|
p = &scr_centerprint[devid];
|
||||||
|
if (!p->cursorchar)
|
||||||
|
p->cursorchar = p->string + p->charcount;
|
||||||
|
while (--p->cursorchar >= p->string)
|
||||||
|
{
|
||||||
|
if (*p->cursorchar == CON_LINKSTART)
|
||||||
|
return true; //found one
|
||||||
|
}
|
||||||
|
p->cursorchar = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if ((key == K_DOWNARROW ||
|
||||||
|
key == K_RIGHTARROW ||
|
||||||
|
key == K_KP_DOWNARROW ||
|
||||||
|
key == K_KP_RIGHTARROW ||
|
||||||
|
key == K_GP_DPAD_DOWN ||
|
||||||
|
key == K_GP_DPAD_RIGHT) && devid < countof(scr_centerprint))
|
||||||
|
{
|
||||||
|
p = &scr_centerprint[devid];
|
||||||
|
if (!p->cursorchar)
|
||||||
|
p->cursorchar = p->string-1;
|
||||||
|
while (++p->cursorchar < p->string + p->charcount)
|
||||||
|
{
|
||||||
|
if (*p->cursorchar == CON_LINKSTART)
|
||||||
|
return true; //found one
|
||||||
|
}
|
||||||
|
p->cursorchar = NULL; //hit the end
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -895,7 +987,6 @@ void SCR_CheckDrawCenterString (void)
|
||||||
for (pnum = 0; pnum < cl.splitclients; pnum++)
|
for (pnum = 0; pnum < cl.splitclients; pnum++)
|
||||||
{
|
{
|
||||||
p = &scr_centerprint[pnum];
|
p = &scr_centerprint[pnum];
|
||||||
p->cursorchar = NULL;
|
|
||||||
|
|
||||||
#ifdef QUAKESTATS
|
#ifdef QUAKESTATS
|
||||||
if (IN_DrawWeaponWheel(pnum))
|
if (IN_DrawWeaponWheel(pnum))
|
||||||
|
|
|
@ -126,6 +126,9 @@ static qboolean sbarfailed;
|
||||||
#ifdef HEXEN2
|
#ifdef HEXEN2
|
||||||
static qboolean sbar_hexen2;
|
static qboolean sbar_hexen2;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef NQPROT
|
||||||
|
static void Sbar_CTFScores_f(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
vrect_t sbar_rect; //screen area that the sbar must fit.
|
vrect_t sbar_rect; //screen area that the sbar must fit.
|
||||||
float sbar_rect_left;
|
float sbar_rect_left;
|
||||||
|
@ -803,15 +806,6 @@ void Sbar_ShowScores (void)
|
||||||
sb_updates = 0;
|
sb_updates = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NQPROT
|
|
||||||
static void Sbar_CTFScores_f(void)
|
|
||||||
{ //issued via stuffcmds.
|
|
||||||
// int red = atoi(Cmd_Argv(1));
|
|
||||||
// int blue = atoi(Cmd_Argv(2));
|
|
||||||
// int flags = atoi(Cmd_Argv(3)); //base|carried|dropped | base|carried|dropped
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HEXEN2
|
#ifdef HEXEN2
|
||||||
static void Sbar_Hexen2InvLeft_f(void)
|
static void Sbar_Hexen2InvLeft_f(void)
|
||||||
{
|
{
|
||||||
|
@ -1455,9 +1449,69 @@ static void Sbar_Hexen2DrawNum (float x, float y, int num, int digits)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef NQPROT
|
||||||
|
//this stuff was added to the rerelease's ctf mod.
|
||||||
|
int cl_ctfredscore;
|
||||||
|
int cl_ctfbluescore;
|
||||||
|
int cl_ctfflags;
|
||||||
|
static void Sbar_CTFScores_f(void)
|
||||||
|
{ //issued via stuffcmds.
|
||||||
|
cl_ctfredscore = atoi(Cmd_Argv(1));
|
||||||
|
cl_ctfbluescore = atoi(Cmd_Argv(2));
|
||||||
|
cl_ctfflags = atoi(Cmd_Argv(3)) | 0x100; //base|carried|dropped | base|carried|dropped
|
||||||
|
}
|
||||||
|
static void Sbar_DrawCTFScores(playerview_t *pv)
|
||||||
|
{
|
||||||
|
if (cl_ctfflags)
|
||||||
|
{
|
||||||
|
int i, x, y, sy;
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
int colour;
|
||||||
|
int *score;
|
||||||
|
const char *base, *held, *dropped; //at base, held, dropped.
|
||||||
|
int shift;
|
||||||
|
} team[] =
|
||||||
|
{
|
||||||
|
{4, &cl_ctfredscore, "gfx/redf1.lmp", "gfx/redf2.lmp", "gfx/redf3.lmp", 0},
|
||||||
|
{13, &cl_ctfbluescore, "gfx/bluef1.lmp", "gfx/bluef2.lmp", "gfx/bluef3.lmp", 3},
|
||||||
|
};
|
||||||
|
|
||||||
|
x = sbar_rect.x + sbar_rect.width - (48+2);
|
||||||
|
sy = sbar_rect.y + sbar_rect.height-sb_lines;
|
||||||
|
|
||||||
|
if (!cl_sbar.value && sb_lines > 24 && scr_viewsize.value>=100 && !cl_hudswap.value)
|
||||||
|
x -= 42; //QW hud nudges it in by 24 to not cover ammo.
|
||||||
|
|
||||||
|
for (i = 0, y=sy-17; i < countof(team); i++, y -= 18)
|
||||||
|
{
|
||||||
|
if (cl.players[pv->playernum].rbottomcolor == team[i].colour)
|
||||||
|
Sbar_FillPC (x-1, y-1, 48+2, 16+2, 12);
|
||||||
|
Sbar_FillPC (x+16, y, 32, 16, team[i].colour);
|
||||||
|
}
|
||||||
|
R2D_ImageColours(1.0, 1.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
for (i = 0, y=sy-17; i < countof(team); i++, y -= 18)
|
||||||
|
{
|
||||||
|
int fl = (cl_ctfflags>>team[i].shift)&7;
|
||||||
|
mpic_t *pic = NULL;
|
||||||
|
if (fl == 1)
|
||||||
|
pic = R2D_SafeCachePic(team[i].base);
|
||||||
|
else if (fl == 2)
|
||||||
|
pic = R2D_SafeCachePic(team[i].held);
|
||||||
|
else if (fl == 4)
|
||||||
|
pic = R2D_SafeCachePic(team[i].dropped);
|
||||||
|
if (pic)
|
||||||
|
R2D_ScalePic(x, y, 16, 16, pic);
|
||||||
|
}
|
||||||
|
for (i = 0, y=sy-17; i < countof(team); i++, y -= 18)
|
||||||
|
Draw_FunStringWidth (x+16, y+((16-8)/2), va("%i", *team[i].score), 32, 2, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
int playerteam[MAX_CLIENTS];
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char team[16+1];
|
char team[16+1];
|
||||||
int frags;
|
int frags;
|
||||||
|
@ -1466,11 +1520,13 @@ typedef struct {
|
||||||
int topcolour, bottomcolour;
|
int topcolour, bottomcolour;
|
||||||
qboolean ownteam;
|
qboolean ownteam;
|
||||||
} team_t;
|
} team_t;
|
||||||
team_t teams[MAX_CLIENTS];
|
static int playerteam[MAX_CLIENTS];
|
||||||
int teamsort[MAX_CLIENTS];
|
static team_t teams[MAX_CLIENTS];
|
||||||
int scoreboardteams;
|
static int teamsort[MAX_CLIENTS];
|
||||||
|
static int scoreboardteams;
|
||||||
|
static qboolean consistentteams; //can hide the 'team' displays when colours are enough.
|
||||||
|
|
||||||
struct
|
static struct
|
||||||
{
|
{
|
||||||
unsigned char upper;
|
unsigned char upper;
|
||||||
short frags;
|
short frags;
|
||||||
|
@ -1567,9 +1623,12 @@ void Sbar_SortTeams (playerview_t *pv)
|
||||||
player_info_t *s;
|
player_info_t *s;
|
||||||
char t[16+1];
|
char t[16+1];
|
||||||
int ownnum;
|
int ownnum;
|
||||||
|
unsigned int seen;
|
||||||
|
char *end;
|
||||||
|
|
||||||
// request new ping times every two second
|
// request new ping times every two second
|
||||||
scoreboardteams = 0;
|
scoreboardteams = 0;
|
||||||
|
consistentteams = false;
|
||||||
|
|
||||||
if (!cl.teamplay)
|
if (!cl.teamplay)
|
||||||
return;
|
return;
|
||||||
|
@ -1652,6 +1711,40 @@ void Sbar_SortTeams (playerview_t *pv)
|
||||||
teamsort[i] = teamsort[j];
|
teamsort[i] = teamsort[j];
|
||||||
teamsort[j] = k;
|
teamsort[j] = k;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
seen = 0;
|
||||||
|
for (i = 0; i < scoreboardteams; i++)
|
||||||
|
{
|
||||||
|
//make sure the colour is one of quake's valid non-fullbright colour ranges.
|
||||||
|
if (teams[i].bottomcolour < 0 || teams[i].bottomcolour > 13)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//don't allow multiple teams with the same colour but different names.
|
||||||
|
if (seen & (1<<teams[i].bottomcolour))
|
||||||
|
return;
|
||||||
|
seen |= (1<<teams[i].bottomcolour);
|
||||||
|
|
||||||
|
if (*teams[i].team == 't')
|
||||||
|
{ //fte servers use t%i for nq team names
|
||||||
|
if (teams[i].bottomcolour != strtoul(teams[i].team+1, &end, 10) || *end)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (teams[i].bottomcolour != strtoul(teams[i].team, &end, 10) || *end)
|
||||||
|
{
|
||||||
|
if (teams[i].bottomcolour == 4 && !strcasecmp(teams[i].team, "red"))
|
||||||
|
;
|
||||||
|
else if (teams[i].bottomcolour == 13 && !strcasecmp(teams[i].team, "blue"))
|
||||||
|
;
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if we got this far, we had no dupe colours and every name checked out.
|
||||||
|
consistentteams = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2604,6 +2697,10 @@ static void Sbar_DrawTeamStatus(playerview_t *pv)
|
||||||
int y;
|
int y;
|
||||||
int track;
|
int track;
|
||||||
|
|
||||||
|
#ifdef NQPROT
|
||||||
|
Sbar_DrawCTFScores(pv);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!sbar_teamstatus.ival)
|
if (!sbar_teamstatus.ival)
|
||||||
return;
|
return;
|
||||||
y = -32;
|
y = -32;
|
||||||
|
@ -3045,14 +3142,14 @@ void Sbar_IntermissionNumber (float x, float y, int num, int digits, int color,
|
||||||
}
|
}
|
||||||
|
|
||||||
#define COL_TEAM_LOWAVGHIGH COLUMN("low/avg/high", 12*8, {sprintf (num, "%3i/%3i/%3i", plow, pavg, phigh); Draw_FunString ( x, y, num); })
|
#define COL_TEAM_LOWAVGHIGH COLUMN("low/avg/high", 12*8, {sprintf (num, "%3i/%3i/%3i", plow, pavg, phigh); Draw_FunString ( x, y, num); })
|
||||||
#define COL_TEAM_TEAM COLUMN("team", 4*8, {Draw_FunStringWidth ( x, y, tm->team, 4*8, false, false); \
|
#define COL_TEAM_TEAM if (!consistentteams){COLUMN("team", 4*8, {Draw_FunStringWidth ( x, y, tm->team, 4*8, false, false); })}
|
||||||
|
#define COL_TEAM_TOTAL COLUMN("total", 5*8, {Draw_FunString ( x, y, va("%5i", tm->frags)); \
|
||||||
if (ourteam)\
|
if (ourteam)\
|
||||||
{\
|
{\
|
||||||
Draw_FunString ( x - 1*8, y, "^Ue010");\
|
Draw_FunString ( x - 1*8, y, "^Ue010");\
|
||||||
Draw_FunString ( x + 4*8, y, "^Ue011");\
|
Draw_FunString ( x + 5*8, y, "^Ue011");\
|
||||||
}\
|
}\
|
||||||
})
|
})
|
||||||
#define COL_TEAM_TOTAL COLUMN("total", 5*8, {Draw_FunString ( x, y, va("%5i", tm->frags)); })
|
|
||||||
#define COL_TEAM_PLAYERS COLUMN("players", 7*8, {Draw_FunString ( x, y, va("%5i", tm->players)); })
|
#define COL_TEAM_PLAYERS COLUMN("players", 7*8, {Draw_FunString ( x, y, va("%5i", tm->players)); })
|
||||||
#define ALL_TEAM_COLUMNS COL_TEAM_LOWAVGHIGH COL_TEAM_TEAM COL_TEAM_TOTAL COL_TEAM_PLAYERS
|
#define ALL_TEAM_COLUMNS COL_TEAM_LOWAVGHIGH COL_TEAM_TEAM COL_TEAM_TOTAL COL_TEAM_PLAYERS
|
||||||
|
|
||||||
|
@ -3092,6 +3189,9 @@ void Sbar_TeamOverlay (playerview_t *pv)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sort the teams
|
||||||
|
Sbar_SortTeams(pv);
|
||||||
|
|
||||||
y = gr.y;
|
y = gr.y;
|
||||||
|
|
||||||
if (scr_scoreboard_drawtitle.ival)
|
if (scr_scoreboard_drawtitle.ival)
|
||||||
|
@ -3157,9 +3257,6 @@ void Sbar_TeamOverlay (playerview_t *pv)
|
||||||
#undef COLUMN
|
#undef COLUMN
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort the teams
|
|
||||||
Sbar_SortTeams(pv);
|
|
||||||
|
|
||||||
if (pv->spectator)
|
if (pv->spectator)
|
||||||
trackplayer = Cam_TrackNum(pv);
|
trackplayer = Cam_TrackNum(pv);
|
||||||
else
|
else
|
||||||
|
@ -3326,7 +3423,7 @@ ping time frags name
|
||||||
Sbar_FillPC(x, y+4, 40, 4, bottom); \
|
Sbar_FillPC(x, y+4, 40, 4, bottom); \
|
||||||
} \
|
} \
|
||||||
})
|
})
|
||||||
#define COLUMN_TEAMNAME COLUMN(team, 4*8, \
|
#define COLUMN_TEAMNAME COLUMN(team, (consistentteams?0:(4*8)), \
|
||||||
{ \
|
{ \
|
||||||
if (!s->spectator) \
|
if (!s->spectator) \
|
||||||
{ \
|
{ \
|
||||||
|
@ -3454,7 +3551,7 @@ void Sbar_DeathmatchOverlay (playerview_t *pv, int start)
|
||||||
|
|
||||||
rank_width = 0;
|
rank_width = 0;
|
||||||
|
|
||||||
#define COLUMN(title, cwidth, code, fill) if (rank_width+(cwidth)+8 <= gr.width) {showcolumns |= (1<<COLUMN##title); rank_width += cwidth+8;}
|
#define COLUMN(title, cwidth, code, fill) if (rank_width+(cwidth)+8 <= gr.width && cwidth) {showcolumns |= (1<<COLUMN##title); rank_width += cwidth+8;}
|
||||||
//columns are listed here in priority order (if the screen is too narrow, later ones will be hidden)
|
//columns are listed here in priority order (if the screen is too narrow, later ones will be hidden)
|
||||||
COLUMN_NAME
|
COLUMN_NAME
|
||||||
COLUMN_PING
|
COLUMN_PING
|
||||||
|
@ -3529,7 +3626,7 @@ void Sbar_DeathmatchOverlay (playerview_t *pv, int start)
|
||||||
}
|
}
|
||||||
|
|
||||||
x = startx;
|
x = startx;
|
||||||
#define COLUMN(title, width, code, fill) if (width && (showcolumns & (1<<COLUMN##title))) {Draw_FunString(x, y, #title); x += width+8;}
|
#define COLUMN(title, width, code, fill) if (showcolumns & (1<<COLUMN##title)) {Draw_FunString(x, y, #title); x += width+8;}
|
||||||
ALLCOLUMNS
|
ALLCOLUMNS
|
||||||
#undef COLUMN
|
#undef COLUMN
|
||||||
|
|
||||||
|
@ -3696,8 +3793,8 @@ static void Sbar_MiniDeathmatchOverlay (playerview_t *pv)
|
||||||
|
|
||||||
// scores
|
// scores
|
||||||
Sbar_SortFrags (false, false);
|
Sbar_SortFrags (false, false);
|
||||||
if (sbar_rect.width >= 640)
|
// if (sbar_rect.width >= 640)
|
||||||
Sbar_SortTeams(pv);
|
Sbar_SortTeams(pv);
|
||||||
|
|
||||||
if (!scoreboardlines)
|
if (!scoreboardlines)
|
||||||
return; // no one there?
|
return; // no one there?
|
||||||
|
@ -3769,7 +3866,7 @@ static void Sbar_MiniDeathmatchOverlay (playerview_t *pv)
|
||||||
|
|
||||||
Q_strncpyz(name, s->name, sizeof(name));
|
Q_strncpyz(name, s->name, sizeof(name));
|
||||||
// team and name
|
// team and name
|
||||||
if (cl.teamplay)
|
if (cl.teamplay && !consistentteams)
|
||||||
{
|
{
|
||||||
Draw_FunStringWidth (x+48, y, s->team, 32, false, false);
|
Draw_FunStringWidth (x+48, y, s->team, 32, false, false);
|
||||||
Draw_FunStringWidth (x+48+40, y, name, MAX_DISPLAYEDNAME*8, false, false);
|
Draw_FunStringWidth (x+48+40, y, name, MAX_DISPLAYEDNAME*8, false, false);
|
||||||
|
@ -3778,38 +3875,67 @@ static void Sbar_MiniDeathmatchOverlay (playerview_t *pv)
|
||||||
Draw_FunStringWidth (x+48, y, name, MAX_DISPLAYEDNAME*8, false, false);
|
Draw_FunStringWidth (x+48, y, name, MAX_DISPLAYEDNAME*8, false, false);
|
||||||
y += 8;
|
y += 8;
|
||||||
}
|
}
|
||||||
|
x += 48;
|
||||||
|
if (cl.teamplay && !consistentteams)
|
||||||
|
x += 40;
|
||||||
|
x += MAX_DISPLAYEDNAME*8;
|
||||||
|
x += 8;
|
||||||
|
|
||||||
// draw teams if room
|
// draw teams if room
|
||||||
if (sbar_rect.width < 640 || !cl.teamplay)
|
if (x + (consistentteams?40:80) > sbar_rect.x+sbar_rect.width || !cl.teamplay)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
y = sbar_rect.y + sbar_rect.height - sb_lines;
|
||||||
|
|
||||||
// draw seperator
|
// draw seperator
|
||||||
x += 208;
|
R2D_ImageColours(0.3, 0.3, 0.3, 1);
|
||||||
|
R2D_FillBlock(x, y, 2, sb_lines);
|
||||||
|
R2D_ImageColours(1,1,1,1);
|
||||||
|
x += 2;
|
||||||
// for (y = sbar_rect.height - sb_lines; y < sbar_rect.height - 6; y += 2)
|
// for (y = sbar_rect.height - sb_lines; y < sbar_rect.height - 6; y += 2)
|
||||||
// Draw_ColouredCharacter(x, y, CON_WHITEMASK|14);
|
// Draw_ColouredCharacter(x, y, CON_WHITEMASK|14);
|
||||||
|
|
||||||
x += 16;
|
x += 8;
|
||||||
|
|
||||||
y = sbar_rect.height - sb_lines;
|
for (i=0 ; i < scoreboardteams && y <= sbar_rect.y+sbar_rect.height; i++)
|
||||||
for (i=0 ; i < scoreboardteams && y <= sbar_rect.height; i++)
|
|
||||||
{
|
{
|
||||||
k = teamsort[i];
|
k = teamsort[i];
|
||||||
tm = teams + k;
|
tm = teams + k;
|
||||||
|
|
||||||
// draw pings
|
if (consistentteams)
|
||||||
Draw_FunStringWidth (x, y, tm->team, 32, false, false);
|
|
||||||
|
|
||||||
// draw total
|
|
||||||
sprintf (num, "%5i", tm->frags);
|
|
||||||
Draw_FunString(x + 40, y, num);
|
|
||||||
|
|
||||||
if (!strncmp(cl.players[pv->playernum].team, tm->team, 16))
|
|
||||||
{
|
{
|
||||||
Font_BeginString(font_default, x-8, y, &px, &py);
|
// draw total
|
||||||
Font_DrawChar(px, py, CON_WHITEMASK, 16|0xe000);
|
Sbar_FillPC ( x, y+1, 48, 3, tm->topcolour);
|
||||||
Font_BeginString(font_default, x+32, y, &px, &py);
|
Sbar_FillPC ( x, y+4, 48, 4, tm->bottomcolour);
|
||||||
Font_DrawChar(px, py, CON_WHITEMASK, 17|0xe000);
|
R2D_ImageColours(1,1,1,1);
|
||||||
Font_EndString(font_default);
|
sprintf (num, "%i", tm->frags);
|
||||||
|
Draw_FunStringWidth(x,y,num, 40, true, false);
|
||||||
|
if (!strncmp(cl.players[pv->playernum].team, tm->team, 16))
|
||||||
|
{
|
||||||
|
Font_BeginString(font_default, x, y, &px, &py);
|
||||||
|
Font_DrawChar(px, py, CON_WHITEMASK, 16|0xe000);
|
||||||
|
Font_BeginString(font_default, x+40, y, &px, &py);
|
||||||
|
Font_DrawChar(px, py, CON_WHITEMASK, 17|0xe000);
|
||||||
|
Font_EndString(font_default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// draw name
|
||||||
|
Draw_FunStringWidth (x, y, tm->team, 32, false, false);
|
||||||
|
|
||||||
|
// draw total
|
||||||
|
sprintf (num, "%5i", tm->frags);
|
||||||
|
Draw_FunString(x + 40, y, num);
|
||||||
|
|
||||||
|
if (!strncmp(cl.players[pv->playernum].team, tm->team, 16))
|
||||||
|
{
|
||||||
|
Font_BeginString(font_default, x-8, y, &px, &py);
|
||||||
|
Font_DrawChar(px, py, CON_WHITEMASK, 16|0xe000);
|
||||||
|
Font_BeginString(font_default, x+32, y, &px, &py);
|
||||||
|
Font_DrawChar(px, py, CON_WHITEMASK, 17|0xe000);
|
||||||
|
Font_EndString(font_default);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
y += 8;
|
y += 8;
|
||||||
|
|
|
@ -981,8 +981,8 @@ struct po_s *PO_Create(void);
|
||||||
void PO_Merge(struct po_s *po, vfsfile_t *file);
|
void PO_Merge(struct po_s *po, vfsfile_t *file);
|
||||||
const char *PO_GetText(struct po_s *po, const char *msg);
|
const char *PO_GetText(struct po_s *po, const char *msg);
|
||||||
void PO_Close(struct po_s *po);
|
void PO_Close(struct po_s *po);
|
||||||
const char *TL_Translate(const char *src); //$foo translations.
|
const char *TL_Translate(int language, const char *src); //$foo translations.
|
||||||
void TL_Reformat(char *out, size_t outsize, size_t numargs, const char **arg); //"{0} died\n" formatting (with $foo translation, on each arg)
|
void TL_Reformat(int language, char *out, size_t outsize, size_t numargs, const char **arg); //"{0} died\n" formatting (with $foo translation, on each arg)
|
||||||
|
|
||||||
//
|
//
|
||||||
// log.c
|
// log.c
|
||||||
|
|
|
@ -7996,7 +7996,7 @@ qc_extension_t QSG_Extensions[] = {
|
||||||
{"EXT_DIMENSION_GHOST"},
|
{"EXT_DIMENSION_GHOST"},
|
||||||
// {"EX_EXTENDED_EF", NULL, 0,{NULL}, "Provides EF_CANDLELIGHT..."},
|
// {"EX_EXTENDED_EF", NULL, 0,{NULL}, "Provides EF_CANDLELIGHT..."},
|
||||||
// {"EX_MOVETYPE_GIB", NULL, 0,{NULL}, "Adds MOVETYPE_GIB - basically MOVETYPE_BOUNCE with gravity controlled by a cvar instead of just setting the .gravity field..."},
|
// {"EX_MOVETYPE_GIB", NULL, 0,{NULL}, "Adds MOVETYPE_GIB - basically MOVETYPE_BOUNCE with gravity controlled by a cvar instead of just setting the .gravity field..."},
|
||||||
// {"EX_PROMPT", NULL, 3,{"ex_prompt", "ex_promptchoice", "ex_clearprompt"}, "Engine-driven alternative to centerprint menus."},
|
{"EX_PROMPT", NULL, 3,{"ex_prompt", "ex_promptchoice", "ex_clearprompt"}, "Engine-driven alternative to centerprint menus."},
|
||||||
{"FRIK_FILE", check_notrerelease, 11,{"stof", "fopen","fclose","fgets","fputs","strlen","strcat","substring","stov","strzone","strunzone"}},
|
{"FRIK_FILE", check_notrerelease, 11,{"stof", "fopen","fclose","fgets","fputs","strlen","strcat","substring","stov","strzone","strunzone"}},
|
||||||
{"FTE_CALLTIMEOFDAY", NULL, 1,{"calltimeofday"}, "Replication of mvdsv functionality (call calltimeofday to cause 'timeofday' to be called, with arguments that can be saved off to a global). Generally strftime is simpler to use."},
|
{"FTE_CALLTIMEOFDAY", NULL, 1,{"calltimeofday"}, "Replication of mvdsv functionality (call calltimeofday to cause 'timeofday' to be called, with arguments that can be saved off to a global). Generally strftime is simpler to use."},
|
||||||
{"FTE_CSQC_ALTCONSOLES", NULL, 4,{"con_getset", "con_printf", "con_draw", "con_input"}, "The engine tracks multiple consoles. These may or may not be directly visible to the user."},
|
{"FTE_CSQC_ALTCONSOLES", NULL, 4,{"con_getset", "con_printf", "con_draw", "con_input"}, "The engine tracks multiple consoles. These may or may not be directly visible to the user."},
|
||||||
|
|
|
@ -15,15 +15,9 @@ int com_language;
|
||||||
char sys_language[64] = "";
|
char sys_language[64] = "";
|
||||||
static char langpath[MAX_OSPATH] = "";
|
static char langpath[MAX_OSPATH] = "";
|
||||||
struct language_s languages[MAX_LANGUAGES];
|
struct language_s languages[MAX_LANGUAGES];
|
||||||
static struct po_s *com_translations;
|
|
||||||
|
|
||||||
static void QDECL TL_LanguageChanged(struct cvar_s *var, char *oldvalue)
|
static void QDECL TL_LanguageChanged(struct cvar_s *var, char *oldvalue)
|
||||||
{
|
{
|
||||||
if (com_translations)
|
|
||||||
{
|
|
||||||
PO_Close(com_translations);
|
|
||||||
com_translations = NULL;
|
|
||||||
}
|
|
||||||
com_language = TL_FindLanguage(var->string);
|
com_language = TL_FindLanguage(var->string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +40,9 @@ void TL_Shutdown(void)
|
||||||
languages[j].name = NULL;
|
languages[j].name = NULL;
|
||||||
PO_Close(languages[j].po);
|
PO_Close(languages[j].po);
|
||||||
languages[j].po = NULL;
|
languages[j].po = NULL;
|
||||||
|
|
||||||
|
PO_Close(languages[j].po_qex);
|
||||||
|
languages[j].po_qex = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,10 +72,10 @@ static int TL_LoadLanguage(char *lang)
|
||||||
//keep truncating until we can find a name that works
|
//keep truncating until we can find a name that works
|
||||||
u = strrchr(lang, '_');
|
u = strrchr(lang, '_');
|
||||||
if (u)
|
if (u)
|
||||||
|
{
|
||||||
*u = 0;
|
*u = 0;
|
||||||
else
|
return TL_LoadLanguage(lang);
|
||||||
lang = "";
|
}
|
||||||
return TL_LoadLanguage(lang);
|
|
||||||
}
|
}
|
||||||
languages[j].name = strdup(lang);
|
languages[j].name = strdup(lang);
|
||||||
languages[j].po = NULL;
|
languages[j].po = NULL;
|
||||||
|
@ -503,7 +500,7 @@ const char *PO_GetText(struct po_s *po, const char *msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void PO_Merge_Rerelease(struct po_s *po, const char *fmt)
|
static void PO_Merge_Rerelease(struct po_s *po, const char *langname, const char *fmt)
|
||||||
{
|
{
|
||||||
//FOO <plat,plat> = "CString"
|
//FOO <plat,plat> = "CString"
|
||||||
char line[32768];
|
char line[32768];
|
||||||
|
@ -512,22 +509,22 @@ static void PO_Merge_Rerelease(struct po_s *po, const char *fmt)
|
||||||
char *s;
|
char *s;
|
||||||
vfsfile_t *file = NULL;
|
vfsfile_t *file = NULL;
|
||||||
|
|
||||||
if (!file && *language.string) //use system locale names
|
if (!file && *langname) //use system locale names
|
||||||
file = FS_OpenVFS(va(fmt, language.string), "rb", FS_GAME);
|
file = FS_OpenVFS(va(fmt, langname), "rb", FS_GAME);
|
||||||
if (!file) //make a guess
|
if (!file) //make a guess
|
||||||
{
|
{
|
||||||
s = NULL;
|
s = NULL;
|
||||||
if (language.string[0] && language.string[1] && (!language.string[2] || language.string[2] == '-' || language.string[2] == '_'))
|
if (langname[0] && langname[1] && (!langname[2] || langname[2] == '-' || langname[2] == '_'))
|
||||||
{ //try to map the user's formal locale to the rerelease's arbitrary names (at least from the perspective of anyone who doesn't speak english).
|
{ //try to map the user's formal locale to the rerelease's arbitrary names (at least from the perspective of anyone who doesn't speak english).
|
||||||
if (!strncmp(language.string, "fr", 2))
|
if (!strncmp(langname, "fr", 2))
|
||||||
s = "french";
|
s = "french";
|
||||||
else if (!strncmp(language.string, "de", 2))
|
else if (!strncmp(langname, "de", 2))
|
||||||
s = "german";
|
s = "german";
|
||||||
else if (!strncmp(language.string, "it", 2))
|
else if (!strncmp(langname, "it", 2))
|
||||||
s = "italian";
|
s = "italian";
|
||||||
else if (!strncmp(language.string, "ru", 2))
|
else if (!strncmp(langname, "ru", 2))
|
||||||
s = "russian";
|
s = "russian";
|
||||||
else if (!strncmp(language.string, "es", 2))
|
else if (!strncmp(langname, "es", 2))
|
||||||
s = "spanish";
|
s = "spanish";
|
||||||
}
|
}
|
||||||
if (s)
|
if (s)
|
||||||
|
@ -553,18 +550,18 @@ static void PO_Merge_Rerelease(struct po_s *po, const char *fmt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *TL_Translate(const char *src)
|
const char *TL_Translate(int language, const char *src)
|
||||||
{
|
{
|
||||||
if (*src == '$')
|
if (*src == '$')
|
||||||
{
|
{
|
||||||
if (!com_translations)
|
if (!languages[language].po_qex)
|
||||||
{
|
{
|
||||||
char lang[64], *h;
|
char lang[64], *h;
|
||||||
vfsfile_t *f = NULL;
|
vfsfile_t *f = NULL;
|
||||||
com_translations = PO_Create();
|
languages[language].po_qex = PO_Create();
|
||||||
PO_Merge_Rerelease(com_translations, "localization/loc_%s.txt");
|
PO_Merge_Rerelease(languages[language].po_qex, languages[language].name, "localization/loc_%s.txt");
|
||||||
|
|
||||||
Q_strncpyz(lang, language.string, sizeof(lang));
|
Q_strncpyz(lang, languages[language].name, sizeof(lang));
|
||||||
while ((h = strchr(lang, '-')))
|
while ((h = strchr(lang, '-')))
|
||||||
*h = '_'; //standardise it
|
*h = '_'; //standardise it
|
||||||
if (*lang)
|
if (*lang)
|
||||||
|
@ -579,20 +576,20 @@ const char *TL_Translate(const char *src)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (f)
|
if (f)
|
||||||
PO_Merge(com_translations, f);
|
PO_Merge(languages[language].po_qex, f);
|
||||||
}
|
}
|
||||||
src = PO_GetText(com_translations, src);
|
src = PO_GetText(languages[language].po_qex, src);
|
||||||
}
|
}
|
||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
void TL_Reformat(char *out, size_t outsize, size_t numargs, const char **arg)
|
void TL_Reformat(int language, char *out, size_t outsize, size_t numargs, const char **arg)
|
||||||
{
|
{
|
||||||
const char *fmt;
|
const char *fmt;
|
||||||
const char *a;
|
const char *a;
|
||||||
size_t alen;
|
size_t alen;
|
||||||
|
|
||||||
fmt = (numargs>0&&arg[0])?arg[0]:"";
|
fmt = (numargs>0&&arg[0])?arg[0]:"";
|
||||||
fmt = TL_Translate(fmt);
|
fmt = TL_Translate(language, fmt);
|
||||||
|
|
||||||
outsize--;
|
outsize--;
|
||||||
while (outsize > 0)
|
while (outsize > 0)
|
||||||
|
@ -623,7 +620,7 @@ void TL_Reformat(char *out, size_t outsize, size_t numargs, const char **arg)
|
||||||
if (index >= numargs || !arg[index])
|
if (index >= numargs || !arg[index])
|
||||||
a = "";
|
a = "";
|
||||||
else
|
else
|
||||||
a = TL_Translate(arg[index]);
|
a = TL_Translate(language, arg[index]);
|
||||||
|
|
||||||
alen = strlen(a);
|
alen = strlen(a);
|
||||||
if (alen > outsize)
|
if (alen > outsize)
|
||||||
|
|
|
@ -12,6 +12,7 @@ struct language_s
|
||||||
{
|
{
|
||||||
char *name;
|
char *name;
|
||||||
struct po_s *po;
|
struct po_s *po;
|
||||||
|
struct po_s *po_qex;
|
||||||
};
|
};
|
||||||
extern struct language_s languages[MAX_LANGUAGES];
|
extern struct language_s languages[MAX_LANGUAGES];
|
||||||
extern int com_language;
|
extern int com_language;
|
||||||
|
|
|
@ -10857,11 +10857,15 @@ static void QCBUILTIN PF_centerprint_qex(pubprogfuncs_t *prinst, struct globalva
|
||||||
int args;
|
int args;
|
||||||
char s[1024];
|
char s[1024];
|
||||||
int entnum;
|
int entnum;
|
||||||
|
int lang = com_language;
|
||||||
|
|
||||||
entnum = G_EDICTNUM(prinst, OFS_PARM0);
|
entnum = G_EDICTNUM(prinst, OFS_PARM0);
|
||||||
for (args = 0; args+1 < prinst->callargc; args++)
|
for (args = 0; args+1 < prinst->callargc; args++)
|
||||||
arg[args] = PR_GetStringOfs(prinst, OFS_PARM1+args*(OFS_PARM1-OFS_PARM0));
|
arg[args] = PR_GetStringOfs(prinst, OFS_PARM1+args*(OFS_PARM1-OFS_PARM0));
|
||||||
TL_Reformat(s, sizeof(s), args, arg);
|
|
||||||
|
if (entnum >= 1 && entnum <= sv.allocated_client_slots)
|
||||||
|
lang = svs.clients[entnum-1].language;
|
||||||
|
TL_Reformat(lang, s, sizeof(s), args, arg);
|
||||||
|
|
||||||
PF_centerprint_Internal(entnum, false, s);
|
PF_centerprint_Internal(entnum, false, s);
|
||||||
}
|
}
|
||||||
|
@ -10893,7 +10897,6 @@ static void QCBUILTIN PF_sprint_qex(pubprogfuncs_t *prinst, struct globalvars_s
|
||||||
for (args = 0; args+2 < prinst->callargc; args++)
|
for (args = 0; args+2 < prinst->callargc; args++)
|
||||||
arg[args] = PR_GetStringOfs(prinst, OFS_PARM2+args*(OFS_PARM1-OFS_PARM0));
|
arg[args] = PR_GetStringOfs(prinst, OFS_PARM2+args*(OFS_PARM1-OFS_PARM0));
|
||||||
}
|
}
|
||||||
TL_Reformat(s, sizeof(s), args, arg);
|
|
||||||
|
|
||||||
if (entnum < 1 || entnum > sv.allocated_client_slots)
|
if (entnum < 1 || entnum > sv.allocated_client_slots)
|
||||||
{
|
{
|
||||||
|
@ -10903,6 +10906,7 @@ static void QCBUILTIN PF_sprint_qex(pubprogfuncs_t *prinst, struct globalvars_s
|
||||||
|
|
||||||
client = &svs.clients[entnum-1];
|
client = &svs.clients[entnum-1];
|
||||||
|
|
||||||
|
TL_Reformat(client->language, s, sizeof(s), args, arg);
|
||||||
SV_ClientPrintf (client, level, "%s", s);
|
SV_ClientPrintf (client, level, "%s", s);
|
||||||
|
|
||||||
if (sv_specprint.ival & SPECPRINT_SPRINT)
|
if (sv_specprint.ival & SPECPRINT_SPRINT)
|
||||||
|
@ -10929,7 +10933,6 @@ static void QCBUILTIN PF_bprint_qex(pubprogfuncs_t *prinst, struct globalvars_s
|
||||||
{ //TODO: send the strings to the client for localisation+reordering
|
{ //TODO: send the strings to the client for localisation+reordering
|
||||||
const char *arg[8];
|
const char *arg[8];
|
||||||
int args;
|
int args;
|
||||||
char formatted[1024];
|
|
||||||
int level;
|
int level;
|
||||||
|
|
||||||
if (progstype == PROG_QW)
|
if (progstype == PROG_QW)
|
||||||
|
@ -10945,8 +10948,178 @@ static void QCBUILTIN PF_bprint_qex(pubprogfuncs_t *prinst, struct globalvars_s
|
||||||
arg[args] = PR_GetStringOfs(prinst, OFS_PARM0+args*(OFS_PARM1-OFS_PARM0));
|
arg[args] = PR_GetStringOfs(prinst, OFS_PARM0+args*(OFS_PARM1-OFS_PARM0));
|
||||||
}
|
}
|
||||||
|
|
||||||
TL_Reformat(formatted, sizeof(formatted), args, arg);
|
SV_BroadcastPrint_QexLoc (0, level, arg, args);
|
||||||
SV_BroadcastPrintf (level, "%s", formatted);
|
}
|
||||||
|
|
||||||
|
void SV_Prompt_Input(client_t *cl, usercmd_t *ucmd)
|
||||||
|
{
|
||||||
|
if (cl->prompt.active && !cl->qex)
|
||||||
|
{ //with this serverside, we don't get autorepeat etc.
|
||||||
|
//we also can't prevent movement beyond the menu closure.
|
||||||
|
if (ucmd->forwardmove >= 100 && cl->prompt.oldmove[0] < 100)
|
||||||
|
{ //up
|
||||||
|
if (cl->prompt.selected > 0)
|
||||||
|
cl->prompt.selected--;
|
||||||
|
else if (cl->prompt.numopts)
|
||||||
|
cl->prompt.selected = cl->prompt.numopts-1; //wrap.
|
||||||
|
|
||||||
|
cl->prompt.nextsend = realtime;
|
||||||
|
}
|
||||||
|
else if (ucmd->forwardmove <= -100 && cl->prompt.oldmove[0] > -100)
|
||||||
|
{ //down
|
||||||
|
cl->prompt.selected++;
|
||||||
|
if (cl->prompt.selected >= cl->prompt.numopts)
|
||||||
|
cl->prompt.selected = 0; //wrap.
|
||||||
|
cl->prompt.nextsend = realtime;
|
||||||
|
}
|
||||||
|
else if (ucmd->sidemove >= 100 && cl->prompt.oldmove[1] < 100)
|
||||||
|
{ //right (use)
|
||||||
|
if (cl->prompt.selected < cl->prompt.numopts)
|
||||||
|
cl->edict->v->impulse = cl->prompt.opt[cl->prompt.selected].impulse;
|
||||||
|
}
|
||||||
|
cl->prompt.oldmove[0] = ucmd->forwardmove;
|
||||||
|
cl->prompt.oldmove[1] = ucmd->sidemove;
|
||||||
|
ucmd->forwardmove = 0;
|
||||||
|
ucmd->sidemove = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cl->prompt.oldmove[0] = ucmd->forwardmove;
|
||||||
|
cl->prompt.oldmove[1] = ucmd->sidemove;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void SV_Prompt_Resend(client_t *client)
|
||||||
|
{
|
||||||
|
Z_Free(client->centerprintstring);
|
||||||
|
client->centerprintstring = NULL;
|
||||||
|
|
||||||
|
if (client->prompt.nextsend > realtime)
|
||||||
|
return; //still good.
|
||||||
|
|
||||||
|
if (client->qex)
|
||||||
|
{ //can depend on the client doing any translation stuff.
|
||||||
|
size_t sz;
|
||||||
|
sizebuf_t *msg;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
sz = 2;
|
||||||
|
if (client->prompt.numopts)
|
||||||
|
{
|
||||||
|
sz += strlen(client->prompt.header)+1;
|
||||||
|
for (i = 0; i < client->prompt.numopts; i++)
|
||||||
|
sz += strlen(client->prompt.opt[i].text)+2;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = ClientReliable_StartWrite(client, sz);
|
||||||
|
|
||||||
|
MSG_WriteByte(msg, svcqex_prompt);
|
||||||
|
MSG_WriteByte(msg, client->prompt.numopts);
|
||||||
|
if (client->prompt.numopts)
|
||||||
|
{
|
||||||
|
MSG_WriteString(msg, client->prompt.header);
|
||||||
|
for (i = 0; i < client->prompt.numopts; i++)
|
||||||
|
{
|
||||||
|
MSG_WriteString(msg, client->prompt.opt[i].text);
|
||||||
|
MSG_WriteByte(msg, client->prompt.opt[i].impulse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientReliable_FinishWrite(client);
|
||||||
|
|
||||||
|
client->prompt.nextsend = DBL_MAX; //don't let it time out.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ //emulate via centerprints
|
||||||
|
const char *txt[4];
|
||||||
|
size_t i;
|
||||||
|
client->prompt.nextsend = realtime + 1; //don't let it time out.
|
||||||
|
|
||||||
|
if (client->prompt.numopts)
|
||||||
|
{
|
||||||
|
txt[0] = client->prompt.header?client->prompt.header:"";
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
if (client->prompt.selected + i - 1u < client->prompt.numopts)
|
||||||
|
txt[1+i] = client->prompt.opt[client->prompt.selected + i - 1u].text;
|
||||||
|
else
|
||||||
|
txt[1+i] = " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
//need to translate it too.
|
||||||
|
for (i = 0; i < countof(txt); i++)
|
||||||
|
txt[i] = TL_Translate(client->language, txt[i]);
|
||||||
|
|
||||||
|
client->centerprintstring = va("%s\n%s\n^a[[ %s ]]^a\n%s", txt[0], txt[1], txt[2], txt[3]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
client->centerprintstring = client->prompt.header?client->prompt.header:"";
|
||||||
|
client->centerprintstring = Z_StrDup(client->centerprintstring);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void SV_Prompt_Clear(client_t *cl)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
cl->prompt.active = false;
|
||||||
|
Z_Free(cl->prompt.header);
|
||||||
|
cl->prompt.header = NULL;
|
||||||
|
cl->prompt.selected = 0;
|
||||||
|
cl->prompt.nextsend = realtime;
|
||||||
|
|
||||||
|
for (i = 0; i < cl->prompt.numopts; i++)
|
||||||
|
Z_Free(cl->prompt.opt[i].text);
|
||||||
|
cl->prompt.numopts = cl->prompt.maxopts = 0;
|
||||||
|
Z_Free(cl->prompt.opt);
|
||||||
|
cl->prompt.opt = NULL;
|
||||||
|
}
|
||||||
|
static void QCBUILTIN PF_prompt_qex(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||||
|
{
|
||||||
|
int p = G_EDICT(prinst, OFS_PARM0)->entnum - 1;
|
||||||
|
client_t *cl;
|
||||||
|
const char *text = (prinst->callargc >= 2)?PR_GetStringOfs(prinst, OFS_PARM1):NULL;
|
||||||
|
unsigned int opts = (prinst->callargc >= 3)?G_FLOAT(OFS_PARM2):0;
|
||||||
|
if (p < 0 || p >= sv.allocated_client_slots)
|
||||||
|
{
|
||||||
|
PR_BIError (prinst, "PF_clearprompt_qex: not a player\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cl = &svs.clients[p];
|
||||||
|
|
||||||
|
SV_Prompt_Clear(cl);
|
||||||
|
if (!text)
|
||||||
|
{
|
||||||
|
SV_Prompt_Resend(cl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cl->prompt.active = true;
|
||||||
|
cl->prompt.maxopts = opts;
|
||||||
|
cl->prompt.numopts = 0;
|
||||||
|
Z_StrDupPtr(&cl->prompt.header, text);
|
||||||
|
cl->prompt.opt = Z_Malloc(sizeof(*cl->prompt.opt) * cl->prompt.maxopts);
|
||||||
|
}
|
||||||
|
static void QCBUILTIN PF_promptchoice_qex(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||||
|
{
|
||||||
|
int p = G_EDICT(prinst, OFS_PARM0)->entnum - 1;
|
||||||
|
client_t *cl;
|
||||||
|
const char *text = PR_GetStringOfs(prinst, OFS_PARM1);
|
||||||
|
int impulse = G_FLOAT(OFS_PARM2);
|
||||||
|
size_t opt;
|
||||||
|
if (p < 0 || p >= sv.allocated_client_slots)
|
||||||
|
{
|
||||||
|
PR_BIError (prinst, "PF_clearprompt_qex: not a player\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cl = &svs.clients[p];
|
||||||
|
if (!cl->prompt.active)
|
||||||
|
{
|
||||||
|
PR_BIError (prinst, "PF_clearprompt_qex: too many options\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
opt = cl->prompt.numopts++;
|
||||||
|
if (opt >= cl->prompt.maxopts)
|
||||||
|
Z_ReallocElements((void**)&cl->prompt.opt, &cl->prompt.maxopts, opt+1, sizeof(*cl->prompt.opt));
|
||||||
|
Z_StrDupPtr(&cl->prompt.opt[opt].text, text);
|
||||||
|
cl->prompt.opt[opt].impulse = impulse;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define STUB ,NULL,true
|
#define STUB ,NULL,true
|
||||||
|
@ -11215,9 +11388,9 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
|
||||||
{"ex_bot_followentity",PF_Fixme, 0, 0, 0,0, D("float(entity bot, entity goal)", "Behaviour is undocumented.")},
|
{"ex_bot_followentity",PF_Fixme, 0, 0, 0,0, D("float(entity bot, entity goal)", "Behaviour is undocumented.")},
|
||||||
{"ex_CheckPlayerEXFlags",PF_CheckPlayerEXFlags_qex,0,0, 0,0, D("float(entity playerEnt)", "Behaviour is undocumented.")},
|
{"ex_CheckPlayerEXFlags",PF_CheckPlayerEXFlags_qex,0,0, 0,0, D("float(entity playerEnt)", "Behaviour is undocumented.")},
|
||||||
{"ex_walkpathtogoal",PF_walkpathtogoal_qex,0, 0, 0,0, D("float(float movedist, vector goal)", "Behaviour is undocumented.")},
|
{"ex_walkpathtogoal",PF_walkpathtogoal_qex,0, 0, 0,0, D("float(float movedist, vector goal)", "Behaviour is undocumented.")},
|
||||||
// {"ex_prompt", PF_prompt_qex, 0, 0, 0,0, D("void(entity player, string text, float numchoices)", "Behaviour is undocumented.")},
|
{"ex_prompt", PF_prompt_qex, 0, 0, 0,0, D("void(entity player, string text, float numchoices)", "Behaviour is undocumented.")},
|
||||||
// {"ex_promptchoice", PF_promptchoice_qex,0, 0, 0,0, D("void(entity player, string text, float impulse)", "Behaviour is undocumented.")},
|
{"ex_promptchoice", PF_promptchoice_qex,0, 0, 0,0, D("void(entity player, string text, float impulse)", "Behaviour is undocumented.")},
|
||||||
// {"ex_clearprompt", PF_clearprompt_qex, 0, 0, 0,0, D("void(entity player)", "Behaviour is undocumented.")},
|
{"ex_clearprompt", PF_prompt_qex, 0, 0, 0,0, D("void(entity player)", "Behaviour is undocumented.")},
|
||||||
//End QuakeEx, for now. :(
|
//End QuakeEx, for now. :(
|
||||||
|
|
||||||
// Tomaz - QuakeC String Manipulation Begin
|
// Tomaz - QuakeC String Manipulation Begin
|
||||||
|
|
|
@ -559,6 +559,21 @@ typedef struct client_s
|
||||||
char *statss[MAX_CL_STATS];
|
char *statss[MAX_CL_STATS];
|
||||||
char *centerprintstring;
|
char *centerprintstring;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
qboolean active;
|
||||||
|
char *header;
|
||||||
|
double nextsend; //qex is a one-off, other clients need spam.
|
||||||
|
size_t numopts, maxopts, selected;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
char *text;
|
||||||
|
int impulse;
|
||||||
|
} *opt;
|
||||||
|
|
||||||
|
int oldmove[2];
|
||||||
|
} prompt;
|
||||||
|
|
||||||
union{ //save space
|
union{ //save space
|
||||||
client_frame_t *frames; // updates can be deltad from here
|
client_frame_t *frames; // updates can be deltad from here
|
||||||
#ifdef Q2SERVER
|
#ifdef Q2SERVER
|
||||||
|
@ -1303,6 +1318,7 @@ void SV_StuffcmdToClient_Unreliable(client_t *cl, const char *string);
|
||||||
void VARGS SV_ClientPrintf (client_t *cl, int level, const char *fmt, ...) LIKEPRINTF(3);
|
void VARGS SV_ClientPrintf (client_t *cl, int level, const char *fmt, ...) LIKEPRINTF(3);
|
||||||
void VARGS SV_ClientTPrintf (client_t *cl, int level, translation_t text, ...);
|
void VARGS SV_ClientTPrintf (client_t *cl, int level, translation_t text, ...);
|
||||||
void VARGS SV_BroadcastPrintf (int level, const char *fmt, ...) LIKEPRINTF(2);
|
void VARGS SV_BroadcastPrintf (int level, const char *fmt, ...) LIKEPRINTF(2);
|
||||||
|
void SV_BroadcastPrint_QexLoc (unsigned int flags, int level, const char **arg, int args);
|
||||||
void SV_BroadcastPrint (unsigned int flags, int level, const char *text);
|
void SV_BroadcastPrint (unsigned int flags, int level, const char *text);
|
||||||
//flags exposed to ktx.
|
//flags exposed to ktx.
|
||||||
#define BPRINT_IGNOREINDEMO (1<<0) // broad cast print will be not put in demo
|
#define BPRINT_IGNOREINDEMO (1<<0) // broad cast print will be not put in demo
|
||||||
|
@ -1317,6 +1333,10 @@ void SV_SendFixAngle(client_t *client, sizebuf_t *msg, int fixtype, qboolean rol
|
||||||
|
|
||||||
void SV_BroadcastUserinfoChange(client_t *about, qboolean isbasic, const char *key, const char *newval);
|
void SV_BroadcastUserinfoChange(client_t *about, qboolean isbasic, const char *key, const char *newval);
|
||||||
|
|
||||||
|
void SV_Prompt_Resend(client_t *cl);
|
||||||
|
void SV_Prompt_Clear(client_t *cl);
|
||||||
|
void SV_Prompt_Input(client_t *cl, usercmd_t *ucmd);
|
||||||
|
|
||||||
//
|
//
|
||||||
// sv_user.c
|
// sv_user.c
|
||||||
//
|
//
|
||||||
|
|
|
@ -613,6 +613,7 @@ void SV_DropClient (client_t *drop)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SV_Prompt_Clear(drop);
|
||||||
if (drop->centerprintstring)
|
if (drop->centerprintstring)
|
||||||
Z_Free(drop->centerprintstring);
|
Z_Free(drop->centerprintstring);
|
||||||
drop->centerprintstring = NULL;
|
drop->centerprintstring = NULL;
|
||||||
|
@ -1084,6 +1085,19 @@ void SV_FullClientUpdate (client_t *client, client_t *to)
|
||||||
MSG_WriteByte(buf, playercolor);
|
MSG_WriteByte(buf, playercolor);
|
||||||
ClientReliable_FinishWrite(to);
|
ClientReliable_FinishWrite(to);
|
||||||
|
|
||||||
|
if (to->qex)
|
||||||
|
{
|
||||||
|
unsigned int s1, s2;
|
||||||
|
if (client->netchan.remote_address.type == NA_LOOPBACK)
|
||||||
|
s1 = s2 = 0; //host
|
||||||
|
else
|
||||||
|
s1 = s2 = -1; //non-playfab connection
|
||||||
|
MSG_WriteByte(buf, svcqex_updatesocial);
|
||||||
|
MSG_WriteByte(buf, i);
|
||||||
|
MSG_WriteLong(buf, s1);
|
||||||
|
MSG_WriteLong(buf, s2);
|
||||||
|
}
|
||||||
|
|
||||||
if (to->fteprotocolextensions2 & PEXT2_PREDINFO)
|
if (to->fteprotocolextensions2 & PEXT2_PREDINFO)
|
||||||
{
|
{
|
||||||
char *s;
|
char *s;
|
||||||
|
@ -1961,11 +1975,18 @@ void SV_AcceptMessage(client_t *newcl)
|
||||||
MSG_WriteLong(&sb, 0);
|
MSG_WriteLong(&sb, 0);
|
||||||
MSG_WriteByte(&sb, CCREP_ACCEPT);
|
MSG_WriteByte(&sb, CCREP_ACCEPT);
|
||||||
if (newcl->qex)
|
if (newcl->qex)
|
||||||
; //skip any port info (as well as any proquake ident stuff.
|
; //skip any port info (as well as any proquake ident stuff).
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NET_LocalAddressForRemote(svs.sockets, &net_from, &localaddr, 0);
|
NET_LocalAddressForRemote(svs.sockets, &net_from, &localaddr, 0);
|
||||||
MSG_WriteLong(&sb, ShortSwap(localaddr.port));
|
if (net_from.prot == NP_DTLS
|
||||||
|
#ifdef SUPPORT_ICE
|
||||||
|
|| net_from.type == NA_ICE
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
MSG_WriteLong(&sb, 0); //send a port of 0 if we expect the client to be sane enough and/or otherwise problematic.
|
||||||
|
else
|
||||||
|
MSG_WriteLong(&sb, ShortSwap(localaddr.port));
|
||||||
if (newcl->proquake_angles_hack)
|
if (newcl->proquake_angles_hack)
|
||||||
{
|
{
|
||||||
MSG_WriteByte(&sb, MOD_PROQUAKE);
|
MSG_WriteByte(&sb, MOD_PROQUAKE);
|
||||||
|
|
|
@ -409,6 +409,69 @@ void SV_BroadcastPrint (unsigned int flags, int level, const char *string)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SV_BroadcastPrint_QexLoc (unsigned int flags, int level, const char **arg, int args)
|
||||||
|
{
|
||||||
|
client_t *cl;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
char string[1024];
|
||||||
|
|
||||||
|
if (!(flags & BPRINT_IGNORECONSOLE))
|
||||||
|
{
|
||||||
|
//pretend to print on the server, but not to the client's console
|
||||||
|
TL_Reformat(com_language, string, sizeof(string), args, arg);
|
||||||
|
Sys_Printf ("%s", string); // print to the system console
|
||||||
|
Log_String(LOG_CONSOLE, string); //dump into log
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(flags & BPRINT_IGNORECLIENTS))
|
||||||
|
{
|
||||||
|
for (i=0, cl = svs.clients ; i<svs.allocated_client_slots ; i++, cl++)
|
||||||
|
{
|
||||||
|
if (level < cl->messagelevel)
|
||||||
|
continue;
|
||||||
|
if (!cl->state)
|
||||||
|
continue;
|
||||||
|
if (cl->protocol == SCP_BAD)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (cl == sv.skipbprintclient) //silence bprints about the player in ClientConnect. NQ completely wipes the buffer after clientconnect, which is what traditionally hides it.
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (cl->controller)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (cl->qex)
|
||||||
|
{ //get the damn client to do it.
|
||||||
|
int size = 3;
|
||||||
|
for (i = 0; i < args; i++)
|
||||||
|
size += strlen(arg[i])+1;
|
||||||
|
ClientReliableWrite_Begin (cl, svcqex_locprint, size);
|
||||||
|
ClientReliableWrite_Short (cl, args);
|
||||||
|
for (i = 0; i < args; i++)
|
||||||
|
ClientReliableWrite_String (cl, arg[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TL_Reformat(cl->language, string, sizeof(string), args, arg);
|
||||||
|
SV_PrintToClient(cl, level, string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MVD_RECORDING
|
||||||
|
if (sv.mvdrecording && !(flags&BPRINT_IGNOREINDEMO))
|
||||||
|
{
|
||||||
|
sizebuf_t *msg;
|
||||||
|
TL_Reformat(com_language, string, sizeof(string), args, arg);
|
||||||
|
msg = MVDWrite_Begin (dem_all, 0, strlen(string)+3);
|
||||||
|
MSG_WriteByte (msg, svc_print);
|
||||||
|
MSG_WriteByte (msg, level);
|
||||||
|
MSG_WriteString (msg, string);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void VARGS SV_BroadcastPrintf (int level, const char *fmt, ...)
|
void VARGS SV_BroadcastPrintf (int level, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
|
@ -1640,6 +1703,9 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
|
||||||
{
|
{
|
||||||
SV_WriteEntityDataToMessage(split, msg, pnum);
|
SV_WriteEntityDataToMessage(split, msg, pnum);
|
||||||
|
|
||||||
|
if (split->prompt.active)
|
||||||
|
SV_Prompt_Resend(split);
|
||||||
|
|
||||||
if (split->centerprintstring && ! client->num_backbuf)
|
if (split->centerprintstring && ! client->num_backbuf)
|
||||||
{
|
{
|
||||||
SV_WriteCenterPrint(split, split->centerprintstring);
|
SV_WriteCenterPrint(split, split->centerprintstring);
|
||||||
|
|
|
@ -4068,6 +4068,35 @@ void SV_PushFloodProt(client_t *client)
|
||||||
client->lastspoke = realtime;
|
client->lastspoke = realtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef NQPROT
|
||||||
|
static void SV_SendQEXChat(client_t *to, int clcolour, int chatcolour, const char *sendername, const char *message)
|
||||||
|
{
|
||||||
|
if (to->controller)
|
||||||
|
to = to->controller;
|
||||||
|
|
||||||
|
switch (to->protocol)
|
||||||
|
{
|
||||||
|
case SCP_BAD: //bot
|
||||||
|
break;
|
||||||
|
case SCP_QUAKE2:
|
||||||
|
case SCP_QUAKE3:
|
||||||
|
case SCP_QUAKEWORLD:
|
||||||
|
break; //doesn't make sense.
|
||||||
|
case SCP_DARKPLACES6:
|
||||||
|
case SCP_DARKPLACES7:
|
||||||
|
case SCP_NETQUAKE:
|
||||||
|
case SCP_BJP3:
|
||||||
|
case SCP_FITZ666:
|
||||||
|
ClientReliableWrite_Begin (to, svcqex_chat, 3 + strlen(sendername)+strlen(message));
|
||||||
|
ClientReliableWrite_Byte (to, clcolour);
|
||||||
|
ClientReliableWrite_Byte (to, chatcolour);
|
||||||
|
ClientReliableWrite_String (to, sendername);
|
||||||
|
ClientReliableWrite_String (to, message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==================
|
==================
|
||||||
SV_Say
|
SV_Say
|
||||||
|
@ -4100,7 +4129,7 @@ void SV_Say (qboolean team)
|
||||||
|
|
||||||
memset(sent, 0, sizeof(sent));
|
memset(sent, 0, sizeof(sent));
|
||||||
|
|
||||||
if (team)
|
if (1)//team)
|
||||||
{
|
{
|
||||||
Q_strncpyz (t1, InfoBuf_ValueForKey(&host_client->userinfo, "team"), sizeof(t1));
|
Q_strncpyz (t1, InfoBuf_ValueForKey(&host_client->userinfo, "team"), sizeof(t1));
|
||||||
}
|
}
|
||||||
|
@ -4223,7 +4252,25 @@ void SV_Say (qboolean team)
|
||||||
else
|
else
|
||||||
sent[cln] = true;
|
sent[cln] = true;
|
||||||
|
|
||||||
SV_ClientPrintf(client, PRINT_CHAT, "%s", text);
|
#ifdef NQPROT
|
||||||
|
if (client->qex)
|
||||||
|
{ //white, green, cyan, yellow
|
||||||
|
int c = 0;
|
||||||
|
if (client == host_client)
|
||||||
|
c = 3; //yellow for yourself.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
t2 = InfoBuf_ValueForKey (&client->userinfo, "team");
|
||||||
|
if (strcmp(t1, t2))
|
||||||
|
c = 1; //green for other team. should probably be red but that's not an option.
|
||||||
|
else
|
||||||
|
c = 2; //cyan for same team.
|
||||||
|
}
|
||||||
|
SV_SendQEXChat(client, c, !!team, host_client->name, p);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
SV_ClientPrintf(client, PRINT_CHAT, "%s", text);
|
||||||
}
|
}
|
||||||
#ifdef MVD_RECORDING
|
#ifdef MVD_RECORDING
|
||||||
sv.mvdrecording = mvdrecording;
|
sv.mvdrecording = mvdrecording;
|
||||||
|
@ -8113,6 +8160,7 @@ static double SVFTE_ExecuteClientMove(client_t *controller)
|
||||||
ran=true;
|
ran=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SV_Prompt_Input(split, &split->lastcmd);
|
||||||
SV_RunCmd (&split->lastcmd, false);
|
SV_RunCmd (&split->lastcmd, false);
|
||||||
split->lastruncmd = split->lastcmd.servertime;
|
split->lastruncmd = split->lastcmd.servertime;
|
||||||
}
|
}
|
||||||
|
@ -8123,6 +8171,7 @@ static double SVFTE_ExecuteClientMove(client_t *controller)
|
||||||
if (split->lastcmd.impulse)
|
if (split->lastcmd.impulse)
|
||||||
split->edict->v->impulse = split->lastcmd.impulse;
|
split->edict->v->impulse = split->lastcmd.impulse;
|
||||||
|
|
||||||
|
SV_Prompt_Input(split, &split->lastcmd);
|
||||||
SV_SetEntityButtons(split->edict, split->lastcmd.buttons);
|
SV_SetEntityButtons(split->edict, split->lastcmd.buttons);
|
||||||
split->lastcmd.buttons = 0;
|
split->lastcmd.buttons = 0;
|
||||||
}
|
}
|
||||||
|
@ -8376,6 +8425,7 @@ void SV_ExecuteClientMessage (client_t *cl)
|
||||||
if (newcmd.impulse)// && SV_FilterImpulse(newcmd.impulse, host_client->trustlevel))
|
if (newcmd.impulse)// && SV_FilterImpulse(newcmd.impulse, host_client->trustlevel))
|
||||||
split->edict->v->impulse = newcmd.impulse;
|
split->edict->v->impulse = newcmd.impulse;
|
||||||
|
|
||||||
|
SV_Prompt_Input(split, &newcmd);
|
||||||
SV_SetEntityButtons(split->edict, newcmd.buttons);
|
SV_SetEntityButtons(split->edict, newcmd.buttons);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -8388,18 +8438,26 @@ void SV_ExecuteClientMessage (client_t *cl)
|
||||||
{
|
{
|
||||||
while (net_drop > 2)
|
while (net_drop > 2)
|
||||||
{
|
{
|
||||||
|
SV_Prompt_Input(split, &split->lastcmd);
|
||||||
SV_RunCmd (&split->lastcmd, false);
|
SV_RunCmd (&split->lastcmd, false);
|
||||||
net_drop--;
|
net_drop--;
|
||||||
}
|
}
|
||||||
if (net_drop > 1)
|
if (net_drop > 1)
|
||||||
|
{
|
||||||
|
SV_Prompt_Input(split, &oldest);
|
||||||
SV_RunCmd (&oldest, false);
|
SV_RunCmd (&oldest, false);
|
||||||
|
}
|
||||||
if (net_drop > 0)
|
if (net_drop > 0)
|
||||||
|
{
|
||||||
|
SV_Prompt_Input(split, &oldcmd);
|
||||||
SV_RunCmd (&oldcmd, false);
|
SV_RunCmd (&oldcmd, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
SV_Prompt_Input(split, &newcmd);
|
||||||
SV_RunCmd (&newcmd, false);
|
SV_RunCmd (&newcmd, false);
|
||||||
host_client->lastruncmd = sv.time*1000;
|
split->lastruncmd = sv.time*1000;
|
||||||
|
|
||||||
if (!SV_PlayerPhysicsQC || host_client->spectator)
|
if (!SV_PlayerPhysicsQC || split->spectator)
|
||||||
SV_PostRunCmd();
|
SV_PostRunCmd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8741,7 +8799,7 @@ void SVNQ_ReadClientMove (qboolean forceangle16, qboolean quakeex)
|
||||||
frame = &host_client->frameunion.frames[host_client->netchan.incoming_acknowledged & UPDATE_MASK];
|
frame = &host_client->frameunion.frames[host_client->netchan.incoming_acknowledged & UPDATE_MASK];
|
||||||
|
|
||||||
if (quakeex)
|
if (quakeex)
|
||||||
;
|
; //sequence is a separate clc (should have already been sent)
|
||||||
else if (host_client->protocol == SCP_DARKPLACES7)
|
else if (host_client->protocol == SCP_DARKPLACES7)
|
||||||
host_client->last_sequence = MSG_ReadLong ();
|
host_client->last_sequence = MSG_ReadLong ();
|
||||||
else if (host_client->fteprotocolextensions2 & PEXT2_PREDINFO)
|
else if (host_client->fteprotocolextensions2 & PEXT2_PREDINFO)
|
||||||
|
@ -8888,6 +8946,8 @@ void SVNQ_ReadClientMove (qboolean forceangle16, qboolean quakeex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SV_Prompt_Input(host_client, &cmd);
|
||||||
|
|
||||||
/*host_client->edict->v->v_angle[0] = SHORT2ANGLE(cmd.angles[0]);
|
/*host_client->edict->v->v_angle[0] = SHORT2ANGLE(cmd.angles[0]);
|
||||||
host_client->edict->v->v_angle[1] = SHORT2ANGLE(cmd.angles[1]);
|
host_client->edict->v->v_angle[1] = SHORT2ANGLE(cmd.angles[1]);
|
||||||
host_client->edict->v->v_angle[2] = SHORT2ANGLE(cmd.angles[2]);*/
|
host_client->edict->v->v_angle[2] = SHORT2ANGLE(cmd.angles[2]);*/
|
||||||
|
|
Loading…
Reference in a new issue