From c2d3d3a41bc60441945fe75685d4366f3435f521 Mon Sep 17 00:00:00 2001 From: Spoike Date: Mon, 23 Aug 2021 06:37:21 +0000 Subject: [PATCH] Fix up translations stuff with the rereleased version of quake. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@6038 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/cl_parse.c | 5 +- engine/client/cl_screen.c | 7 +- engine/client/m_items.c | 8 +- engine/client/pr_csqc.c | 4 +- engine/client/quakedef.h | 1 + engine/client/r_2d.c | 2 + engine/client/screen.h | 1 + engine/common/common.c | 2 + engine/common/common.h | 1 + engine/common/fs.c | 19 ++++- engine/common/pr_bgcmd.c | 5 +- engine/common/pr_common.h | 1 + engine/common/translate.c | 150 +++++++++++++++++++++++++++++++++++++ engine/gl/gl_font.c | 88 ++++++++++++++++++++++ engine/gl/gl_vidlinuxglx.c | 17 ++++- engine/server/pr_cmds.c | 123 +++++++++++++++++++++++++----- engine/server/sv_main.c | 7 +- engine/server/sv_phys.c | 23 +++--- 18 files changed, 424 insertions(+), 40 deletions(-) diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index cc76db8f1..537e02b59 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -6348,7 +6348,10 @@ static void CL_PrintStandardMessage(char *msgtext, int printlevel) // print final chunk Q_strncatz(fullmessage, msgtext, sizeof(fullmessage)); - Con_Printf("%s", fullmessage); + if (scr_usekfont.ival) + Con_PrintFlags(fullmessage, PFS_FORCEUTF8, 0); + else + Con_Printf("%s", fullmessage); } static char printtext[4096]; diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 4356da76d..75be43959 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -403,8 +403,13 @@ for a few moments */ void SCR_CenterPrint (int pnum, const char *str, qboolean skipgamecode) { + unsigned int pfl = 0; size_t i; cprint_t *p; +#ifdef HAVE_LEGACY + if (scr_usekfont.ival) + pfl |= PFS_FORCEUTF8; +#endif if (!str) { if (cl.intermissionmode == IM_NONE) @@ -545,7 +550,7 @@ void SCR_CenterPrint (int pnum, const char *str, qboolean skipgamecode) for (;;) { - p->charcount = COM_ParseFunString(CON_WHITEMASK, str, p->string, p->stringbytes, false) - p->string; + p->charcount = COM_ParseFunString(CON_WHITEMASK, str, p->string, p->stringbytes, pfl) - p->string; if ((p->charcount+1)*sizeof(*p->string) < p->stringbytes) break; diff --git a/engine/client/m_items.c b/engine/client/m_items.c index eea9204f2..487a6a8da 100644 --- a/engine/client/m_items.c +++ b/engine/client/m_items.c @@ -216,7 +216,8 @@ mpic_t *QBigFontWorks(void) if (p && R_GetShaderSizes(p, NULL, NULL, true)) return p; } - return NULL; + + return (mpic_t*)font_menu; } void Draw_BigFontString(int x, int y, const char *text) { @@ -228,6 +229,11 @@ void Draw_BigFontString(int x, int y, const char *text) Draw_AltFunString(x, y + (20-8)/2, text); return; } + if (p == (mpic_t*)font_menu) + { + Draw_FunStringWidthFont(font_menu, x, y, text, vid.width-x, false, false); + return; + } { //a hack for scaling p->width = 20*8; diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index e7d973f1b..3471d337a 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -4691,7 +4691,7 @@ static void QCBUILTIN PF_checkextension (pubprogfuncs_t *prinst, struct globalva { if (QSG_Extensions[i].extensioncheck) { - extcheck_t ctx = {cls.fteprotocolextensions, cls.fteprotocolextensions2}; + extcheck_t ctx = {prinst->parms->user, cls.fteprotocolextensions, cls.fteprotocolextensions2}; G_FLOAT(OFS_RETURN) = QSG_Extensions[i].extensioncheck(&ctx); } else @@ -8552,7 +8552,7 @@ void PR_CSExtensionList_f(void) int j; const char *extname; - extcheck_t extcheck = {cls.fteprotocolextensions, cls.fteprotocolextensions2}; + extcheck_t extcheck = {&csqc_world, cls.fteprotocolextensions, cls.fteprotocolextensions2}; #define SHOW_ACTIVEEXT 1 diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h index 6ecd916a6..b16f3eae1 100644 --- a/engine/client/quakedef.h +++ b/engine/client/quakedef.h @@ -326,6 +326,7 @@ extern cvar_t com_protocolversion; extern cvar_t com_nogamedirnativecode; extern cvar_t com_parseutf8; #ifdef HAVE_LEGACY +extern cvar_t scr_usekfont; extern cvar_t ezcompat_markup; #endif extern cvar_t sys_ticrate; diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index 8ca290678..4292bb3e2 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -1231,6 +1231,8 @@ void R2D_Font_Changed(void) #endif } + font_menu = Font_LoadFont("qfont?fmt=r", 20, 1, r_font_postprocess_outline.ival); + font_default = Font_LoadFont(gl_font.string, 8, 1, r_font_postprocess_outline.ival); if (!font_default && *gl_font.string) font_default = Font_LoadFont("", 8, 1, r_font_postprocess_outline.ival); diff --git a/engine/client/screen.h b/engine/client/screen.h index 89ee9cf47..d0a3094a4 100644 --- a/engine/client/screen.h +++ b/engine/client/screen.h @@ -351,6 +351,7 @@ int Font_LineWidth(conchar_t *start, conchar_t *end); float Font_LineScaleWidth(conchar_t *start, conchar_t *end); void Font_LineDraw(int x, int y, conchar_t *start, conchar_t *end); conchar_t *Font_CharAt(int x, conchar_t *start, conchar_t *end); +extern struct font_s *font_menu; extern struct font_s *font_default; extern struct font_s *font_console; extern struct font_s *font_tiny; diff --git a/engine/common/common.c b/engine/common/common.c index 3f80507a1..d82fc8840 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -92,6 +92,7 @@ cvar_t host_mapname = CVARAFD("mapname", "", "host_mapname", 0, "Cvar that hol #ifdef HAVE_LEGACY cvar_t ezcompat_markup = CVARD("ezcompat_markup", "1", "Attempt compatibility with ezquake's text markup.0: disabled.\n1: Handle markup ampersand markup.\n2: Handle chevron markup (only in echo commands, for config compat, because its just too unreliable otherwise)."); cvar_t pm_noround = CVARD("pm_noround", "0", "Disables player prediction snapping, in a way that cannot be reliably predicted but may be needed to avoid map bugs."); +cvar_t scr_usekfont = CVARD("scr_usekfont"/*kex*/, "0", "Exists for compat with the quake rerelease, changing the behaviour of QC's sprint/bprint/centerprint builtins."); #endif qboolean com_modified; // set true if using non-id files @@ -6358,6 +6359,7 @@ void COM_Init (void) Cvar_Register (&com_nogamedirnativecode, "Gamecode"); Cvar_Register (&com_parseutf8, "Internationalisation"); #ifdef HAVE_LEGACY + Cvar_Register (&scr_usekfont, NULL); Cvar_Register (&ezcompat_markup, NULL); Cvar_Register (&pm_noround, NULL); #endif diff --git a/engine/common/common.h b/engine/common/common.h index f42edcd3c..2e8008442 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -975,6 +975,7 @@ struct po_s *PO_Create(void); void PO_Merge(struct po_s *po, vfsfile_t *file); const char *PO_GetText(struct po_s *po, const char *msg); void PO_Close(struct po_s *po); +void TL_Reformat(char *out, size_t outsize, size_t numargs, const char **arg); // // log.c diff --git a/engine/common/fs.c b/engine/common/fs.c index 121f8794f..55dc0028b 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -3820,7 +3820,9 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths) /*quake requires a few settings for compatibility*/ #define QRPCOMPAT "set cl_cursor_scale 0.2\nset cl_cursor_bias_x 7.5\nset cl_cursor_bias_y 0.8\n" #define QUAKESPASMSUCKS "set mod_h2holey_bugged 1\n" -#define QCFG "//schemes quake qw\n" "set v_gammainverted 1\nset con_stayhidden 0\nset com_parseutf8 0\nset allow_download_pakcontents 1\nset allow_download_refpackages 0\nset r_meshpitch -1\nr_sprite_backfacing 1\nset sv_bigcoords \"\"\nmap_autoopenportals 1\n" "sv_port "STRINGIFY(PORT_QWSERVER)" "STRINGIFY(PORT_NQSERVER)"\n" ZFIXHACK EZQUAKECOMPETITIVE QRPCOMPAT QUAKESPASMSUCKS +#define QUAKEOVERRIDES "set v_gammainverted 1\nset con_stayhidden 0\nset allow_download_pakcontents 1\nset allow_download_refpackages 0\nset r_meshpitch -1\nr_sprite_backfacing 1\nset sv_bigcoords \"\"\nmap_autoopenportals 1\n" "sv_port "STRINGIFY(PORT_QWSERVER)" "STRINGIFY(PORT_NQSERVER)"\n" ZFIXHACK EZQUAKECOMPETITIVE QUAKESPASMSUCKS +#define QCFG "//schemes quake qw\n" QUAKEOVERRIDES "set com_parseutf8 0\n" QRPCOMPAT +#define KEXCFG "//schemes quake_r2\n" QUAKEOVERRIDES "set com_parseutf8 1\nset campaign 0\n" /*NetQuake reconfiguration, to make certain people feel more at home...*/ #define NQCFG "//disablehomedir 1\n//mainconfig ftenq\n" QCFG "cfg_save_auto 1\nset sv_nqplayerphysics 1\nset cl_loopbackprotocol auto\ncl_sbar 1\nset plug_sbar 0\nset sv_port "STRINGIFY(PORT_NQSERVER)"\ncl_defaultport "STRINGIFY(PORT_NQSERVER)"\nset m_preset_chosen 1\nset vid_wait 1\nset cl_demoreel 1\n" #define SPASMCFG NQCFG "fps_preset builtin_spasm\nset cl_demoreel 0\ncl_sbar 2\nset gl_load24bit 1\n" @@ -3895,6 +3897,8 @@ static const gamemode_info_t gamemode_info[] = { //for quake, we also allow extracting all files from paks. some people think it loads faster that way or something. #ifdef HAVE_LEGACY //cmdline switch exename protocol name(dpmaster) identifying file exec dir1 dir2 dir3 dir(fte) full name + //use rerelease behaviours if we seem to be running from that dir. + {"-quake_rerel",NULL, "FTE-QuakeRerelease", {"QuakeEX.kpf"}, KEXCFG, {"id1", "*fte"}, "RerelQuake", UPDATEURL(Q1)}, //standard quake {"-quake", "q1", QUAKEPROT, {"id1/pak0.pak","id1/quake.rc"},QCFG, {"id1", "qw", "*fte"}, "Quake", UPDATEURL(Q1)}, //alternative name, because fmf file install names are messy when a single name is used for registry install path. @@ -4468,6 +4472,19 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags) com_base_searchpaths = NULL; gameonly_gamedir = gameonly_homedir = NULL; +#if defined(HAVE_LEGACY) && defined(PACKAGE_PK3) + { + searchpathfuncs_t *pak; + vfsfile_t *vfs; + char pakname[MAX_OSPATH]; + Q_snprintfz(pakname, sizeof(pakname), "%sQuakeEX.kpf", com_gamepath); + vfs = VFSOS_Open(pakname, "rb"); + pak = FSZIP_LoadArchive(vfs, NULL, pakname, pakname, ""); + if (pak) //logically should have SPF_EXPLICIT set, but that would give it a worse gamedir depth + FS_AddPathHandle(&oldpaths, "", pakname, pak, "", SPF_COPYPROTECTED, reloadflags); + } +#endif + i = COM_CheckParm ("-basepack"); while (i && i < com_argc-1) { diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index a2423ec5c..37d40dda2 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -7590,6 +7590,9 @@ static qboolean check_pext2_infoblobs (extcheck_t *extcheck) {return !!(extchec //static qboolean check_pext2_stunaware (extcheck_t *extcheck) {return !!(extcheck->pext2 & PEXT2_STUNAWARE);} static qboolean check_pext2_vrinputs (extcheck_t *extcheck) {return !!(extcheck->pext2 & PEXT2_VRINPUTS);} +//rerelease stomped on things. make sure our earlier extension reports correctly. +static qboolean check_bouncemissile (extcheck_t *extcheck) {return !extcheck->world->remasterlogic/*became 'movetype_gib'*/;} + #define NOBI NULL, 0,{NULL}, qc_extension_t QSG_Extensions[] = { //these don't have well-defined names... @@ -7635,7 +7638,7 @@ qc_extension_t QSG_Extensions[] = { {"DP_LIGHTSTYLE_STATICVALUE"}, {"DP_LITSUPPORT"}, {"DP_MONSTERWALK", NULL, 0,{NULL}, "MOVETYPE_WALK is valid on non-player entities. Note that only players receive acceleration etc in line with none/bounce/fly/noclip movetypes on the player, thus you will have to provide your own accelerations (incluing gravity) yourself."}, - {"DP_MOVETYPEBOUNCEMISSILE"}, //I added the code for hexen2 support. + {"DP_MOVETYPEBOUNCEMISSILE", check_bouncemissile}, //I added the code for hexen2 support. {"DP_MOVETYPEFOLLOW"}, {"DP_QC_ASINACOSATANATAN2TAN", NULL, 5,{"asin", "acos", "atan", "atan2", "tan"}}, {"DP_QC_CHANGEPITCH", NULL, 1,{"changepitch"}}, diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index 0dc9022c9..d5c33a946 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -46,6 +46,7 @@ struct wedict_s //thus this system requires various builtins to exist at specific numbers. //this competes against checkbuiltin(funcreference). typedef struct { + world_t *world; unsigned int pext1, pext2; } extcheck_t; typedef struct qc_extension_s { diff --git a/engine/common/translate.c b/engine/common/translate.c index 8a4a06ab2..7ee44d12a 100644 --- a/engine/common/translate.c +++ b/engine/common/translate.c @@ -15,9 +15,15 @@ int com_language; char sys_language[64] = ""; static char langpath[MAX_OSPATH] = ""; struct language_s languages[MAX_LANGUAGES]; +static struct po_s *com_translations; 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); } @@ -495,3 +501,147 @@ const char *PO_GetText(struct po_s *po, const char *msg) return line->translated; return msg; } + + +static void PO_Merge_Rerelease(struct po_s *po, const char *fmt) +{ + //FOO = "CString" + char line[32768]; + char key[256]; + char val[32768]; + char *s; + vfsfile_t *file = NULL; + + if (!file && *language.string) //use system locale names + file = FS_OpenVFS(va(fmt, language.string), "rb", FS_GAME); + if (!file) //make a guess + { + s = NULL; + if (language.string[0] && language.string[1] && (!language.string[2] || language.string[2] == '-' || language.string[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). + if (!strncmp(language.string, "fr", 2)) + s = "french"; + else if (!strncmp(language.string, "de", 2)) + s = "german"; + else if (!strncmp(language.string, "it", 2)) + s = "italian"; + else if (!strncmp(language.string, "ru", 2)) + s = "russian"; + else if (!strncmp(language.string, "es", 2)) + s = "spanish"; + } + if (s) + file = FS_OpenVFS(va(fmt, s), "rb", FS_GAME); + } + if (!file) //fall back on misnamed american, for lack of a better default. + file = FS_OpenVFS(va(fmt, "english"), "rb", FS_GAME); + if (file) + { + *key = '$'; + while(VFS_GETS(file, line, sizeof(line))) + { + s = COM_ParseOut(line, key+1, sizeof(key)-1); + s = COM_ParseOut(s, val, sizeof(val)); + if (strcmp(val,"=")) + continue; + s = COM_ParseCString(s, val, sizeof(val), NULL); + if (!s) + continue; + PO_AddText(po, key, val); + } + VFS_CLOSE(file); + } +} + +void TL_Reformat(char *out, size_t outsize, size_t numargs, const char **arg) +{ + const char *fmt; + const char *a; + size_t alen; + + for (alen = 0; alen < numargs; alen++) + { + if (*arg[alen] == '$') + { + if (!com_translations) + { + char lang[64], *h; + vfsfile_t *f = NULL; + com_translations = PO_Create(); + PO_Merge_Rerelease(com_translations, "localization/loc_%s.txt"); + + Q_strncpyz(lang, language.string, sizeof(lang)); + while ((h = strchr(lang, '-'))) + *h = '_'; //standardise it + if (*lang) + f = FS_OpenVFS(va("localisation/%s.po", lang), "rb", FS_GAME); //long/specific form + if (!f) + { + if ((h = strchr(lang, '_'))) + { + *h = 0; + if (*lang) + f = FS_OpenVFS(va("localisation/%s.po", lang), "rb", FS_GAME); //short/general form + } + } + if (f) + PO_Merge(com_translations, f); + } + arg[alen] = PO_GetText(com_translations, arg[alen]); + } + } + + fmt = (numargs>0&&arg[0])?arg[0]:""; + + outsize--; + while (outsize > 0) + { + if (!*fmt) + break; + else if (*fmt == '{') + { + unsigned int index = strtoul(fmt+1, (char**)&fmt, 10)+1; + int size = 0; + if (*fmt == ',') + size = strtol(fmt+1, (char**)&fmt, 10); + if (*fmt == ':') + { //formatting, which we don't support because its all strings. + fmt = fmt+1; + while (*fmt && *fmt != '}') + fmt++; + } + if (*fmt == '}') + fmt++; + else + break; //some formatting error + + if (index >= numargs || !arg[index]) + a = ""; + else + a = arg[index]; + + alen = strlen(a); + if (alen > outsize) + alen = outsize; + if (size > 0) + { //right aligned + if (alen > size) + alen = size; + memcpy(out, a, alen); + } + else if (size < 0) + { //left aligned + if (alen > -size) + alen = -size; + memcpy(out, a, alen); + } + else //no alignment, no padding. + memcpy(out, a, alen); + out += alen; + outsize -= alen; + } + else + *out++ = *fmt++, outsize--; + } + *out = 0; +} diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 3e04c9afd..ff378fb8a 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -34,6 +34,7 @@ float Font_DrawScaleChar(float px, float py, unsigned int charflags, unsigned in void Font_EndString(struct font_s *font); int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int maxlines, conchar_t **starts, conchar_t **ends); +struct font_s *font_menu; struct font_s *font_default; struct font_s *font_console; struct font_s *font_tiny; @@ -228,6 +229,7 @@ enum fontfmt_e FMT_WINDOWS1252,//variation of latin-1 with extra glyphs FMT_KOI8U, //image is 16*16 koi8-u codepage. FMT_HORIZONTAL, //unicode, charcount=width/(height-2). single strip of chars, like halflife. + FMT_RERELEASE, //fonts/foo.kfont specifies a texture and a series of glyph positions within it. }; typedef struct fontface_s @@ -1023,6 +1025,7 @@ static struct charcache_s *Font_TryLoadGlyphRaster(font_t *f, fontface_t *qface, { safedefault: case FMT_AUTO: //shouldn't happen. + case FMT_RERELEASE: //shouldn't happen. case FMT_ISO88591: //all identity. case FMT_HORIZONTAL: //erk... c1tab = NULL; @@ -1610,6 +1613,85 @@ qboolean Font_LoadHorizontalFont(struct font_s *f, int fheight, const char *font return false; } +qboolean Font_LoadKexFont(struct font_s *f, int fheight, const char *fontfilename) +{ + vfsfile_t *kfont = FS_OpenVFS(va("fonts/%s.kfont", fontfilename), "rb", FS_GAME); + char line[256]; + char val[256], *s; + struct charcache_s *c; + fontface_t *qface; + if (!kfont) + return false; + while(VFS_GETS(kfont, line, sizeof(line))) + { + s = COM_ParseOut(line, val, sizeof(val)); + if (!s) + continue; + if (!strcmp(val, "texture") && (s=COM_ParseOut(s, val, sizeof(val)))) + { + TEXDOWAIT(f->singletexture); + if (!TEXLOADED(f->singletexture)) + f->singletexture = Image_GetTexture(val, NULL, IF_NOWORKER|IF_EXACTEXTENSION|IF_UIPIC|(r_font_linear.ival?IF_LINEAR:IF_NEAREST|IF_NOPURGE)|IF_NOPICMIP|IF_NOMIPMAP|IF_NOGAMMA|IF_NOPURGE, NULL, NULL, 0, 0, PTI_INVALID); + } + else if (*val >= '0' && *val <='9') + { + unsigned int codepoint = atoi(val); + unsigned int x, y, w, h;//, u; + if (!TEXLOADED(f->singletexture)) + break; + + s=COM_ParseOut(s, val, sizeof(val)); + x = atoi(val); + s=COM_ParseOut(s, val, sizeof(val)); + y = atoi(val); + s=COM_ParseOut(s, val, sizeof(val)); + w = atoi(val); + s=COM_ParseOut(s, val, sizeof(val)); + h = atoi(val); + s=COM_ParseOut(s, val, sizeof(val)); + //u = atoi(val); + if (!s) + continue; //something truncated. + if (codepoint >= FONT_MAXCHARS || h<=0) + continue; //out of range. + c = Font_GetCharStore(f, codepoint); + if (codepoint != ' ') + { + y+=2; + h-=4; + } + c->advance = max(1,(f->charheight * w)/h); + + c->bmw = (w * PLANEWIDTH) / f->singletexture->width; + c->bmh = (h * PLANEHEIGHT) / f->singletexture->height; + c->bmx = (x * PLANEWIDTH) / f->singletexture->width; + c->bmy = (y * PLANEHEIGHT) / f->singletexture->height; + c->left = 0; + c->nextchar = 0; //these chars are not linked in + c->texplane = BITMAPPLANE; + } + } + + + VFS_CLOSE(kfont); + if (!TEXLOADED(f->singletexture)) + return false; + + /*success!*/ + qface = Z_Malloc(sizeof(*qface)); + qface->flink = &faces; + qface->fnext = *qface->flink; + *qface->flink = qface; + if (qface->fnext) + qface->fnext->flink = &qface->fnext; + qface->refs++; + Q_snprintfz(qface->name, sizeof(qface->name), "fonts/%s.kfont", fontfilename); + + f->face[f->faces++] = qface; + + return true; +} + #ifdef AVAIL_FREETYPE extern cvar_t dpcompat_smallerfonts; int Font_ChangeFTSize(fontface_t *qface, int pixelheight) @@ -2196,6 +2278,8 @@ struct font_s *Font_LoadFont(const char *fontfilename, float vheight, float scal fmt = FMT_KOI8U; else if (*t == 'h') fmt = FMT_HORIZONTAL; + else if (*t == 'r') + fmt = FMT_RERELEASE; } if (!strncmp(parms, "aspect=", 7)) { @@ -2388,6 +2472,8 @@ struct font_s *Font_LoadFont(const char *fontfilename, float vheight, float scal if (end) *end = 0; + if (fmt == FMT_RERELEASE) + success = Font_LoadKexFont(f, height, start); if (fmt == FMT_HORIZONTAL) success = Font_LoadHorizontalFont(f, height, start); #ifdef AVAIL_FREETYPE @@ -2673,6 +2759,8 @@ float Font_CharScaleHeight(void) int Font_TabWidth(int x) { int tabwidth = Font_CharWidth(CON_WHITEMASK, ' '); + if (!tabwidth) + tabwidth = curfont->charheight; tabwidth *= 8; x++; diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c index 550cb83c6..5e8fd7e6b 100644 --- a/engine/gl/gl_vidlinuxglx.c +++ b/engine/gl/gl_vidlinuxglx.c @@ -3558,10 +3558,19 @@ static void *X11VID_CreateCursor(const qbyte *imagedata, int width, int height, { int nw,nh; qbyte *nd; - nw = width * scale; - nh = height * scale; - if (nw <= 0 || nh <= 0 || nw > 128 || nh > 128) //don't go crazy. - return NULL; + for(;;) + { + nw = width * scale; + nh = height * scale; + if (nw <= 0 || nh <= 0 || nw > 128 || nh > 128) //don't go crazy. + return NULL; + if (nw < 8) + scale = 8/width; + else if (nh < 8) + scale = 8/height; + else + break; + } nd = Image_ResampleTexture(format, imagedata, width, height, NULL, nw, nh); if (!nd) return NULL; //resampling of that format didn't work for some reason... diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 4ab379902..9010d924e 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -2313,16 +2313,6 @@ void Q_InitProgs(enum initprogs_e flags) #endif World_RBE_Start(&sv.world); - - if (sv.world.remasterlogic) - { - PR_EnableEBFSBuiltin("bprints", 23); - PR_EnableEBFSBuiltin("sprints", 24); - PR_EnableEBFSBuiltin("centerprints", 73); - PR_EnableEBFSBuiltin("finaleFinished", 79); - PR_EnableEBFSBuiltin("localsound_remaster", 80); - Con_Printf(CON_WARNING "Remastered quakec detected (this is not fool-proof), compat workarounds have been enabled\n"); - } } qboolean PR_QCChat(char *text, int say_type) @@ -7237,13 +7227,13 @@ static void QCBUILTIN PF_checkextension (pubprogfuncs_t *prinst, struct globalva if (ext->extensioncheck && clnum >= 1 && clnum <= sv.allocated_client_slots) { client_t *cl = &svs.clients[clnum-1]; - extcheck_t check = {cl->fteprotocolextensions, cl->fteprotocolextensions2}; + extcheck_t check = {prinst->parms->user, cl->fteprotocolextensions, cl->fteprotocolextensions2}; if (!ext->extensioncheck(&check)) return; //blocked by some setting somewhere, somehow. } else if (ext->extensioncheck) { - extcheck_t check = {Net_PextMask(PROTOCOL_VERSION_FTE1, false), Net_PextMask(PROTOCOL_VERSION_FTE2, false)}; + extcheck_t check = {prinst->parms->user, Net_PextMask(PROTOCOL_VERSION_FTE1, false), Net_PextMask(PROTOCOL_VERSION_FTE2, false)}; if (!ext->extensioncheck(&check)) return; //blocked by some setting somewhere, somehow. } @@ -10732,15 +10722,100 @@ void PF_localsound_remaster(pubprogfuncs_t *prinst, struct globalvars_s *pr_glob } void PF_centerprints(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { //TODO: send the strings to the client for localisation+reordering - PF_centerprint(prinst, pr_globals); + const char *arg[8]; + int args; + char s[1024]; + int entnum; + + entnum = G_EDICTNUM(prinst, OFS_PARM0); + for (args = 0; args+1 < prinst->callargc; args++) + arg[args] = PR_GetStringOfs(prinst, OFS_PARM1+args*(OFS_PARM1-OFS_PARM0)); + TL_Reformat(s, sizeof(s), args, arg); + + PF_centerprint_Internal(entnum, false, s); } void PF_sprints(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) -{ //TODO: send the strings to the client for localisation+reordering. - PF_sprint(prinst, pr_globals); +{ + const char *arg[8]; + int args; + char s[1024]; + client_t *client; + int entnum; + int level; + +#ifdef SERVER_DEMO_PLAYBACK + if (sv.demofile) + return; +#endif + + entnum = G_EDICTNUM(prinst, OFS_PARM0); + + if (progstype == PROG_NQ || progstype == PROG_H2) + { + level = PRINT_HIGH; + for (args = 0; args+1 < prinst->callargc; args++) + arg[args] = PR_GetStringOfs(prinst, OFS_PARM1+args*(OFS_PARM1-OFS_PARM0)); + } + else + { + level = G_FLOAT(OFS_PARM1); + for (args = 0; args+2 < prinst->callargc; args++) + 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) + { + Con_TPrintf ("tried to sprint to a non-client\n"); + return; + } + + client = &svs.clients[entnum-1]; + + SV_ClientPrintf (client, level, "%s", s); + + if (sv_specprint.ival & SPECPRINT_SPRINT) + { + client_t *spec; + unsigned int i; + for (i = 0, spec = svs.clients; i < sv.allocated_client_slots; i++, spec++) + { + if (spec->state != cs_spawned || !spec->spectator) + continue; + if (spec->spec_track == entnum && (spec->spec_print & SPECPRINT_SPRINT)) + { + if (level < spec->messagelevel) + continue; + if (spec->controller) + SV_PrintToClient(spec->controller, level, s); + else + SV_PrintToClient(spec, level, s); + } + } + } } void PF_bprints(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { //TODO: send the strings to the client for localisation+reordering - PF_bprint(prinst, pr_globals); + const char *arg[8]; + int args; + char formatted[1024]; + int level; + + if (progstype == PROG_QW) + { + level = G_FLOAT(OFS_PARM0); + for (args = 0; args+1 < prinst->callargc; args++) + arg[args] = PR_GetStringOfs(prinst, OFS_PARM1+args*(OFS_PARM1-OFS_PARM0)); + } + else + { + level = PRINT_HIGH; + for (args = 0; args < prinst->callargc; args++) + arg[args] = PR_GetStringOfs(prinst, OFS_PARM0+args*(OFS_PARM1-OFS_PARM0)); + } + + TL_Reformat(formatted, sizeof(formatted), args, arg); + SV_BroadcastPrintf (level, "%s", formatted); } #define STUB ,NULL,true @@ -12113,6 +12188,20 @@ void PR_ResetBuiltins(progstype_t type) //fix all nulls to PF_FIXME and add any Con_Printf("Be aware that MVDSV does not follow standards. Please encourage mod developers to not require pr_imitatemvdsv to be set.\n"); } } + +#ifdef HAVE_LEGACY + //when this cvar is set, we're assumed to be running a rerelease-compatible mod. + //obviously this might still break mods that don't include their own quake.rc (most of them), but hey... compat, right? + if (scr_usekfont.ival) + { + PR_EnableEBFSBuiltin("bprints", 23); + PR_EnableEBFSBuiltin("sprints", 24); + PR_EnableEBFSBuiltin("centerprints", 73); + + PR_EnableEBFSBuiltin("finaleFinished", 79); + PR_EnableEBFSBuiltin("localsound_remaster", 80); + } +#endif } void PR_SVExtensionList_f(void) @@ -12126,7 +12215,7 @@ void PR_SVExtensionList_f(void) int num; char biissues[8192]; - extcheck_t extcheck = {Net_PextMask(PROTOCOL_VERSION_FTE1, false), Net_PextMask(PROTOCOL_VERSION_FTE2, false)}; + extcheck_t extcheck = {&sv.world, Net_PextMask(PROTOCOL_VERSION_FTE1, false), Net_PextMask(PROTOCOL_VERSION_FTE2, false)}; #define SHOW_ACTIVEEXT 1 #define SHOW_ACTIVEBI 2 diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 1eeafefa6..17d433743 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -5726,11 +5726,12 @@ void SV_InitLocal (void) } #define iswhite(c) ((c) == ' ' || (unsigned char)(c) == (unsigned char)INVIS_CHAR1 || (unsigned char)(c) == (unsigned char)INVIS_CHAR2 || (unsigned char)(c) == (unsigned char)INVIS_CHAR3) -#define isinvalid(c) ((c) == ':' || (c) == '\\' || (c) == '\r' || (c) == '\n' || (unsigned char)(c) == (unsigned char)0xff || (c) == '\"') -//colon is so clients can't get confused while parsing chats -//255 is so fuhquake/ezquake don't end up with nameless players +#define isinvalid(c) ((c) == ':' || (c) == '\\' || (c) == '$' || (c) == '\r' || (c) == '\n' || (unsigned char)(c) == (unsigned char)0xff || (c) == '\"') +//colon is so clients can't get confused while parsing chats (eg frag messages) +//255 is so fuhquake/ezquake don't end up with nameless players (and general MSG_ReadString bugs) //" is so mods that use player names in tokenizing/frik_files don't mess up. mods are still expected to be able to cope with space. //\ is blocked because it messes up our ^[NAME\player\NUM^] links, and because vanilla would hate it. +//$ is blocked because of potential internationalisation escapes. //is allowed to shorten, out must be as long as in and min of "unnamed"+1 void SV_FixupName(const char *in, char *out, unsigned int outlen) diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 3c41acbcd..629ab1296 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -1332,6 +1332,7 @@ static void WPhys_Physics_Toss (world_t *w, wedict_t *ent) int fl; const float *gravitydir; + int movetype; WPhys_CheckVelocity (w, ent); @@ -1364,11 +1365,12 @@ static void WPhys_Physics_Toss (world_t *w, wedict_t *ent) } // add gravity - if (ent->v->movetype != MOVETYPE_FLY - && ent->v->movetype != MOVETYPE_FLY_WORLDONLY - && ent->v->movetype != MOVETYPE_FLYMISSILE - && (ent->v->movetype != MOVETYPE_BOUNCEMISSILE || w->remasterlogic/*gib*/) - && ent->v->movetype != MOVETYPE_H2SWIM) + movetype = ent->v->movetype; + if (movetype != MOVETYPE_FLY + && movetype != MOVETYPE_FLY_WORLDONLY + && movetype != MOVETYPE_FLYMISSILE + && (movetype != MOVETYPE_BOUNCEMISSILE || w->remasterlogic/*gib*/) + && movetype != MOVETYPE_H2SWIM) WPhys_AddGravity (w, ent, gravitydir); // move angles @@ -1407,14 +1409,17 @@ static void WPhys_Physics_Toss (world_t *w, wedict_t *ent) VectorCopy(trace.endpos, move); - if (ent->v->movetype == MOVETYPE_BOUNCE) + movetype = ent->v->movetype; + if (movetype == MOVETYPE_BOUNCEMISSILE && w->remasterlogic) + movetype = MOVETYPE_BOUNCE; //'gib'... + if (movetype == MOVETYPE_BOUNCE) { if (ent->xv->bouncefactor) backoff = 1 + ent->xv->bouncefactor; else backoff = 1.5; } - else if (ent->v->movetype == MOVETYPE_BOUNCEMISSILE) + else if (movetype == MOVETYPE_BOUNCEMISSILE) { if (ent->xv->bouncefactor) backoff = 1 + ent->xv->bouncefactor; @@ -1431,7 +1436,7 @@ static void WPhys_Physics_Toss (world_t *w, wedict_t *ent) // stop if on ground - if ((-DotProduct(gravitydir, trace.plane.normal) > 0.7) && (ent->v->movetype != MOVETYPE_BOUNCEMISSILE)) + if ((-DotProduct(gravitydir, trace.plane.normal) > 0.7) && (movetype != MOVETYPE_BOUNCEMISSILE)) { float bouncespeed; float bouncestop = ent->xv->bouncestop; @@ -1443,7 +1448,7 @@ static void WPhys_Physics_Toss (world_t *w, wedict_t *ent) bouncespeed = DotProduct(trace.plane.normal, ent->v->velocity); else bouncespeed = -DotProduct(gravitydir, ent->v->velocity); - if (bouncespeed < bouncestop || ent->v->movetype != MOVETYPE_BOUNCE ) + if (bouncespeed < bouncestop || movetype != MOVETYPE_BOUNCE ) { ent->v->flags = (int)ent->v->flags | FL_ONGROUND; ent->v->groundentity = EDICT_TO_PROG(w->progs, trace.ent);