From 9000f497ecdb129b1a7702b1805c3c48bc26ed68 Mon Sep 17 00:00:00 2001 From: Spoike Date: Tue, 27 Oct 2015 15:20:15 +0000 Subject: [PATCH] misc fixes and tweaks: added //it stuffcmd. now parsing //wps stuffcmds for ezhud use. rework worker threads a little so that the main thread is no longer guaranteed to be stalled at least once. This speeds up load times a little. fix nq server player counts in the server browser. fix switching from/to spectator mode from destroying frag counts. tweak custom bf args a little. fix issue with player names starting with char 0x80. fix menu.dat not loading. attempt to fix flush lag on windows. some fixes for stencil shadows. try to fix public builds not knowing their svn revision. this should fix autoupdates. added global_gravitydir vector, for mods that want to be really weird. doesn't clear onground flags however. reworked the status command a little to attempt to report bursts a little better. fix multicasts missing in mvds issue. fix illegible server message with dpp7 downloads. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4992 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/Makefile | 2 +- engine/client/cl_ents.c | 56 +++-- engine/client/cl_input.c | 8 +- engine/client/cl_main.c | 6 +- engine/client/cl_parse.c | 79 ++++++- engine/client/cl_plugin.inc | 60 ++++++ engine/client/cl_pred.c | 17 +- engine/client/cl_screen.c | 2 + engine/client/client.h | 9 + engine/client/console.c | 17 +- engine/client/image.c | 3 + engine/client/m_options.c | 38 +++- engine/client/merged.h | 4 + engine/client/net_master.c | 2 +- engine/client/p_script.c | 2 +- engine/client/r_surf.c | 48 ++--- engine/client/renderer.c | 2 +- engine/client/sbar.c | 6 +- engine/client/snd_dma.c | 21 +- engine/client/view.c | 49 ++++- engine/common/cmd.c | 2 + engine/common/common.c | 59 +++++- engine/common/cvar.c | 28 +-- engine/common/fs.c | 9 +- engine/common/fs_win32.c | 5 +- engine/common/pr_bgcmd.c | 21 +- engine/common/world.h | 1 + engine/gl/gl_backend.c | 22 +- engine/gl/gl_font.c | 12 +- engine/gl/gl_model.c | 10 + engine/gl/gl_shadow.c | 21 +- engine/gl/gl_vidcommon.c | 21 +- engine/qclib/qcc_pr_lex.c | 6 + engine/qclib/qccgui.c | 1 + engine/server/pr_cmds.c | 63 ++++-- engine/server/pr_lua.c | 2 +- engine/server/pr_q1qvm.c | 11 + engine/server/progdefs.h | 1 + engine/server/server.h | 14 +- engine/server/sv_ccmds.c | 8 +- engine/server/sv_ents.c | 25 ++- engine/server/sv_main.c | 25 ++- engine/server/sv_mvd.c | 4 +- engine/server/sv_phys.c | 21 +- engine/server/sv_send.c | 38 +++- engine/server/sv_sys_win.c | 24 ++- engine/server/sv_user.c | 11 +- engine/server/world.c | 7 +- plugins/ezhud/ezhud.vcproj | 14 -- plugins/ezhud/ezquakeisms.c | 16 ++ plugins/ezhud/ezquakeisms.h | 3 +- plugins/ezhud/hud_common.c | 402 +++++++++++++++++++++++++++--------- plugins/plugin.c | 17 ++ plugins/plugin.h | 7 +- plugins/qvm_api.c | 41 ++-- specs/particles.txt | 24 ++- 56 files changed, 1088 insertions(+), 339 deletions(-) diff --git a/engine/Makefile b/engine/Makefile index 811806d9e..8f00eb22f 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -15,7 +15,7 @@ else BASE_DIR:=$(realpath .) endif -SVNREVISION:=-DSVNREVISION=$(shell test -d .svn && svnversion || echo -) +SVNREVISION:=-DSVNREVISION=$(shell test -d $(BASE_DIR)/../.svn && svnversion $(BASE_DIR) || echo -) WHOAMI:=$(shell whoami) diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 3cb23782b..41888fe30 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -1517,6 +1517,8 @@ void CLNQ_ParseEntity(unsigned int bits) entity_state_t *base; packet_entities_t *pack; + qboolean isnehahra = false;//(cls.protocol_nq == CPNQ_ID && cls.demoplayback); + if (cls.signon == 4 - 1) { // first update is the final signon stage cls.signon = 4; @@ -1530,15 +1532,19 @@ void CLNQ_ParseEntity(unsigned int bits) i = MSG_ReadByte (); bits |= (i<<8); } - if (bits & DPU_EXTEND1) + + if (!isnehahra) { - i = MSG_ReadByte (); - bits |= (i<<16); - } - if (bits & DPU_EXTEND2) - { - i = MSG_ReadByte (); - bits |= (i<<24); + if (bits & DPU_EXTEND1) + { + i = MSG_ReadByte (); + bits |= (i<<16); + } + if (bits & DPU_EXTEND2) + { + i = MSG_ReadByte (); + bits |= (i<<24); + } } if (bits & NQU_LONGENTITY) @@ -1603,7 +1609,21 @@ void CLNQ_ParseEntity(unsigned int bits) if (bits & NQU_ANGLE3) state->angles[2] = MSG_ReadAngle(); - if (cls.protocol_nq == CPNQ_FITZ666) + if (isnehahra) + { + if (bits & DPU_EXTEND1) //U_TRANS + { + float tmp = MSG_ReadFloat(); + float alpha = MSG_ReadFloat(); + if (tmp == 2) + { + if (MSG_ReadFloat() > 0.5) + state->effects |= EF_FULLBRIGHT; + } + state->trans = bound(0, 255 * alpha, 255); + } + } + else if (cls.protocol_nq == CPNQ_FITZ666) { if (bits & FITZU_ALPHA) state->trans = MSG_ReadByte(); @@ -1711,7 +1731,8 @@ void CL_RotateAroundTag(entity_t *ent, int entnum, int parenttagent, int parentt if ((ps->dpflags & RENDER_EXTERIORMODEL) || r_refdef.playerview->viewentity == ps->number) ent->flags |= RF_EXTERNALMODEL; - if (ent->playerindex == -1 && ps->colormap > 0 && ps->colormap <= cl.allocated_client_slots) + //hack for xonotic. + if ((ent->flags & RF_WEAPONMODEL) && ent->playerindex == -1 && ps->colormap > 0 && ps->colormap <= cl.allocated_client_slots) { ent->playerindex = ps->colormap-1; ent->topcolour = cl.players[ent->playerindex].ttopcolor; @@ -1828,7 +1849,7 @@ void CL_RotateAroundTag(entity_t *ent, int entnum, int parenttagent, int parentt parent[10] = axis[2][2]; parent[11] = org[2]; - R_ConcatTransforms((void*)old, (void*)parent, (void*)result); + R_ConcatTransforms((void*)parent, (void*)old, (void*)result); ent->axis[0][0] = result[0]; ent->axis[1][0] = result[1]; @@ -3436,11 +3457,14 @@ void CL_LinkPacketEntities (void) else { timerlink = &(*timerlink)->next; - if (timer->entnum >= cl.maxlerpents) - continue; - le = &cl.lerpents[timer->entnum]; - if (le->sequence != cl.lerpentssequence) - continue; + if (timer->entnum) + { + if (timer->entnum >= cl.maxlerpents) + continue; + le = &cl.lerpents[timer->entnum]; + if (le->sequence != cl.lerpentssequence) + continue; + } R_AddItemTimer(timer->origin, cl.time*90 + timer->origin[0] + timer->origin[1] + timer->origin[2], timer->radius, (cl.time - timer->start) / timer->duration); } } diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index be4ea2c7a..2f1a0d28d 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -298,7 +298,7 @@ void IN_JumpDown (void) KeyDown(&in_up); else #endif - if (condition && cl.spectator && !CAM_ISLOCKED(&cl.playerview[pnum])) + if (condition && cl.spectator && cl.playerview[pnum].cam_state == CAM_FREECAM) KeyDown(&in_up); else KeyDown(&in_jump); @@ -2026,7 +2026,11 @@ void CL_SendCmd (double frametime, qboolean mainloop) // deliver the message // cls.netchan.dupe = cl_c2sdupe.ival; - Netchan_Transmit (&cls.netchan, buf.cursize, buf.data, 2500); + Netchan_Transmit (&cls.netchan, buf.cursize, buf.data, 2500); + + //don't bank too much, because that results in banking speedcheats + if (msecs > 200) + msecs = 200; if (cls.netchan.fatal_error) { diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 4ffe62e5e..33b57e23c 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -4890,7 +4890,11 @@ double Host_Frame (double time) CL_ProgressDemoTime(); hadwork = haswork; } - cl.stillloading = cl.sendprespawn || (cls.state < ca_active && worker_flush.ival && COM_HasWork()); + cl.stillloading = cl.sendprespawn +#ifdef LOADERTHREAD + || (cls.state < ca_active && worker_flush.ival && COM_HasWork()) +#endif + ; COM_MainThreadWork(); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 598c12be2..e49e8143e 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -5725,8 +5725,71 @@ void CL_ParsePrint(char *msg, int level) } } +static void CL_ParseWeaponStats(void) +{ +#ifdef QUAKEHUD + int pl = atoi(Cmd_Argv(0)); + char *wname = Cmd_Argv(1); + unsigned int total = strtoul(Cmd_Argv(2), NULL, 0); + unsigned int hit = strtoul(Cmd_Argv(3), NULL, 0); + unsigned int idx; -void CL_ParseTeamInfo(void) + if (pl >= cl.allocated_client_slots) + return; + + for (idx = 0; idx < countof(cl.players[pl].weaponstats); idx++) + { + if (!strcmp(cl.players[pl].weaponstats[idx].wname, wname) || !*cl.players[pl].weaponstats[idx].wname) + { + Q_strncpyz(cl.players[pl].weaponstats[idx].wname, wname, sizeof(cl.players[pl].weaponstats[idx].wname)); + cl.players[pl].weaponstats[idx].total = total; + cl.players[pl].weaponstats[idx].hit = hit; + return; + } + } +#endif +} + +static void CL_ParseItemTimer(void) +{ + float timeout = atof(Cmd_Argv(0)); + vec3_t org = { atof(Cmd_Argv(1)), + atof(Cmd_Argv(2)), + atof(Cmd_Argv(3))}; + float radius = atof(Cmd_Argv(4)); + //unsigned int rgb = strtoul(Cmd_Argv(5), NULL, 16); + char *timername = Cmd_Argv(6); + unsigned int entnum = strtoul(Cmd_Argv(7), NULL, 0); + struct itemtimer_s *timer; + + if (!timeout) + timeout = FLT_MAX; + if (!radius) + radius = 32; + + for (timer = cl.itemtimers; timer; timer = timer->next) + { + if (VectorCompare(timer->origin, org) && timer->entnum == entnum) + break; + } + if (!timer) + { //didn't find it. + timer = Z_Malloc(sizeof(*timer)); + timer->next = cl.itemtimers; + cl.itemtimers = timer; + } + + VectorCopy(org, timer->origin); + timer->start = cl.time; + timer->duration = timeout; + timer->radius = radius; + timer->duration = timeout; + timer->entnum = entnum; + timer->start = cl.time; + timer->end = cl.time + timer->duration; +} + +static void CL_ParseTeamInfo(void) { unsigned int pidx = atoi(Cmd_Argv(1)); vec3_t org = @@ -5828,8 +5891,8 @@ void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds from n } else if (!strncmp(stufftext, "//wps ", 5)) { - //weapon stats, eg: - //wps CLIENT WNAME attacks hits + Cmd_TokenizeString(stufftext+5, false, false); + CL_ParseWeaponStats(); } else if (!strncmp(stufftext, "//kickfile ", 11)) { @@ -5838,6 +5901,11 @@ void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds from n if (FS_FLocateFile(Cmd_Argv(1), FSLF_IFFOUND, &loc)) Con_Printf("You have been kicked due to the file \"%s\" being modified.\n", Cmd_Argv(1)); } + else if (!strncmp(stufftext, "//it ", 5)) + { + Cmd_TokenizeString(stufftext+5, false, false); + CL_ParseItemTimer(); + } #ifdef PLUGINS else if (!strncmp(stufftext, "//tinfo ", 8)) { @@ -7002,6 +7070,11 @@ void CLNQ_ParseServerMessage (void) CLNQ_ParseProtoVersion(); break; case svc_serverdata: + if (*printtext) + { //work around a missing-eol proquake bug. + CL_PrintStandardMessage(printtext, PRINT_HIGH); + printtext[0] = 0; + } Cbuf_Execute (); // make sure any stuffed commands are done CLNQ_ParseServerData (); break; diff --git a/engine/client/cl_plugin.inc b/engine/client/cl_plugin.inc index 7b2465412..8d6b41cba 100644 --- a/engine/client/cl_plugin.inc +++ b/engine/client/cl_plugin.inc @@ -370,6 +370,32 @@ static qintptr_t VARGS Plug_Draw_StringH(void *offset, quintptr_t mask, const qi return 0; } +static qintptr_t VARGS Plug_Draw_StringWidth(void *offset, quintptr_t mask, const qintptr_t *arg) +{ + qintptr_t ret; + float h = VM_FLOAT(arg[0]); + unsigned int flags = VM_LONG(arg[1]); + char *instr = VM_POINTER(arg[2]); + conchar_t buffer[2048], *str, cmask = CON_WHITEMASK; + unsigned int parseflags = 0; + float px,py; + if (qrenderer == QR_NONE) + return 0; + if (flags & 1) + cmask |= CON_2NDCHARSETTEXT; + if (flags & 2) + parseflags |= PFS_FORCEUTF8; + str = COM_ParseFunString(CON_WHITEMASK, instr, buffer, sizeof(buffer), parseflags); + + Font_BeginScaledString(font_default, 0, 0, h, h, &px, &py); + px = Font_LineScaleWidth(buffer, str); + Font_EndString(NULL); + + //put it back in virtual space + VM_FLOAT(ret) = (px*(float)vid.width) / (float)vid.rotpixelwidth; + return ret; +} + static qintptr_t VARGS Plug_Draw_Fill(void *offset, quintptr_t mask, const qintptr_t *arg) { float x, y, width, height; @@ -791,6 +817,38 @@ static qintptr_t VARGS Plug_GetTeamInfo(void *offset, quintptr_t mask, const qin return VM_LONG(count); } #endif +#ifdef QUAKEHUD +static qintptr_t VARGS Plug_GetWeaponStats(void *offset, quintptr_t mask, const qintptr_t *arg) +{ + int self = VM_LONG(arg[0]); + struct wstats_s *result = VM_POINTER(arg[1]); + size_t maxresults = VM_LONG(arg[2]); + + int count = 0; + int i; + + if (VM_OOB(arg[0], maxresults*sizeof(*result))) + return 0; + + //FIXME: we should support some way to clear this to 0 again, other than nosave. + Cvar_Get("wpsx", "1", CVAR_USERINFO|CVAR_NOSAVE, "Hacks because ktx sucks. Must be 1 in order to receive weapon stats information in ktx."); + + if (self < 0) + { + unsigned int seat = (unsigned)(-self-1)%MAX_SPLITS; + self = cl.playerview[seat].playernum; + if (cl.playerview[seat].cam_state != CAM_FREECAM) + self = cl.playerview[seat].cam_spec_track; + } + if (self < 0) + return 0; + + if (maxresults > countof(cl.players[i].weaponstats)) + maxresults = countof(cl.players[i].weaponstats); + memcpy(result, cl.players[self].weaponstats, sizeof(*result) * maxresults); + return VM_LONG(maxresults); +} +#endif static qintptr_t VARGS Plug_Con_SubPrint(void *offset, quintptr_t mask, const qintptr_t *arg) { @@ -1158,6 +1216,7 @@ void Plug_Client_Init(void) Plug_RegisterBuiltin("Draw_CharacterH", Plug_Draw_CharacterH, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("Draw_String", Plug_Draw_String, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("Draw_StringH", Plug_Draw_StringH, PLUG_BIF_NEEDSRENDERER); + Plug_RegisterBuiltin("Draw_StringWidth", Plug_Draw_StringWidth, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("Draw_Fill", Plug_Draw_Fill, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("Draw_Line", Plug_Draw_Line, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("Draw_Colourp", Plug_Draw_ColourP, PLUG_BIF_NEEDSRENDERER); @@ -1181,6 +1240,7 @@ void Plug_Client_Init(void) #ifdef QUAKEHUD Plug_RegisterBuiltin("GetTeamInfo", Plug_GetTeamInfo, PLUG_BIF_NEEDSRENDERER); + Plug_RegisterBuiltin("GetWeaponStats", Plug_GetWeaponStats, PLUG_BIF_NEEDSRENDERER); #endif Plug_RegisterBuiltin("GetLocationName", Plug_GetLocationName, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("GetPlayerInfo", Plug_GetPlayerInfo, PLUG_BIF_NEEDSRENDERER); diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 9ef528d3d..912893379 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -370,9 +370,18 @@ void CL_PredictUsercmd (int pnum, int entnum, player_state_t *from, player_state split = *u; split.msec = u->msec / 2; //special care to avoid forgetting an msec here and there - CL_PredictUsercmd (pnum, entnum, from, &temp, &split); - split.msec = u->msec - split.msec; - CL_PredictUsercmd (pnum, entnum, &temp, to, &split); + + if (split.msec > 500) + { + split.msec = 500; + CL_PredictUsercmd (pnum, entnum, from, to, &split); + } + else + { + CL_PredictUsercmd (pnum, entnum, from, &temp, &split); + split.msec = u->msec - split.msec; + CL_PredictUsercmd (pnum, entnum, &temp, to, &split); + } return; } if (!cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED) @@ -972,7 +981,7 @@ void CL_PredictMovePNum (int seat) if (!cl.ackedmovesequence) nopred = true; else if (cl.movesequence - cl.ackedmovesequence >= UPDATE_BACKUP-1) - return; + nopred = true; //these things also force-disable prediction if ((cls.demoplayback==DPB_MVD || cls.demoplayback == DPB_EZTV) || diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index a0f37b7b3..44d7705ff 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -1889,6 +1889,8 @@ void SCR_ImageName (char *mapname) if (qrenderer) { + R_LoadHiResTexture(levelshotname, NULL, IF_NOWORKER|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_CLAMP); + if (!R_GetShaderSizes(R2D_SafeCachePic (levelshotname), NULL, NULL, true)) { *levelshotname = '\0'; diff --git a/engine/client/client.h b/engine/client/client.h index 4328ef807..8351858bd 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -200,6 +200,15 @@ typedef struct player_info_s int prevcount; +#ifdef QUAKEHUD + struct wstats_s + { + char wname[16]; + unsigned int hit; + unsigned int total; + } weaponstats[16]; +#endif + int stats[MAX_CL_STATS]; float statsf[MAX_CL_STATS]; } player_info_t; diff --git a/engine/client/console.c b/engine/client/console.c index be260f607..2ce8d25d8 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -60,6 +60,9 @@ float con_cursorspeed = 4; cvar_t con_numnotifylines = SCVAR("con_notifylines","4"); //max lines to show cvar_t con_notifytime = SCVAR("con_notifytime","3"); //seconds +cvar_t con_notify_x = SCVAR("con_notify_x","0"); +cvar_t con_notify_y = SCVAR("con_notify_y","0"); +cvar_t con_notify_w = SCVAR("con_notify_w","1"); cvar_t con_centernotify = SCVAR("con_centernotify", "0"); cvar_t con_displaypossibilities = SCVAR("con_displaypossibilities", "1"); cvar_t con_maxlines = SCVAR("con_maxlines", "1024"); @@ -622,8 +625,11 @@ void Con_Init (void) // // register our commands // - Cvar_Register (&con_notifytime, "Console controls"); Cvar_Register (&con_centernotify, "Console controls"); + Cvar_Register (&con_notifytime, "Console controls"); + Cvar_Register (&con_notify_x, "Console controls"); + Cvar_Register (&con_notify_y, "Console controls"); + Cvar_Register (&con_notify_w, "Console controls"); Cvar_Register (&con_numnotifylines, "Console controls"); Cvar_Register (&con_displaypossibilities, "Console controls"); Cvar_Register (&cl_chatmode, "Console controls"); @@ -1036,6 +1042,8 @@ void Con_Footerf(console_t *con, qboolean append, char *fmt, ...) conline_t *newf; if (!con) con = con_current; + if (!con) + return; va_start (argptr,fmt); vsnprintf (msg,sizeof(msg)-1, fmt,argptr); @@ -1422,7 +1430,9 @@ void Con_DrawNotify (void) con_main.flags |= CONF_NOTIFY; /*keep the main console up to date*/ con_main.notif_l = con_numnotifylines.ival; - con_main.notif_w = 1; + con_main.notif_w = con_notify_w.value; + con_main.notif_x = con_notify_x.value; + con_main.notif_y = con_notify_y.value; con_main.notif_t = con_notifytime.value; if (con_chat) @@ -1540,7 +1550,7 @@ static int Con_DrawProgress(int left, int right, int y) char *progresstext = NULL; char *txt; int x, tw; - int i, j; + int i; int barwidth, barleft; float progresspercent = 0; unsigned int codeflags, codepoint; @@ -1761,7 +1771,6 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in int linecount; conchar_t *starts[64], *ends[sizeof(starts)/sizeof(starts[0])]; conchar_t *s, *e, *c; - int i; int x; int charh = Font_CharHeight(); unsigned int codeflags, codepoint; diff --git a/engine/client/image.c b/engine/client/image.c index 9c4facc1d..8522c2ca9 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -4384,6 +4384,9 @@ static image_t *Image_CreateTexture_Internal (const char *identifier, const char buck = (bucket_t*)(tex+1); tex->ident = (char*)(buck+1); strcpy(tex->ident, identifier); +#ifdef _DEBUG + Q_strncpyz(tex->dbgident, identifier, sizeof(tex->dbgident)); +#endif if (subdir && *subdir) { tex->subpath = tex->ident + strlen(identifier)+1; diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 66253b3f5..3726aac83 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -253,7 +253,30 @@ void M_Menu_Options_f (void) }; menu_t *menu = M_Options_Title(&y, 0); static menuresel_t resel; - MC_AddBulk(menu, &resel, bulk, 16, 216, y); + y = MC_AddBulk(menu, &resel, bulk, 16, 216, y); + +#ifdef PLUGINS + if (Cmd_Exists("ezhud_nquake")) + { + extern cvar_t plug_sbar; + static const char *hudplugopts[] = { + "Never", + "Deathmatch", + "Single Player/Coop", + "Always", + NULL + }; + static const char *hudplugvalues[] = { + "0", + "1", + "2", + "3", + NULL + }; + MC_AddCvarCombo(menu, 16, 216, y, "Use Hud Plugin", &plug_sbar, hudplugopts, hudplugvalues); y += 8; + } +#endif + menu->data = updatecbo; menu->remove = M_Options_Remove; @@ -1213,6 +1236,9 @@ qboolean M_VideoApplyShadowLighting (union menuoption_s *op,struct menu_s *menu, cvarsrds = "1"; break; case 4: + cvard = "-1"; + break; + case 5: cvard = "1"; cvarvd = "1"; break; @@ -1259,6 +1285,7 @@ void M_Menu_Lighting_f (void) "Standard", "Realtime", "RT+Shadows", + "Threaded Lightmaps", #ifndef MINIMAL "Vertex", #endif @@ -1352,11 +1379,13 @@ void M_Menu_Lighting_f (void) else dlightselect = 2; } + else if (r_dynamic.ival < 0) + dlightselect = 4; #ifndef MINIMAL else if (r_vertexdlights.ival) - dlightselect = 4; + dlightselect = 5; #endif - else if (r_dynamic.ival) + else if (r_dynamic.ival > 0) dlightselect = 1; else dlightselect = 0; @@ -2707,6 +2736,9 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_ modelview_t *mods = c->dptr; + if (R2D_Flush) + R2D_Flush(); + memset(&pv, 0, sizeof(pv)); CL_DecayLights (); diff --git a/engine/client/merged.h b/engine/client/merged.h index 5dd5d038a..e6bf88db7 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -137,6 +137,7 @@ enum mlverbosity_e { MLV_SILENT, MLV_WARN, + MLV_WARNSYNC, MLV_ERROR }; @@ -225,6 +226,9 @@ enum }; typedef struct image_s { +#ifdef _DEBUG + char dbgident[32]; +#endif char *ident; //allocated on end char *subpath; //allocated on end int regsequence; diff --git a/engine/client/net_master.c b/engine/client/net_master.c index c3c50821e..cf092c099 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -2923,7 +2923,7 @@ int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolean favor info->players=details.numplayers = 0; if (!strchr(msg, '\n')) - info->players = atoi(Info_ValueForKey(details.info, "clients")); + info->numhumans = info->players = atoi(Info_ValueForKey(details.info, "clients")); else { int clnum; diff --git a/engine/client/p_script.c b/engine/client/p_script.c index 8dbb8f160..208d5a4b6 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -830,7 +830,7 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) memset(&tn, 0, sizeof(tn)); if (*ptype->texname) { - tn.base = R_LoadHiResTexture(ptype->texname, "particles", IF_NOMIPMAP|(ptype->looks.premul?IF_PREMULTIPLYALPHA:0)); //mipmapping breaks particlefont stuff + tn.base = R_LoadHiResTexture(ptype->texname, "particles", IF_LOADNOW | IF_NOMIPMAP|(ptype->looks.premul?IF_PREMULTIPLYALPHA:0)); //mipmapping breaks particlefont stuff if (tn.base && tn.base->status == TEX_LOADING) COM_WorkerPartialSync(tn.base, &tn.base->status, TEX_LOADING); } diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 841910407..d953daf45 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -1575,9 +1575,9 @@ static void Surf_RenderDynamicLightmaps_Worker (msurface_t *fa) qbyte *base, *luxbase; stmap *stainbase; int maps; - glRect_t *theRect; + glRect_t *lmr, *dlmr = NULL; int smax, tmax; - lightmapinfo_t *lm, *dlm; + lightmapinfo_t *lm, *dlm = NULL; //surfaces without lightmaps if (fa->lightmaptexturenums[0]<0 || !lightmap) @@ -1613,29 +1613,11 @@ dynamic: smax = (fa->extents[0]>>fa->lmshift)+1; tmax = (fa->extents[1]>>fa->lmshift)+1; - theRect = &lm->rectchange; - if (theRect->t > fa->light_t[0]) - theRect->t = fa->light_t[0]; - if (theRect->b < fa->light_t[0]+tmax) - theRect->b = fa->light_t[0]+tmax; - if (theRect->l > fa->light_s[0]) - theRect->l = fa->light_s[0]; - if (theRect->r < fa->light_s[0]+smax) - theRect->r = fa->light_s[0]+smax; - + lmr = &lm->rectchange; if (lm->hasdeluxe) { dlm = lightmap[fa->lightmaptexturenums[0]+1]; - dlm->modified = true; - theRect = &dlm->rectchange; - if (theRect->t > fa->light_t[0]) - theRect->t = fa->light_t[0]; - if (theRect->b < fa->light_t[0]+tmax) - theRect->b = fa->light_t[0]+tmax; - if (theRect->l > fa->light_s[0]) - theRect->l = fa->light_s[0]; - if (theRect->r < fa->light_s[0]+smax) - theRect->r = fa->light_s[0]+smax; + dlmr = &dlm->rectchange; luxbase = dlm->lightmaps; luxbase += (fa->light_t[0] * dlm->width + fa->light_s[0]) * lightmap_bytes; @@ -1649,6 +1631,26 @@ dynamic: stainbase += (fa->light_t[0] * lm->width + fa->light_s[0]) * 3; Surf_BuildLightMap_Worker (fa, base, luxbase, stainbase, lightmap_shift, r_ambient.value*255, lm->width); + if (dlm) + { + if (dlmr->t > fa->light_t[0]) + dlmr->t = fa->light_t[0]; + if (dlmr->b < fa->light_t[0]+tmax) + dlmr->b = fa->light_t[0]+tmax; + if (dlmr->l > fa->light_s[0]) + dlmr->l = fa->light_s[0]; + if (dlmr->r < fa->light_s[0]+smax) + dlmr->r = fa->light_s[0]+smax; + dlm->modified = true; + } + if (lmr->t > fa->light_t[0]) + lmr->t = fa->light_t[0]; + if (lmr->b < fa->light_t[0]+tmax) + lmr->b = fa->light_t[0]+tmax; + if (lmr->l > fa->light_s[0]) + lmr->l = fa->light_s[0]; + if (lmr->r < fa->light_s[0]+smax) + lmr->r = fa->light_s[0]+smax; lm->modified = true; } #endif //THREADEDWORLD @@ -3584,7 +3586,7 @@ TRACE(("dbg: Surf_NewMap: tp\n")); { //unfortunately, we need to know the actual size so that we can get this right. bum. if (cl_static_entities[i].ent.model->loadstate == MLS_NOTLOADED) - Mod_LoadModel(cl_static_entities[i].ent.model, MLV_SILENT); + Mod_LoadModel(cl_static_entities[i].ent.model, MLV_WARNSYNC); if (cl_static_entities[i].ent.model->loadstate == MLS_LOADING) COM_WorkerPartialSync(cl_static_entities[i].ent.model, &cl_static_entities[i].ent.model->loadstate, MLS_LOADING); VectorAdd(cl_static_entities[i].ent.origin, cl_static_entities[i].ent.model->mins, mins); diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 883b3823c..7dd0de03b 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -1268,7 +1268,7 @@ TRACE(("dbg: R_ApplyRenderer: initing mods\n")); #endif TRACE(("dbg: R_ApplyRenderer: reloading server map\n")); - sv.world.worldmodel = Mod_ForName (sv.modelname, MLV_WARN); + sv.world.worldmodel = Mod_ForName (sv.modelname, MLV_WARNSYNC); TRACE(("dbg: R_ApplyRenderer: loaded\n")); if (sv.world.worldmodel->loadstate == MLS_LOADING) COM_WorkerPartialSync(sv.world.worldmodel, &sv.world.worldmodel->loadstate, MLS_LOADING); diff --git a/engine/client/sbar.c b/engine/client/sbar.c index f7bec943d..fed4308a5 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -1423,8 +1423,6 @@ void Sbar_SortFrags (qboolean includespec, qboolean doteamsort) { fragsort[scoreboardlines] = i; scoreboardlines++; - if (cl.players[i].spectator) - cl.players[i].frags = -999; } } @@ -1443,8 +1441,8 @@ void Sbar_SortFrags (qboolean includespec, qboolean doteamsort) if (!doteamsort || w1 == w2) #endif { - w1 = cl.players[fragsort[i]].frags; - w2 = cl.players[fragsort[j]].frags; + w1 = cl.players[fragsort[i]].spectator==1?-999:cl.players[fragsort[i]].frags; + w2 = cl.players[fragsort[j]].spectator==1?-999:cl.players[fragsort[j]].frags; } if (w1 < w2) { diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 7693af964..1e5f289f0 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -2572,26 +2572,23 @@ void S_StopAllSounds(qboolean clear) for (sc = sndcardinfo; sc; sc = sc->next) { - for (i=0 ; itotal_chans ; i++) + for (i=sc->total_chans ; i --> 0 ; ) { if (i >= MUSIC_FIRST && i < MUSIC_FIRST+NUM_MUSICS && sc->selfpainting) continue; //don't reset music if is safe to continue playing it without stuttering - if (sc->channel[i].sfx) + s = sc->channel[i].sfx; + if (s) { - s = sc->channel[i].sfx; - if (s->loadstate == SLS_LOADING) - COM_WorkerPartialSync(s, &s->loadstate, SLS_LOADING); -// else + sc->channel[i].sfx = NULL; + if (s->loadstate == SLS_LOADED && s->decoder.ended) + if (!S_IsPlayingSomewhere(s)) //if we aint playing it elsewhere, free it compleatly. { - sc->channel[i].sfx = NULL; if (s->decoder.ended) - if (!S_IsPlayingSomewhere(s)) //if we aint playing it elsewhere, free it compleatly. - { s->decoder.ended(s); - } - if (sc->ChannelUpdate) - sc->ChannelUpdate(sc, &sc->channel[i], true); } + + if (sc->ChannelUpdate) + sc->ChannelUpdate(sc, &sc->channel[i], true); } } diff --git a/engine/client/view.c b/engine/client/view.c index e7974798f..1ea3b600a 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -580,37 +580,68 @@ When you run over an item, the server sends this command */ void V_BonusFlash_f (void) { - if (v_bonusflash.value || !Cmd_FromGamecode()) + float frac; + if (!gl_cshiftenabled.ival) + frac = 0; + else if (Cmd_FromGamecode()) + frac = v_bonusflash.value; + else + frac = 1; + + { + //still adheres to gl_cshiftpercent even when forced. + float minfrac = atof(Cmd_Argv(5)); + if (frac < minfrac) + frac = minfrac; + } + + frac *= gl_cshiftpercent.value / 100.0; + + if (frac) { if (Cmd_Argc() > 1) { //this is how I understand DP expects them. - cl.cshifts[CSHIFT_BONUS].destcolor[0] = atof(Cmd_Argv(1)); - cl.cshifts[CSHIFT_BONUS].destcolor[1] = atof(Cmd_Argv(2)); - cl.cshifts[CSHIFT_BONUS].destcolor[2] = atof(Cmd_Argv(3)); - cl.cshifts[CSHIFT_BONUS].percent = atof(Cmd_Argv(4))*255*v_bonusflash.value; + cl.cshifts[CSHIFT_BONUS].destcolor[0] = atof(Cmd_Argv(1))*255; + cl.cshifts[CSHIFT_BONUS].destcolor[1] = atof(Cmd_Argv(2))*255; + cl.cshifts[CSHIFT_BONUS].destcolor[2] = atof(Cmd_Argv(3))*255; + cl.cshifts[CSHIFT_BONUS].percent = atof(Cmd_Argv(4))*255*frac; } else { cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215; cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186; cl.cshifts[CSHIFT_BONUS].destcolor[2] = 69; - cl.cshifts[CSHIFT_BONUS].percent = 50*v_bonusflash.value; + cl.cshifts[CSHIFT_BONUS].percent = 50*frac; } } } void V_DarkFlash_f (void) { + float frac; + if (!gl_cshiftenabled.ival) + frac = 0; + else + frac = 1; + frac *= gl_cshiftpercent.value / 100.0; + cl.cshifts[CSHIFT_BONUS].destcolor[0] = 0; cl.cshifts[CSHIFT_BONUS].destcolor[1] = 0; cl.cshifts[CSHIFT_BONUS].destcolor[2] = 0; - cl.cshifts[CSHIFT_BONUS].percent = 255; + cl.cshifts[CSHIFT_BONUS].percent = 255*frac; } void V_WhiteFlash_f (void) { + float frac; + if (!gl_cshiftenabled.ival) + frac = 0; + else + frac = 1; + frac *= gl_cshiftpercent.value / 100.0; + cl.cshifts[CSHIFT_BONUS].destcolor[0] = 255; cl.cshifts[CSHIFT_BONUS].destcolor[1] = 255; cl.cshifts[CSHIFT_BONUS].destcolor[2] = 255; - cl.cshifts[CSHIFT_BONUS].percent = 255; + cl.cshifts[CSHIFT_BONUS].percent = 255*frac; } /* @@ -718,7 +749,7 @@ void V_CalcBlend (float *hw_blend) //don't apply it to the server, we'll blend the two later if the user has no hardware gamma (if they do have it, we use just the server specified value) This way we avoid winnt users having a cheat with flashbangs and stuff. for (j=0 ; j= 2) + Con_Printf (" "); #ifdef SERVERONLY Con_Printf ("%s", Cmd_Argv(i)); #else diff --git a/engine/common/common.c b/engine/common/common.c index c0e446460..b677308ac 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -704,7 +704,10 @@ void deleetstring(char *result, const char *leet) s2++; continue; } - *s = *s2 & ~128; + if (*s2 >= 0xa0) + *s = *s2 & ~128; + else + *s = *s2; s2++; if (*s == '3') *s = 'e'; @@ -4724,6 +4727,11 @@ void COM_ErrorMe_f(void) #ifdef LOADERTHREAD +static void QDECL COM_WorkerCount_Change(cvar_t *var, char *oldvalue); +cvar_t worker_flush = CVARD("worker_flush", "1", "If set, process the entire load queue, loading stuff faster but at the risk of stalling the main thread."); +cvar_t worker_count = CVARFDC("worker_count", "", CVAR_NOTFROMSERVER, "Specifies the number of worker threads to utilise.", COM_WorkerCount_Change); +cvar_t worker_sleeptime = CVARFD("worker_sleeptime", "0", CVAR_NOTFROMSERVER, "Causes workers to sleep for a period of time after each job."); + #define WG_MAIN 0 #define WG_LOADER 1 #define WG_COUNT 2 //main and loaders @@ -4801,11 +4809,26 @@ void COM_AddWork(int tg, void(*func)(void *ctx, void *data, size_t a, size_t b), Sys_ConditionSignal(com_workercondition[tg]); Sys_UnlockConditional(com_workercondition[tg]); - -// if (!com_workerthread[thread]) -// while(COM_DoWork(thread, false)) -// ; } + +void COM_PrintWork(void) +{ + struct com_work_s *work; + int tg; + Sys_Printf("--------- BEGIN WORKER LIST ---------\n"); + for (tg = 0; tg < WG_COUNT; tg++) + { + Sys_LockConditional(com_workercondition[tg]); + work = com_work_head[tg]; + while (work) + { + Sys_Printf("thread%i: %s\n", tg, (char*)work->ctx); + work = work->next; + } + Sys_UnlockConditional(com_workercondition[tg]); + } +} + //leavelocked = false == poll mode. //leavelocked = true == safe sleeping qboolean COM_DoWork(int tg, qboolean leavelocked) @@ -4905,7 +4928,14 @@ static int COM_WorkerThread(void *arg) for(;;) { while(COM_DoWork(group, true)) - ; + { + if (worker_sleeptime.value) + { + Sys_UnlockConditional(com_workercondition[group]); + Sys_Sleep(worker_sleeptime.value); + Sys_LockConditional(com_workercondition[group]); + } + } if (thread->request) //flagged from some work { if (thread->request == WR_DIE) @@ -5065,7 +5095,7 @@ void COM_WorkerFullSync(void) void COM_WorkerPartialSync(void *priorityctx, int *address, int value) { struct com_work_s **link, *work, *prev; - double time1 = Sys_DoubleTime(); +// double time1 = Sys_DoubleTime(); // Con_Printf("waiting for %p %s\n", priorityctx, priorityctx); @@ -5106,7 +5136,15 @@ void COM_WorkerPartialSync(void *priorityctx, int *address, int value) Sys_UnlockConditional(com_workercondition[grp]); } if (!found) - Con_DPrintf("Might be in for a long wait for %s\n", (char*)priorityctx); + { + while(COM_DoWork(WG_MAIN, false)) + { + //give up as soon as we're done + if (*address != value) + return; + } +// Con_Printf("Might be in for a long wait for %s\n", (char*)priorityctx); + } } Sys_LockConditional(com_workercondition[WG_MAIN]); @@ -5178,8 +5216,6 @@ static void QDECL COM_WorkerCount_Change(cvar_t *var, char *oldvalue) } Sys_ConditionBroadcast(com_workercondition[WG_LOADER]); //and make sure they ALL wake up to check their new death values. } -cvar_t worker_flush = CVARD("worker_flush", "1", "If set, process the entire load queue, loading stuff faster but at the risk of stalling the main thread."); -cvar_t worker_count = CVARFDC("worker_count", "", CVAR_NOTFROMSERVER, "Specifies the number of worker threads to utilise.", COM_WorkerCount_Change); static void COM_InitWorkerThread(void) { int i; @@ -5200,10 +5236,11 @@ static void COM_InitWorkerThread(void) worker_count.flags |= CVAR_NOSET; } Cvar_Register(&worker_count, NULL); - Cvar_ForceCallback(&worker_count); Cmd_AddCommand ("worker_test", COM_WorkerTest_f); Cvar_Register(&worker_flush, NULL); + Cvar_Register(&worker_sleeptime, NULL); + Cvar_ForceCallback(&worker_count); } #endif diff --git a/engine/common/cvar.c b/engine/common/cvar.c index bab4d6f34..2dcc7b1a2 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -1179,6 +1179,10 @@ cvar_t *Cvar_Get2(const char *name, const char *defaultvalue, int flags, const c if (!description) description = ""; + //don't allow cvars with certain funny chars in their name. ever. such things get really messy when saved in configs or whatever. + if (!*name || strchr(name, '\"') || strchr(name, '^') || strchr(name, '$') || strchr(name, ' ') || strchr(name, '\t') || strchr(name, '\r') || strchr(name, '\n') || strchr(name, ';')) + return NULL; + var = (cvar_t*)Z_Malloc(sizeof(cvar_t)+strlen(name)+1+(description?(strlen(description)+1):0)); var->name = (char *)(var+1); strcpy(var->name, name); @@ -1259,31 +1263,31 @@ qboolean Cvar_Command (int level) { if (v->flags & CVAR_LATCH) { - Con_Printf ("\"%s\" is currently %s\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), false)); - Con_Printf ("Will be changed to %s on the next map\n", COM_QuotedString(v->latched_string, buffer, sizeof(buffer), false)); + Con_Printf ("\"%s\" is currently \"%s\"\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), true)); + Con_Printf ("Will be changed to \"%s\" on the next map\n", COM_QuotedString(v->latched_string, buffer, sizeof(buffer), true)); } else if (v->flags & CVAR_RENDERERLATCH) { - Con_Printf ("\"%s\" is %s\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), false)); - Con_Printf ("Will be changed to %s on vid_restart\n", COM_QuotedString(v->latched_string, buffer, sizeof(buffer), false)); + Con_Printf ("\"%s\" is \"%s\"\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), true)); + Con_Printf ("Will be changed to \"%s\" on vid_restart\n", COM_QuotedString(v->latched_string, buffer, sizeof(buffer), true)); } else { - Con_Printf ("\"%s\" is %s\n", v->name, COM_QuotedString(v->latched_string, buffer, sizeof(buffer), false)); - Con_Printf ("Effective value is %s\n", COM_QuotedString(v->string, buffer, sizeof(buffer), false)); + Con_Printf ("\"%s\" is \"%s\"\n", v->name, COM_QuotedString(v->latched_string, buffer, sizeof(buffer), true)); + Con_Printf ("Effective value is \"%s\"\n", COM_QuotedString(v->string, buffer, sizeof(buffer), true)); } if (v->defaultstr) - Con_Printf("Default: \"%s\"\n", COM_QuotedString(v->defaultstr, buffer, sizeof(buffer), false)); + Con_Printf("Default: \"%s\"\n", COM_QuotedString(v->defaultstr, buffer, sizeof(buffer), true)); } else { if (v->defaultstr && !strcmp(v->string, v->defaultstr)) - Con_Printf ("\"%s\" is %s (default)\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), false)); + Con_Printf ("\"%s\" is \"%s\" (default)\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), true)); else { - Con_Printf ("\"%s\" is %s\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), false)); + Con_Printf ("\"%s\" is \"%s\"\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), true)); if (v->defaultstr) - Con_Printf("Default: %s\n", COM_QuotedString(v->defaultstr, buffer, sizeof(buffer), false)); + Con_Printf("Default: \"%s\"\n", COM_QuotedString(v->defaultstr, buffer, sizeof(buffer), true)); } } return true; @@ -1309,9 +1313,9 @@ qboolean Cvar_Command (int level) { //don't bother even changing the cvar locally, just update the server's version. //fixme: quake2/quake3 latching. if (seat) - CL_SendClientCommand(true, "%i setinfo %s \"%s\"", seat+1, v->name, str); + CL_SendClientCommand(true, "%i setinfo %s %s", seat+1, v->name, COM_QuotedString(str, buffer, sizeof(buffer), false)); else - CL_SendClientCommand(true, "setinfo %s \"%s\"", v->name, str); + CL_SendClientCommand(true, "setinfo %s %s", v->name, COM_QuotedString(str, buffer, sizeof(buffer), false)); } else CL_SetInfo(seat, v->name, str); diff --git a/engine/common/fs.c b/engine/common/fs.c index 645fd3ce5..291b3d392 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -1065,7 +1065,7 @@ int FS_FLocateFile(const char *filename, unsigned int lflags, flocation_t *loc) // optionally check the non-pure paths too. for (search = com_searchpaths ; search ; search = search->next) { - if ((lflags & FSLF_SECUREONLY) && !(search->flags & SPF_UNTRUSTED)) + if ((lflags & FSLF_SECUREONLY) && (search->flags & SPF_UNTRUSTED)) continue; depth += ((search->flags & SPF_EXPLICIT) || (lflags & FSLF_DEPTH_EXPLICIT)); fs_finds++; @@ -3636,8 +3636,11 @@ static void FS_FreePaths(void) void FS_Shutdown(void) { FS_FreePaths(); - Sys_DestroyMutex(fs_thread_mutex); - fs_thread_mutex = NULL; + if (fs_thread_mutex) + { + Sys_DestroyMutex(fs_thread_mutex); + fs_thread_mutex = NULL; + } Cvar_SetEngineDefault(&fs_gamename, NULL); Cvar_SetEngineDefault(&com_protocolname, NULL); diff --git a/engine/common/fs_win32.c b/engine/common/fs_win32.c index c140d01a2..88efbad87 100644 --- a/engine/common/fs_win32.c +++ b/engine/common/fs_win32.c @@ -281,7 +281,10 @@ static void QDECL VFSW32_Flush(struct vfsfile_s *file) vfsw32file_t *intfile = (vfsw32file_t*)file; if (intfile->mmap) FlushViewOfFile(intfile->mmap, intfile->length); - FlushFileBuffers(intfile->hand); + + //we only really flush things to ensure that we don't get a stall later. + //in windows, FlushFileBuffers can have significant costs, so lets see if anyone complains about us not flushing. +// FlushFileBuffers(intfile->hand); } static qofs_t QDECL VFSW32_GetSize (struct vfsfile_s *file) { diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 4faaa0337..27c7bcde2 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -105,19 +105,29 @@ void INS_UpdateGrabs(int fullscreen, int activeapp); int QCLibEditor(pubprogfuncs_t *prinst, const char *filename, int *line, int *statement, char *error, pbool fatal); void QCLoadBreakpoints(const char *vmname, const char *progsname) { //this asks the gui to reapply any active breakpoints and waits for them so that any spawn functions can be breakpointed properly. -#if defined(_WIN32) && !defined(SERVERONLY) && !defined(FTE_SDL) +#if defined(_WIN32) && !defined(FTE_SDL) extern int isPlugin; if (isPlugin >= 2) { +#ifdef SERVERONLY + SV_GetConsoleCommands(); +#else Sys_SendKeyEvents(); +#endif debuggerresume = -1; printf("qcreloaded \"%s\" \"%s\"\n", vmname, progsname); fflush(stdout); +#ifndef SERVERONLY INS_UpdateGrabs(false, false); +#endif while(debuggerresume == -1 && !wantquit) { Sleep(10); +#ifdef SERVERONLY + SV_GetConsoleCommands(); +#else Sys_SendKeyEvents(); +#endif } } #endif @@ -129,6 +139,8 @@ size_t debuggerwnd; qboolean QCExternalDebuggerCommand(char *text) { + if (!isPlugin) + return false; if ((!strncmp(text, "qcstep", 6) && (text[6] == 0 || text[6] == ' ')) || (!strncmp(text, "qcresume", 8) && (text[8] == 0 || text[8] == ' '))) { // int l; @@ -321,6 +333,8 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, const char *filename, int *line, int if (debuggerstacky) PR_StackTrace(prinst, 2); debuggerstacky = 0; + if (R2D_Flush) + R2D_Flush(); VID_SwapBuffers(); } } @@ -4575,14 +4589,13 @@ void QCBUILTIN PF_droptofloor (pubprogfuncs_t *prinst, struct globalvars_s *pr_g vec3_t start; trace_t trace; const float *gravitydir; - extern const vec3_t standardgravity; ent = PROG_TO_WEDICT(prinst, *world->g.self); if (ent->xv->gravitydir[2] || ent->xv->gravitydir[1] || ent->xv->gravitydir[0]) gravitydir = ent->xv->gravitydir; else - gravitydir = standardgravity; + gravitydir = world->g.defaultgravitydir; VectorCopy (ent->v->origin, end); if (pr_droptofloorunits.value > 0) @@ -5960,9 +5973,11 @@ lh_extension_t QSG_Extensions[] = { {"FTE_QC_TRACETRIGGER"}, {"FTE_SOLID_LADDER"}, //Allows a simple trigger to remove effects of gravity (solid 20). obsolete. will prolly be removed at some point as it is not networked properly. Use FTE_ENT_SKIN_CONTENTS +#ifdef SQL // serverside SQL functions for managing an SQL database connection {"FTE_SQL", 9, NULL, {"sqlconnect","sqldisconnect","sqlopenquery","sqlclosequery","sqlreadfield","sqlerror","sqlescape","sqlversion", "sqlreadfloat"}}, +#endif //eperimental advanced strings functions. //reuses the FRIK_FILE builtins (with substring extension) diff --git a/engine/common/world.h b/engine/common/world.h index fc83b4cd6..143288547 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -213,6 +213,7 @@ struct world_s float *v_forward; float *v_right; float *v_up; + float *defaultgravitydir; //used by menu+csqc. float *drawfont; diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index b19670975..3b48b75a5 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -248,18 +248,16 @@ void GLBE_PolyOffsetStencilShadow(qboolean pushdepth) { extern cvar_t r_polygonoffset_stencil_offset, r_polygonoffset_stencil_factor; polyoffset_t po; + po.factor = r_polygonoffset_stencil_factor.value; + po.unit = r_polygonoffset_stencil_offset.value; + if (pushdepth) { /*some quake doors etc are flush with the walls that they're meant to be hidden behind, or plats the same height as the floor, etc we move them back very slightly using polygonoffset to avoid really ugly z-fighting*/ extern cvar_t r_polygonoffset_submodel_offset, r_polygonoffset_submodel_factor; - po.factor = r_polygonoffset_submodel_factor.value + r_polygonoffset_stencil_factor.value; - po.unit = r_polygonoffset_submodel_offset.value + r_polygonoffset_stencil_offset.value; - } - else - { - po.factor = r_polygonoffset_stencil_factor.value; - po.unit = r_polygonoffset_stencil_offset.value; + po.factor += r_polygonoffset_submodel_factor.value; + po.unit += r_polygonoffset_submodel_offset.value; } #ifndef FORCESTATE @@ -903,7 +901,8 @@ void GLBE_RenderShadowBuffer(unsigned int numverts, int vbo, vecV_t *verts, unsi shaderstate.sourcevbo = &shaderstate.dummyvbo; shaderstate.dummyvbo.indicies.gl.vbo = ibo; - GLBE_PolyOffsetShadowMap(false); + if (shaderstate.mode != BEM_STENCIL) + GLBE_PolyOffsetShadowMap(false); if (shaderstate.allblackshader.glsl.handle) { @@ -4942,7 +4941,11 @@ static void BE_UpdateLightmaps(void) { int t = lm->rectchange.t; //pull them out now, in the hopes that it'll be more robust with respect to r_dynamic -1 int b = lm->rectchange.b; - lm->modified = false; +#ifdef _DEBUG + if (t >= b) + Con_Printf("Dodgy lightmaps\n"); + else +#endif if (!TEXVALID(lm->lightmap_texture)) { extern cvar_t gl_lightmap_nearest; @@ -4962,6 +4965,7 @@ static void BE_UpdateLightmaps(void) lm->width, b-t, glformat, gltype, lm->lightmaps+t *lm->width*lightmap_bytes); } + lm->modified = false; lm->rectchange.l = lm->width; lm->rectchange.t = lm->height; lm->rectchange.r = 0; diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 88df66505..657494e64 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -946,17 +946,17 @@ static texid_t Font_LoadReplacementConchars(void) { texid_t tex; //q1 replacement - tex = R_LoadReplacementTexture("gfx/conchars.lmp", NULL, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA, NULL, 0, 0, TF_INVALID); + tex = R_LoadReplacementTexture("gfx/conchars.lmp", NULL, IF_LOADNOW|IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA, NULL, 0, 0, TF_INVALID); TEXDOWAIT(tex); if (TEXLOADED(tex)) return tex; //q2 - tex = R_LoadHiResTexture("pics/conchars.pcx", NULL, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA); + tex = R_LoadHiResTexture("pics/conchars.pcx", NULL, IF_LOADNOW|IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA); TEXDOWAIT(tex); if (TEXLOADED(tex)) return tex; //q3 - tex = R_LoadHiResTexture("gfx/2d/bigchars.tga", NULL, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA); + tex = R_LoadHiResTexture("gfx/2d/bigchars.tga", NULL, IF_LOADNOW|IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA); TEXDOWAIT(tex); if (TEXLOADED(tex)) return tex; @@ -980,7 +980,7 @@ static texid_t Font_LoadQuakeConchars(void) if (lump[i] == 0) lump[i] = 255; // proper transparent color - return R_LoadTexture8("charset", 128, 128, (void*)lump, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA, 1); + return R_LoadTexture8("charset", 128, 128, (void*)lump, IF_LOADNOW|IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA, 1); } return r_nulltex; } @@ -1066,7 +1066,7 @@ static texid_t Font_LoadHexen2Conchars(qboolean iso88591) for (i=0 ; i<128*128 ; i++) if (outbuf[i] == 0) outbuf[i] = 255; // proper transparent color - tex = R_LoadTexture8 (iso88591?"gfx/menu/8859-1.lmp":"charset", 128, 128, outbuf, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA, 1); + tex = R_LoadTexture8 (iso88591?"gfx/menu/8859-1.lmp":"charset", 128, 128, outbuf, IF_LOADNOW|IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA, 1); Z_Free(outbuf); return tex; } @@ -1123,7 +1123,7 @@ static texid_t Font_LoadFallbackConchars(void) Font_CopyGlyph(']', 130, lump); Font_CopyGlyph('o', 131, lump); } - tex = R_LoadTexture32("charset", width, height, (void*)lump, IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA); + tex = R_LoadTexture32("charset", width, height, (void*)lump, IF_LOADNOW|IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA); BZ_Free(lump); return tex; } diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 4d8837d1a..f03d72f32 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -481,7 +481,11 @@ void Mod_Purge(enum mod_purge_e ptype) if (unused || ptype != MP_MAPCHANGED) { if (mod->loadstate == MLS_LOADING) + { + if (ptype == MP_MAPCHANGED && !mod->submodelof) + continue; //don't bother waiting for it on map changes. COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING); + } if (unused) Con_DPrintf("model \"%s\" no longer needed\n", mod->name); @@ -944,6 +948,7 @@ void Mod_ModelLoaded(void *ctx, void *data, size_t a, size_t b) case MLV_ERROR: Host_EndGame ("Mod_NumForName: %s not found or couldn't load", mod->name); break; + case MLV_WARNSYNC: case MLV_WARN: if (*mod->name != '*' && strcmp(mod->name, "null") && mod_warnmodels.ival && !previouslyfailed) Con_Printf(CON_ERROR "Unable to load %s\n", mod->name); @@ -1168,6 +1173,9 @@ model_t *Mod_LoadModel (model_t *mod, enum mlverbosity_e verbose) // if (verbose == MLV_ERROR) //if its fatal on failure (ie: world), do it on the main thread and block to wait for it. // Mod_LoadModelWorker(mod, MLV_WARN, 0); // else + if (verbose == MLV_ERROR || verbose == MLV_WARNSYNC) + COM_AddWork(0, Mod_LoadModelWorker, mod, NULL, verbose, 0); + else COM_AddWork(1, Mod_LoadModelWorker, mod, NULL, verbose, 0); } @@ -1689,6 +1697,8 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean COM_FileBase(loadmodel->name, litbase, sizeof(litbase)); for (i = 0; i < sizeof(litnames)/sizeof(litnames[0]); i++) { + if (temp_lit2support.ival && !(i & 1)) + continue; if (strchr(litnames[i], '/')) Q_snprintfz(litname, sizeof(litname), litnames[i], litbase); else diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index a22eaed1c..fd26a5e7d 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -2755,6 +2755,7 @@ static void Sh_DrawStencilLightShadows(dlight_t *dl, qbyte *lvis, qbyte *vvis, q int i; struct shadowmesh_s *sm; entity_t *ent; + model_t *emodel; sm = SHM_BuildShadowMesh(dl, lvis, vvis, SMT_STENCILVOLUME); if (!sm) @@ -2804,25 +2805,37 @@ static void Sh_DrawStencilLightShadows(dlight_t *dl, qbyte *lvis, qbyte *vvis, q { ent = &cl_visedicts[i]; + if (ent->rtype != RT_MODEL) + continue; + if (ent->flags & (RF_NOSHADOW|Q2RF_BEAM)) continue; if (ent->keynum == dl->key && ent->keynum) continue; - if (!ent->model) + emodel = ent->model; + if (!emodel) continue; if (cls.allow_anyparticles) //allowed or static { - if (ent->model->engineflags & MDLF_ENGULPHS) + if (emodel->engineflags & MDLF_ENGULPHS) { if (gl_part_flame.value) continue; } } - switch (ent->model->type) + if (emodel->loadstate == MLS_NOTLOADED) + { + if (!Mod_LoadModel(emodel, MLV_WARN)) + continue; + } + if (emodel->loadstate != MLS_LOADED) + continue; + + switch (emodel->type) { case mod_alias: R_DrawGAliasShadowVolume (ent, dl->origin, dl->radius); @@ -2940,7 +2953,7 @@ static qboolean Sh_DrawStencilLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], } #endif //our stencil writes. - if (gl_config.arb_depth_clamp) + if (gl_config.arb_depth_clamp && gl_maxdist.value != 0) qglEnable(GL_DEPTH_CLAMP_ARB); #if 0 //def _DEBUG diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index 96e6fbd05..b0fd5b868 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -1021,7 +1021,7 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) //certain drivers (*cough* mesa *cough*) update vao0 state even when a different vao is bound. //they also don't support client arrays, so are unusable without glsl or vertex streaming (which is *really* hard to optimise for - especially with webgl etc) //so only use them with gl3+ core contexts where vbo is mandatory anyway. - if (!gl_config.nofixedfunc) + if (!gl_config_nofixedfunc) { //don't bother if we've no glsl qglGenVertexArrays = NULL; @@ -1833,11 +1833,6 @@ static GLhandleARB GLSlang_CreateShader (const char *name, int ver, const char * length[strings] = strlen(prstrings[strings]); strings++; - //prstrings[strings] = "invariant gl_Position;\n"; - //length[strings] = strlen(prstrings[strings]); - //strings++; - - switch (shadertype) { case GL_FRAGMENT_SHADER_ARB: @@ -1884,6 +1879,12 @@ static GLhandleARB GLSlang_CreateShader (const char *name, int ver, const char * prstrings[strings] = "#define VERTEX_SHADER\n"; length[strings] = strlen(prstrings[strings]); strings++; + if (!r_shadow_shadowmapping.ival && ver >= 120) + { + prstrings[strings] = "invariant gl_Position;\n"; + length[strings] = strlen(prstrings[strings]); + strings++; + } if (gl_config.gles) { prstrings[strings] = @@ -1905,7 +1906,7 @@ static GLhandleARB GLSlang_CreateShader (const char *name, int ver, const char * length[strings] = strlen(prstrings[strings]); strings++; } - if (gl_config.nofixedfunc || ver >= 130) + if (gl_config_nofixedfunc || ver >= 130) { prstrings[strings] = "attribute vec3 v_position1;\n" @@ -2029,7 +2030,7 @@ static GLhandleARB GLSlang_FinishShader(GLhandleARB shader, const char *name, GL Con_Printf("%s shader (%s) compilation error:\n----------\n%s----------\n", typedesc, name, str); //if there's no fixed function then failure to compile the default2d shader should be considered fatal. this should help avoid black screens on android. - if (gl_config.nofixedfunc && !strcmp(name, "default2d")) + if (gl_config_nofixedfunc && !strcmp(name, "default2d")) Sys_Error("%s shader (%s) compilation error:\n----------\n%s----------\n", typedesc, name, str); if (developer.ival) @@ -2658,7 +2659,7 @@ void GL_Init(void *(*getglfunction) (char *name)) qglDrawRangeElements = GL_DrawRangeElementsEmul; } - else if (gl_config.nofixedfunc) + else if (gl_config_nofixedfunc) { qglLoadMatrixf = NULL; qglPolygonMode = NULL; @@ -2773,7 +2774,7 @@ void GL_Init(void *(*getglfunction) (char *name)) sh_config.pProgAutoFields = GLSlang_ProgAutoFields; } - if (gl_config.nofixedfunc) + if (gl_config_nofixedfunc) { sh_config.tex_env_combine = 1; sh_config.nv_tex_env_combine4 = 1; diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index f1b03e155..42fe9fef4 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -220,6 +220,12 @@ void QCC_FindBestInclude(char *newfile, char *currentfile, char *rootpath, pbool } } + while (doubledots-- > 0) + { + strcpy(end, "../"); + end += 3; + } + strcpy(end, newfile); if (verbose) diff --git a/engine/qclib/qccgui.c b/engine/qclib/qccgui.c index b1a563753..598149410 100644 --- a/engine/qclib/qccgui.c +++ b/engine/qclib/qccgui.c @@ -4951,6 +4951,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin { {FCONTROL|FVIRTKEY, 'S', IDM_SAVE}, {FCONTROL|FVIRTKEY, 'F', IDM_FIND}, + {FCONTROL|FVIRTKEY, 'G', IDM_GREP}, {FCONTROL|FVIRTKEY, 'R', IDM_RECOMPILE}, // {FVIRTKEY, VK_F4, IDM_NEXTERROR}, {FVIRTKEY, VK_F5, IDM_DEBUG_RUN}, diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 06e2d656a..02299ca1c 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -425,6 +425,7 @@ void PR_SV_FillWorldGlobals(world_t *w) w->g.v_forward = *pr_global_ptrs->v_forward; w->g.v_right = *pr_global_ptrs->v_right; w->g.v_up = *pr_global_ptrs->v_up; + w->g.defaultgravitydir = *pr_global_ptrs->global_gravitydir; } static void PDECL PR_SSQC_Relocated(pubprogfuncs_t *pr, char *oldb, char *newb, int oldlen) @@ -692,6 +693,7 @@ void PR_LoadGlabalStruct(qboolean muted) static float input_impulse_default; static vec3_t input_angles_default; static vec3_t input_movevalues_default; + static vec3_t global_gravitydir_default; int i; int *v; globalptrs_t *pr_globals = pr_global_ptrs; @@ -758,6 +760,7 @@ void PR_LoadGlabalStruct(qboolean muted) globalvec (false, input_movevalues); globalfloat (false, input_buttons); globalint (false, serverid); + globalvec (false, global_gravitydir); memset(&evalc_idealpitch, 0, sizeof(evalc_idealpitch)); memset(&evalc_pitch_speed, 0, sizeof(evalc_pitch_speed)); @@ -782,6 +785,7 @@ void PR_LoadGlabalStruct(qboolean muted) ensureglobal(input_angles, input_angles_default); ensureglobal(input_movevalues, input_movevalues_default); ensureglobal(input_buttons, input_buttons_default); + ensureglobal(global_gravitydir, global_gravitydir_default); // qtest renames and missing variables if (!(pr_globals)->trace_plane_normal) @@ -2452,7 +2456,7 @@ void PF_setmodel_Internal (pubprogfuncs_t *prinst, edict_t *e, const char *m) //qw dedicated servers only load bsps (better) if (mod) { - mod = Mod_ForName (Mod_FixName(m, sv.modelname), MLV_WARN); + mod = Mod_ForName (Mod_FixName(m, sv.modelname), MLV_WARNSYNC); if (mod) { while(mod->loadstate == MLS_LOADING) @@ -3456,8 +3460,10 @@ void PF_stuffcmd_Internal(int entnum, const char *str, unsigned int flags) slen = strlen(str); - SV_StuffcmdToClient(cl, str); + if (!(flags & STUFFCMD_DEMOONLY)) + SV_StuffcmdToClient(cl, str); + if (!(flags & STUFFCMD_IGNOREINDEMO)) if (sv.mvdrecording) { sizebuf_t *msg = MVDWrite_Begin (dem_single, entnum - 1, 2 + slen); @@ -3466,6 +3472,7 @@ void PF_stuffcmd_Internal(int entnum, const char *str, unsigned int flags) } //this seems a little dangerous. v_cshift could leave a spectator's machine unusable if they switch players at unfortunate times. + if (!(flags & STUFFCMD_DEMOONLY)) if (sv_specprint.ival & SPECPRINT_STUFFCMD) { client_t *spec; @@ -3494,6 +3501,11 @@ static void QCBUILTIN PF_stuffcmd (pubprogfuncs_t *prinst, struct globalvars_s * PF_stuffcmd_Internal(G_EDICTNUM(prinst, OFS_PARM0), PR_GetStringOfs(prinst, OFS_PARM1), 0); } +static void QCBUILTIN PF_stuffcmdflags (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + PF_stuffcmd_Internal(G_EDICTNUM(prinst, OFS_PARM0), PR_GetStringOfs(prinst, OFS_PARM2), G_FLOAT(OFS_PARM1)); +} + //DP_QC_DROPCLIENT static void QCBUILTIN PF_dropclient (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -3864,7 +3876,7 @@ int PF_precache_model_Internal (pubprogfuncs_t *prinst, const char *s, qboolean sv.strings.model_precache[i] = PR_AddString(prinst, s, 0, false); s = sv.strings.model_precache[i]; if (!strcmp(s + strlen(s) - 4, ".bsp") || sv_gameplayfix_setmodelrealbox.ival) - sv.models[i] = Mod_ForName(Mod_FixName(s, sv.modelname), MLV_WARN); + sv.models[i] = Mod_ForName(Mod_FixName(s, sv.modelname), MLV_WARNSYNC); else { /*touch the file, so any packs will be referenced*/ @@ -5371,11 +5383,22 @@ char *PF_infokey_Internal (int entnum, const char *key) { value = ov; if (!strcmp(key, "ip")) - NET_BaseAdrToString (ov, sizeof(ov), &svs.clients[entnum-1].netchan.remote_address); + { + if (svs.clients[entnum-1].state > cs_zombie && svs.clients[entnum-1].protocol == SCP_BAD) + sprintf(ov, "bot"); //bots don't have valid ips + else if (svs.clients[entnum-1].netchan.remote_address.type == NA_INVALID) + sprintf(ov, ""); //bots don't have valid ips + else + NET_BaseAdrToString (ov, sizeof(ov), &svs.clients[entnum-1].netchan.remote_address); + } else if (!strcmp(key, "realip")) { - if (svs.clients[entnum-1].realip_status) + if (svs.clients[entnum-1].state > cs_zombie && svs.clients[entnum-1].protocol == SCP_BAD) + sprintf(ov, "bot"); //bots don't have valid ips + else if (svs.clients[entnum-1].realip_status) NET_BaseAdrToString (ov, sizeof(ov), &svs.clients[entnum-1].realip); + else if (svs.clients[entnum-1].netchan.remote_address.type == NA_INVALID) + sprintf(ov, ""); //bots don't have valid ips else //FIXME: should we report the spoofable/proxy address if the real ip is not known? NET_BaseAdrToString (ov, sizeof(ov), &svs.clients[entnum-1].netchan.remote_address); } @@ -6017,7 +6040,7 @@ static void QCBUILTIN PF_checkextension (pubprogfuncs_t *prinst, struct globalva } else if (!PR_EnableEBFSBuiltin(ext->builtinnames[i], 0)) { - Con_Printf("Failed to initialise builtin \"%s\" for extension \"%s\"", ext->builtinnames[i], s); + Con_Printf("Failed to initialise builtin \"%s\" for extension \"%s\"\n", ext->builtinnames[i], s); return; //whoops, we failed. } } @@ -8491,7 +8514,13 @@ int PF_ForceInfoKey_Internal(unsigned int entnum, const char *key, const char *v } else if (entnum <= sv.allocated_client_slots) { //woo. we found a client. - char *oldvalue = Info_ValueForKey(svs.clients[entnum-1].userinfo, key); + char *oldvalue; + if (svs.clients[entnum-1].state == cs_free) + { + Con_DPrintf("PF_ForceInfoKey: inactive client\n"); + return 0; + } + oldvalue = Info_ValueForKey(svs.clients[entnum-1].userinfo, key); if (strcmp(oldvalue, value)) { Info_SetValueForStarKey(svs.clients[entnum-1].userinfo, key, value, sizeof(svs.clients[entnum-1].userinfo)); @@ -8622,7 +8651,7 @@ static void QCBUILTIN PF_ShowPic(pubprogfuncs_t *prinst, struct globalvars_s *pr { //to a single client entnum = G_EDICTNUM(prinst, OFS_PARM5)-1; if (entnum < 0 || entnum >= sv.allocated_client_slots) - PR_RunError (prinst, "WriteDest: not a client"); + PR_RunError (prinst, "PF_ShowPic: not a client"); if (!(svs.clients[entnum].fteprotocolextensions & PEXT_SHOWPIC)) return; //need an extension for this. duh. @@ -8655,7 +8684,7 @@ static void QCBUILTIN PF_HidePic(pubprogfuncs_t *prinst, struct globalvars_s *pr { //to a single client entnum = G_EDICTNUM(prinst, OFS_PARM1)-1; if (entnum < 0 || entnum >= sv.allocated_client_slots) - PR_RunError (prinst, "WriteDest: not a client"); + PR_RunError (prinst, "PF_HidePic: not a client"); if (!(svs.clients[entnum].fteprotocolextensions & PEXT_SHOWPIC)) return; //need an extension for this. duh. @@ -8690,7 +8719,7 @@ static void QCBUILTIN PF_MovePic(pubprogfuncs_t *prinst, struct globalvars_s *pr { //to a single client entnum = G_EDICTNUM(prinst, OFS_PARM4)-1; if (entnum < 0 || entnum >= sv.allocated_client_slots) - PR_RunError (prinst, "WriteDest: not a client"); + PR_RunError (prinst, "PF_MovePic: not a client"); if (!(svs.clients[entnum].fteprotocolextensions & PEXT_SHOWPIC)) return; //need an extension for this. duh. @@ -8723,7 +8752,7 @@ static void QCBUILTIN PF_ChangePic(pubprogfuncs_t *prinst, struct globalvars_s * { //to a single client entnum = G_EDICTNUM(prinst, OFS_PARM2)-1; if (entnum < 0 || entnum >= sv.allocated_client_slots) - PR_RunError (prinst, "WriteDest: not a client"); + PR_RunError (prinst, "PF_ChangePic: not a client"); if (!(svs.clients[entnum].fteprotocolextensions & PEXT_SHOWPIC)) return; //need an extension for this. duh. @@ -9313,6 +9342,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"precache_sound", PF_precache_sound, 19, 19, 19, 0, D("string(string s)", "Precaches a sound, making it known to clients and loading it from disk. This builtin (strongly) should be called during spawn functions. This builtin must be called for the sound before the sound builtin is called, or it might not even be heard.")}, {"precache_model", PF_precache_model, 20, 20, 20, 0, D("string(string s)", "Precaches a model, making it known to clients and loading it from disk if it has a .bsp extension. This builtin (strongly) should be called during spawn functions. This must be called for each model name before setmodel may use that model name.\nModelindicies precached in SSQC will always be positive. CSQC precaches will be negative if they are not also on the server.")}, {"stuffcmd", PF_stuffcmd, 21, 21, 21, 0, D("void(entity client, string s)", "Sends a console command (or cvar) to the client, where it will be executed. Different clients support different commands. Do NOT forget the final \\n.\nThis builtin is generally considered evil.")}, + {"stuffcmdflags", PF_stuffcmdflags, 0, 0, 0, 0, D("void(entity client, float flags, string s)", "Sends a console command (or cvar) to the client, where it will be executed. Different clients support different commands. Do NOT forget the final \\n.\nThis (just as evil) variant allows specifying some flags too. See the STUFFCMD_* constants.")}, {"findradius", PF_findradius, 22, 22, 22, 0, D("entity(vector org, float rad)", "Finds all entities within a distance of the 'org' specified. One entity is returned directly, while other entities are returned via that entity's .chain field.")}, //both bprint and sprint accept different arguments in QW vs NQ/H2 {"bprint", PF_bprint, 23, 0, 23, 0, D("void(string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8)", "NQ: Concatenates all arguments, and prints the messsage on the console of all connected clients.")}, @@ -10155,7 +10185,7 @@ static void QCBUILTIN PF_Fixme (pubprogfuncs_t *prinst, struct globalvars_s *pr_ Con_Printf("\n"); - if (progstype == PROG_QW) + if (progstype == PROG_QW && (binum >= 83 && binum < 105)) prinst->RunError(prinst, "\nBuiltin %i:%s not implemented.\nMods designed for mvdsv may need pr_imitatemvdsv to be enabled.", binum, fname); else prinst->RunError(prinst, "\nBuiltin %i:%s not implemented.\nMod is not compatible.", binum, fname); @@ -10851,6 +10881,7 @@ void PR_DumpPlatform_f(void) {"SOLID_BSP", "const float", QW|NQ|CS, "Does not collide against other SOLID_BSP entities. Normally paired with MOVETYPE_PUSH.", SOLID_BSP}, {"SOLID_CORPSE", "const float", QW|NQ|CS, "Non-solid to SOLID_SLIDEBOX or other SOLID_CORPSE entities. For hitscan weapons to hit corpses, change the player's .solid value to SOLID_BBOX or so, perform the traceline, then revert the player's .solid value.", SOLID_CORPSE}, {"SOLID_LADDER", "const float", QW|NQ|CS, "Obsolete and may be removed at some point. Use skin=CONTENT_LADDER and solid_bsp or solid_trigger instead.", SOLID_LADDER}, + {"SOLID_PORTAL", "const float", QW|NQ|CS, "CSG subtraction volume combined with entity transformations on impact.", SOLID_PORTAL}, {"SOLID_PHYSICS_BOX", "const float", QW|NQ|CS, NULL, SOLID_PHYSICS_BOX}, {"SOLID_PHYSICS_SPHERE", "const float", QW|NQ|CS, NULL, SOLID_PHYSICS_SPHERE}, {"SOLID_PHYSICS_CAPSULE", "const float", QW|NQ|CS, NULL, SOLID_PHYSICS_CAPSULE}, @@ -11000,6 +11031,14 @@ void PR_DumpPlatform_f(void) {"SERVERKEY_PROTOCOL", "const string", CS, "The protocol we are connected to the server with.", 0, "\"protocol\""}, {"SERVERKEY_MAXPLAYERS","const string", CS, "The protocol we are connected to the server with.", 0, "\"maxplayers\""}, + {"STUFFCMD_IGNOREINDEMO","const float", QW|NQ, "The protocol we are connected to the server with.", STUFFCMD_IGNOREINDEMO}, + {"STUFFCMD_DEMOONLY", "const float", QW|NQ, "The protocol we are connected to the server with.", STUFFCMD_DEMOONLY}, + + {"SOUND_RELIABLE", "const float", QW|NQ, "The sound will be sent reliably, and without regard to phs.", CF_RELIABLE}, + {"SOUND_FORCELOOP", "const float", QW|NQ|CS,"The sound will restart once it reaches the end of the sample.", CF_FORCELOOP}, + {"SOUND_NOSPACIALISE", "const float", QW|NQ|CS,"The different audio channels are played at the same volume regardless of which way the player is facing, without needing to use 0 attenuation.", CF_NOSPACIALISE}, + {"SOUND_ABSVOLUME", "const float", QW|NQ|CS,"The sample's volume is not scaled by the volume cvar. Use with caution", CF_ABSVOLUME}, + // edict.flags {"FL_FLY", "const float", QW|NQ|CS, NULL, FL_FLY}, {"FL_SWIM", "const float", QW|NQ|CS, NULL, FL_SWIM}, diff --git a/engine/server/pr_lua.c b/engine/server/pr_lua.c index 64ec850dd..499d0deaf 100644 --- a/engine/server/pr_lua.c +++ b/engine/server/pr_lua.c @@ -744,7 +744,7 @@ static int bi_lua_stuffcmd(lua_State *L) entnum = lua.tointegerx(L, -1, NULL); str = lua.tolstring(L, 2, NULL); - PF_stuffcmd_Internal(entnum, str); + PF_stuffcmd_Internal(entnum, str, 0); return 0; } static int bi_lua_centerprint(lua_State *L) diff --git a/engine/server/pr_q1qvm.c b/engine/server/pr_q1qvm.c index eadbd408e..3341222ac 100755 --- a/engine/server/pr_q1qvm.c +++ b/engine/server/pr_q1qvm.c @@ -1757,10 +1757,12 @@ void QDECL Q1QVMPF_SetStringField(pubprogfuncs_t *progfuncs, struct edict_s *ed, qboolean PR_LoadQ1QVM(void) { + static int writable_int; static float writable; static float dimensionsend = 255; static float dimensiondefault = 255; static float physics_mode = 2; + static vec3_t defaultgravity = {0,0,-1}; int i; gameDataN_t *gd, gdm; gameData32_t *gd32; @@ -1923,6 +1925,15 @@ qboolean PR_LoadQ1QVM(void) pr_global_ptrs->dimension_default = &dimensiondefault; pr_global_ptrs->dimension_send = &dimensionsend; pr_global_ptrs->physics_mode = &physics_mode; + pr_global_ptrs->trace_brush_id = &writable_int; + pr_global_ptrs->trace_brush_faceid = &writable_int; + pr_global_ptrs->global_gravitydir = &defaultgravity; + +// ensureglobal(input_timelength, input_timelength_default); +// ensureglobal(input_impulse, input_impulse_default); +// ensureglobal(input_angles, input_angles_default); +// ensureglobal(input_movevalues, input_movevalues_default); +// ensureglobal(input_buttons, input_buttons_default); dimensionsend = dimensiondefault = 255; for (i = 0; i < 16; i++) diff --git a/engine/server/progdefs.h b/engine/server/progdefs.h index 5c495190e..a381ffb01 100644 --- a/engine/server/progdefs.h +++ b/engine/server/progdefs.h @@ -93,6 +93,7 @@ typedef struct nqglobalvars_s vec3_t *input_angles; vec3_t *input_movevalues; float *input_buttons; + vec3_t *global_gravitydir; float *spawnparamglobals[NUM_SPAWN_PARMS]; int *serverid; } globalptrs_t; diff --git a/engine/server/server.h b/engine/server/server.h index b8cfe1798..ac4b9fc05 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -381,6 +381,9 @@ enum #define SPECPRINT_SPRINT 0x2 #define SPECPRINT_STUFFCMD 0x4 +#define STUFFCMD_IGNOREINDEMO ( 1<<0) // do not put in mvd demo +#define STUFFCMD_DEMOONLY ( 1<<1) // put in mvd demo only + typedef struct client_s { client_conn_state_t state; @@ -748,18 +751,23 @@ typedef struct //============================================================================= - -#define STATFRAMES 100 +#define SVSTATS_PERIOD 10 typedef struct { double active; double idle; int count; int packets; + double maxresponse; //longest (active) frame time within the current period + int maxpackets; //max packet count in a single frame - double latched_active; + double latched_time; //time that the current period ends + double latched_active; //active time in the last period double latched_idle; + int latched_count; int latched_packets; + int latched_maxpackets; + double latched_maxresponse; } svstats_t; // MAX_CHALLENGES is made large to prevent a denial diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index 6c8ce3aa1..2529c105f 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -1699,7 +1699,7 @@ static void SV_Status_f (void) { int i; client_t *cl; - float cpu, avg, pak; + float cpu; char *s, *p; char adr[MAX_ADR_SIZE]; float pi, po, bi, bo; @@ -1728,12 +1728,10 @@ static void SV_Status_f (void) cpu = (svs.stats.latched_active+svs.stats.latched_idle); if (cpu) cpu = 100*svs.stats.latched_active/cpu; - avg = 1000*svs.stats.latched_active / STATFRAMES; - pak = (float)svs.stats.latched_packets/ STATFRAMES; Con_Printf("cpu utilization : %3i%%\n",(int)cpu); - Con_Printf("avg response time: %i ms\n",(int)avg); - Con_Printf("packets/frame : %5.2f\n", pak); //not relevent as a limit. + Con_Printf("avg response time: %i ms (%i max)\n",(int)(1000*svs.stats.latched_active/svs.stats.latched_count), (int)(1000*svs.stats.latched_maxresponse)); + Con_Printf("packets/frame : %5.2f (%i max)\n", (float)svs.stats.latched_packets/svs.stats.latched_count, svs.stats.latched_maxpackets); //not relevent as a limit. if (NET_GetRates(svs.sockets, &pi, &po, &bi, &bo)) Con_Printf("packets,bytes/sec: in: %g %g out: %g %g\n", pi, bi, po, bo); //not relevent as a limit. Con_Printf("server uptime : %s\n", ShowTime(realtime)); diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index 7e92b9eb3..2efbb1af6 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -2010,9 +2010,9 @@ void SV_WritePlayerToClient(sizebuf_t *msg, clstate_t *ent) else { memset(&cmd, 0, sizeof(cmd)); - cmd.angles[0] = (int)(ent->angles[0] * 65535/360.0f); - cmd.angles[1] = (int)(ent->angles[1] * 65535/360.0f); - cmd.angles[2] = (int)(ent->angles[2] * 65535/360.0f); + cmd.angles[0] = (short)(ent->angles[0] * 65535/360.0f); + cmd.angles[1] = (short)(ent->angles[1] * 65535/360.0f); + cmd.angles[2] = (short)(ent->angles[2] * 65535/360.0f); } if (ent->health <= 0) @@ -2035,7 +2035,7 @@ void SV_WritePlayerToClient(sizebuf_t *msg, clstate_t *ent) { for (i=0 ; i<3 ; i++) if (pflags & (PF_VELOCITY1<velocity[i]); + MSG_WriteShort (msg, (short)(ent->velocity[i])); } else { @@ -3055,11 +3055,26 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli state->lightpflags = ent->xv->pflags; state->u.q1.traileffectnum = ent->xv->traileffectnum; - if ((!ent->xv->gravitydir[0] && !ent->xv->gravitydir[1] && !ent->xv->gravitydir[2]) || (ent->xv->gravitydir[2] == -1)) + if (ent->xv->gravitydir[2] == -1) { state->u.q1.gravitydir[0] = 0; state->u.q1.gravitydir[1] = 0; } + else if ((!ent->xv->gravitydir[0] && !ent->xv->gravitydir[1] && !ent->xv->gravitydir[2]))// || (ent->xv->gravitydir[2] == -1)) + { + vec3_t ang; + if (sv.world.g.defaultgravitydir[2] == -1) + { + state->u.q1.gravitydir[0] = 0; + state->u.q1.gravitydir[1] = 0; + } + else + { + vectoangles(sv.world.g.defaultgravitydir, ang); + state->u.q1.gravitydir[0] = ((ang[0]/360) * 256) - 192; + state->u.q1.gravitydir[1] = (ang[1]/360) * 256; + } + } else { vec3_t ang; diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 5b9707e52..91d099b5c 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -1858,6 +1858,7 @@ void SV_ClientProtocolExtensionsChanged(client_t *client) ptr += sizeof(*client->frameunion.frames[i].resendentnum)*maxents; client->frameunion.frames[i].resendentbits = (void*)ptr; ptr += sizeof(*client->frameunion.frames[i].resendentbits)*maxents; + client->frameunion.frames[i].senttime = realtime; } //make sure the reset is sent. @@ -1870,6 +1871,7 @@ void SV_ClientProtocolExtensionsChanged(client_t *client) { client->frameunion.frames[i].entities.max_entities = maxpacketentities; client->frameunion.frames[i].entities.entities = (entity_state_t*)(client->frameunion.frames+UPDATE_BACKUP) + i*client->frameunion.frames[i].entities.max_entities; + client->frameunion.frames[i].senttime = realtime; } } break; @@ -4116,6 +4118,7 @@ SV_GetConsoleCommands Add them exactly as if they had been typed at the console =================== */ +qboolean QCExternalDebuggerCommand(char *text); void SV_GetConsoleCommands (void) { char *cmd; @@ -4125,8 +4128,11 @@ void SV_GetConsoleCommands (void) cmd = Sys_ConsoleInput (); if (!cmd) break; + if (QCExternalDebuggerCommand(cmd)) + continue; Log_String(LOG_CONSOLE, cmd); Cbuf_AddText (cmd, RESTRICT_LOCAL); + Cbuf_AddText ("\n", RESTRICT_LOCAL); } } @@ -4309,18 +4315,19 @@ float SV_Frame (void) { extern cvar_t pr_imitatemvdsv; static double start, end, idletime; + static int oldpackets; float oldtime; qboolean isidle; static int oldpaused; float timedelta; float delay; - COM_MainThreadWork(); - start = Sys_DoubleTime (); svs.stats.idle += start - end; end = start; + COM_MainThreadWork(); + //qw qc uses this for newmis handling svs.framenum++; if (svs.framenum > 0x10000) @@ -4564,16 +4571,28 @@ void SV_MVDStream_Poll(void); // collect timing statistics end = Sys_DoubleTime (); svs.stats.active += end-start; - if (++svs.stats.count == STATFRAMES) + if (svs.stats.maxresponse < end-start) + svs.stats.maxresponse = end-start; + if (svs.stats.maxpackets < svs.stats.packets-oldpackets) + svs.stats.maxpackets = svs.stats.packets-oldpackets; + svs.stats.count++; + if (svs.stats.latched_time < end) { svs.stats.latched_active = svs.stats.active; svs.stats.latched_idle = svs.stats.idle; svs.stats.latched_packets = svs.stats.packets; + svs.stats.latched_count = svs.stats.count; + svs.stats.latched_maxpackets = svs.stats.maxpackets; + svs.stats.latched_maxresponse = svs.stats.maxresponse; + svs.stats.latched_time = end + SVSTATS_PERIOD; svs.stats.active = 0; svs.stats.idle = 0; svs.stats.packets = 0; svs.stats.count = 0; + svs.stats.maxresponse = 0; + svs.stats.maxpackets = 0; } + oldpackets = svs.stats.packets; return delay; } diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index 92fbe5bcf..c26327252 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -790,7 +790,7 @@ void SV_MVD_FullClientUpdate(sizebuf_t *msg, client_t *player) msg = MVDWrite_Begin (dem_all, 0, 4); MSG_WriteByte (msg, svc_updateping); MSG_WriteByte (msg, player - svs.clients); - MSG_WriteShort (msg, SV_CalcPing(player, false)); + MSG_WriteShort (msg, SV_CalcPing(player, false)&0xffff); if (dosizes) msg = MVDWrite_Begin (dem_all, 0, 3); @@ -1191,7 +1191,7 @@ qboolean SV_MVDWritePackets (int num) MSG_WriteByte (&msg, cl->info.skinnum); if (flags & DF_EFFECTS) - MSG_WriteByte (&msg, cl->info.effects); + MSG_WriteByte (&msg, cl->info.effects & 0xff); if (flags & DF_WEAPONFRAME) MSG_WriteByte (&msg, cl->info.weaponframe); diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index cdd297614..1942beb91 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -94,7 +94,6 @@ void WPhys_Init(void) #define MOVE_EPSILON 0.01 static void WPhys_Physics_Toss (world_t *w, wedict_t *ent); -const vec3_t standardgravity = {0, 0, -1}; // warning: ‘SV_CheckAllEnts’ defined but not used /* @@ -1295,7 +1294,7 @@ static void WPhys_Physics_Toss (world_t *w, wedict_t *ent) if (ent->xv->gravitydir[2] || ent->xv->gravitydir[1] || ent->xv->gravitydir[0]) gravitydir = ent->xv->gravitydir; else - gravitydir = standardgravity; + gravitydir = w->g.defaultgravitydir; // if onground, return without moving if ( ((int)ent->v->flags & FL_ONGROUND) ) @@ -1426,7 +1425,7 @@ static void WPhys_Physics_Step (world_t *w, wedict_t *ent) if (ent->xv->gravitydir[2] || ent->xv->gravitydir[1] || ent->xv->gravitydir[0]) gravitydir = ent->xv->gravitydir; else - gravitydir = standardgravity; + gravitydir = w->g.defaultgravitydir; if (-DotProduct(gravitydir, ent->v->velocity) >= (1.0 / 32.0) && (fl & FL_ONGROUND)) { @@ -2153,7 +2152,7 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent) if (ent->xv->gravitydir[2] || ent->xv->gravitydir[1] || ent->xv->gravitydir[0]) gravitydir = ent->xv->gravitydir; else - gravitydir = standardgravity; + gravitydir = w->g.defaultgravitydir; if (!WPhys_CheckWater (w, ent) && ! ((int)ent->v->flags & FL_WATERJUMP) ) WPhys_AddGravity (w, ent, gravitydir, ent->xv->gravity); @@ -2283,6 +2282,14 @@ void World_Physics_Frame(world_t *w) wedict_t *ent; extern cvar_t sv_nqplayerphysics; + if (w->g.defaultgravitydir) + { + w->g.defaultgravitydir[0] = 0; + w->g.defaultgravitydir[1] = 0; + w->g.defaultgravitydir[2] = -1; + VectorNormalize(w->g.defaultgravitydir); + } + w->framenum++; i = *w->g.physics_mode; @@ -2456,9 +2463,9 @@ qboolean SV_Physics (void) SV_PreRunCmd(); ucmd.msec = ms; - ucmd.angles[0] = (int)(sv_player->v->v_angle[0] * (65535/360.0f)); - ucmd.angles[1] = (int)(sv_player->v->v_angle[1] * (65535/360.0f)); - ucmd.angles[2] = (int)(sv_player->v->v_angle[2] * (65535/360.0f)); + ucmd.angles[0] = (short)(sv_player->v->v_angle[0] * (65535/360.0f)); + ucmd.angles[1] = (short)(sv_player->v->v_angle[1] * (65535/360.0f)); + ucmd.angles[2] = (short)(sv_player->v->v_angle[2] * (65535/360.0f)); ucmd.forwardmove = sv_player->xv->movement[0]; ucmd.sidemove = sv_player->xv->movement[1]; ucmd.upmove = sv_player->xv->movement[2]; diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index c6b5e62c4..7125502ed 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -932,19 +932,39 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int if (sv.mvdrecording && ((demo.recorder.fteprotocolextensions & with) == with) && !(demo.recorder.fteprotocolextensions & without)) { sizebuf_t *msg; - if (!mask) + + switch(to) { - /*no distinction between reliable or not*/ - msg = MVDWrite_Begin(dem_single, pnum, sv.multicast.cursize); - } - else - { - if (reliable) + //mvds have no idea where the receiver's camera will be. + //as such, they cannot have any support for pvs/phs + case MULTICAST_INIT: + default: + case MULTICAST_ALL_R: + case MULTICAST_PHS_R: + case MULTICAST_PVS_R: + msg = MVDWrite_Begin(dem_all, 0, sv.multicast.cursize); + break; + case MULTICAST_ALL: + case MULTICAST_PHS: + case MULTICAST_PVS: + msg = &demo.datagram; + break; + + //mvds are all reliables really. + case MULTICAST_ONE_R: + case MULTICAST_ONE: + if (svprogfuncs) { - msg = MVDWrite_Begin(dem_all, 0, sv.multicast.cursize); + edict_t *ent = PROG_TO_EDICT(svprogfuncs, pr_global_struct->msg_entity); + pnum = NUM_FOR_EDICT(svprogfuncs, ent) - 1; } else - msg = &demo.datagram; + { + pnum = 0; //FIXME + Con_Printf("SV_MulticastProtExt: unsupported unicast\n"); + } + msg = MVDWrite_Begin(dem_single, pnum, sv.multicast.cursize); + break; } SZ_Write(msg, sv.multicast.data, sv.multicast.cursize); } diff --git a/engine/server/sv_sys_win.c b/engine/server/sv_sys_win.c index 616369eba..7ad55ed20 100644 --- a/engine/server/sv_sys_win.c +++ b/engine/server/sv_sys_win.c @@ -37,6 +37,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static HANDLE hconsoleout; +extern int isPlugin; //if 2, we qcdebug to external program qboolean WinNT; //if true, use utf-16 file paths. if false, hope that paths are in ascii. @@ -1358,7 +1359,10 @@ void Sys_Init (void) Cmd_AddCommand("hide", Sys_HideConsole); - hconsoleout = GetStdHandle(STD_OUTPUT_HANDLE); + if (isPlugin) + hconsoleout = CreateFileA("CONOUT$",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,0,0); + else + hconsoleout = GetStdHandle(STD_OUTPUT_HANDLE); // SetConsoleCP(CP_UTF8); // SetConsoleOutputCP(CP_UTF8); @@ -1386,6 +1390,7 @@ void StartQuakeServer(void) { quakeparms_t parms; static char bindir[MAX_OSPATH]; + int c; memset(&parms, 0, sizeof(parms)); @@ -1400,6 +1405,23 @@ void StartQuakeServer(void) TL_InitLanguages(parms.basedir); + c = COM_CheckParm("-qcdebug"); + if (c) + isPlugin = 3; + else + { + c = COM_CheckParm("-plugin"); + if (c) + { + if (c < com_argc && !strcmp(com_argv[c+1], "qcdebug")) + isPlugin = 2; + else + isPlugin = 1; + } + else + isPlugin = 0; + } + SV_Init (&parms); // run one frame immediately for first heartbeat diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index db870a80a..eb39b3138 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -2012,8 +2012,8 @@ void SV_DarkPlacesDownloadChunk(client_t *cl, sizebuf_t *msg) size = 1024; //fixme - if (size > cl->datagram.maxsize - cl->datagram.cursize) - size = cl->datagram.maxsize - cl->datagram.cursize - 16; + if (size > msg->maxsize - msg->cursize) + size = msg->maxsize - msg->cursize - 16; if (size > MAXDPDOWNLOADCHUNK) //don't clog it too much size = MAXDPDOWNLOADCHUNK; @@ -2843,6 +2843,7 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam vfsfile_t *f = FS_OpenVFS(name+8, "rb", FS_ROOT); if (f) { + loc->len = VFS_GETLEN(f); VFS_CLOSE(f); return -5; //found package } @@ -6533,7 +6534,11 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse) pmove.player_maxs[1] = sv_player->v->maxs[1]; pmove.player_maxs[2] = sv_player->v->maxs[2]; - VectorCopy(sv_player->xv->gravitydir, pmove.gravitydir); + if (sv_player->xv->gravitydir[2] || sv_player->xv->gravitydir[1] || sv_player->xv->gravitydir[0]) + VectorCopy(sv_player->xv->gravitydir, pmove.gravitydir); + else + VectorCopy(sv.world.g.defaultgravitydir, pmove.gravitydir); + VectorCopy(sv_player->v->origin, pmove.origin); VectorCopy(sv_player->v->oldorigin, pmove.safeorigin); pmove.safeorigin_known = true; diff --git a/engine/server/world.c b/engine/server/world.c index 3f7b79e71..cd2b9d500 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -1976,7 +1976,12 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e if (touch == clip.passedict) continue; if (touch->v->solid == SOLID_TRIGGER || touch->v->solid == SOLID_LADDER) - Host_Error ("Trigger (%s) in clipping list", PR_GetString(w->progs, touch->v->classname)); + { + if (!(clip.type & MOVE_TRIGGERS)) + continue; + if (!((int)touch->v->flags & FL_FINDABLE_NONSOLID)) + continue; + } if (clip.type & MOVE_NOMONSTERS && touch->v->solid != SOLID_BSP) continue; diff --git a/plugins/ezhud/ezhud.vcproj b/plugins/ezhud/ezhud.vcproj index 42e228c67..91db2e61d 100644 --- a/plugins/ezhud/ezhud.vcproj +++ b/plugins/ezhud/ezhud.vcproj @@ -174,24 +174,10 @@ - - - - - - value; + if (size >= 120) + sb_lines = 0; // no status bar at all + else if (size >= 110) + sb_lines = 24; // no inventory + else + sb_lines = 24 + 16 + 8; + } + + //cl.faceanimtime //cl.simvel //cl.item_gettime diff --git a/plugins/ezhud/ezquakeisms.h b/plugins/ezhud/ezquakeisms.h index 942ffe7bd..b9f046727 100644 --- a/plugins/ezhud/ezquakeisms.h +++ b/plugins/ezhud/ezquakeisms.h @@ -129,10 +129,9 @@ char *TP_ItemName(unsigned int itbit); void Replace_In_String(char *string, size_t strsize, char leadchar, int patterns, ...); static qbool Utils_RegExpMatch(char *regexp, char *term) {return true;} -#define strlen_color strlen #define clamp(v,min,max) v=bound(min,v,max) - +#define strlen_color(line) (pDraw_StringWidth(8, 0, line)/8.0) #define TIMETYPE_CLOCK 0 #define TIMETYPE_GAMECLOCK 1 diff --git a/plugins/ezhud/hud_common.c b/plugins/ezhud/hud_common.c index 682f1f605..79d0309fb 100644 --- a/plugins/ezhud/hud_common.c +++ b/plugins/ezhud/hud_common.c @@ -796,7 +796,6 @@ void SCR_HUD_DrawClock(hud_t *hud) // draw HUD notify // -#ifdef HAXX static void SCR_HUD_DrawNotify(hud_t* hud) { static cvar_t* hud_notify_rows = NULL; @@ -817,15 +816,20 @@ static void SCR_HUD_DrawNotify(hud_t* hud) hud_notify_time = HUD_FindVar(hud, "time"); } - height = Q_rint((con_linewidth / hud_notify_cols->ival) * hud_notify_rows->ival * 8 * hud_notify_scale->value); + height = hud_notify_rows->ival * 8 * hud_notify_scale->value; width = 8 * hud_notify_cols->ival * hud_notify_scale->value; if (HUD_PrepareDraw(hud, width, height, &x, &y)) { - SCR_DrawNotify(x, y, hud_notify_scale->value, hud_notify_time->ival, hud_notify_rows->ival, hud_notify_cols->ival); + pCvar_SetFloat("con_notify_x", (float)x / vid.width); + pCvar_SetFloat("con_notify_y", (float)y / vid.height); + pCvar_SetFloat("con_notify_w", (float)width / vid.width); + pCvar_SetFloat("con_numnotifylines",(int)(height/(8*hud_notify_scale->value) + 0.01)); + pCvar_SetFloat("con_notifytime", (float)hud_notify_time->ival); + pCvar_SetFloat("con_textsize", 8.0 * hud_notify_scale->value); +// SCR_DrawNotify(x, y, hud_notify_scale->value, hud_notify_time->ival, hud_notify_rows->ival, hud_notify_cols->ival); } } -#endif //--------------------- // @@ -2253,11 +2257,71 @@ void SCR_HUD_DrawArmor(hud_t *hud) scale->value, style->value, digits->value, align->string); } -void Draw_AMFStatLoss (int stat, hud_t* hud); -#if HAXX +//void Draw_AMFStatLoss (int stat, hud_t* hud); +static int vxdamagecount, vxdamagecount_time, vxdamagecount_oldhealth; +static int vxdamagecountarmour, vxdamagecountarmour_time, vxdamagecountarmour_oldhealth; +void Amf_Reset_DamageStats(void) +{ + vxdamagecount = vxdamagecount_time = vxdamagecount_oldhealth = 0; + vxdamagecountarmour = vxdamagecountarmour_time = vxdamagecountarmour_oldhealth = 0; +} +void Draw_AMFStatLoss (int stat, hud_t* hud) { + //fixme: should reset these on pov change + int * vxdmgcnt, * vxdmgcnt_t, * vxdmgcnt_o; + int x; + float alpha; + int elem; + + if (stat == STAT_HEALTH) { + vxdmgcnt = &vxdamagecount; + vxdmgcnt_t = &vxdamagecount_time; + vxdmgcnt_o = &vxdamagecount_oldhealth; + x = 136; + elem = 0; + } else { + vxdmgcnt = &vxdamagecountarmour; + vxdmgcnt_t = &vxdamagecountarmour_time; + vxdmgcnt_o = &vxdamagecountarmour_oldhealth; + x = 24; + elem = 1; + } + + //VULT STAT LOSS + //Pretty self explanitory, I just thought it would be a nice feature to go with my "what the hell is going on?" theme + //and obscure even more of the screen + if (cl.stats[stat] < (*vxdmgcnt_o - 1)) + { + if (*vxdmgcnt_t > cl.time) //add to damage + *vxdmgcnt = *vxdmgcnt + (*vxdmgcnt_o - cl.stats[stat]); + else + *vxdmgcnt = *vxdmgcnt_o - cl.stats[stat]; + *vxdmgcnt_t = cl.time + 2 * (HUD_FindVar(hud, "duration")->value); + } + *vxdmgcnt_o = cl.stats[stat]; + + if (*vxdmgcnt_t > cl.time) + alpha = min(1, (*vxdmgcnt_t - cl.time)); + else + alpha = 0; + + pDraw_Colour4f(1,1,1,alpha); + { + static cvar_t *scale[2] = {NULL}, *style[2], *digits[2], *align[2]; + if (scale[elem] == NULL) // first time called + { + scale[elem] = HUD_FindVar(hud, "scale"); + style[elem] = HUD_FindVar(hud, "style"); + digits[elem] = HUD_FindVar(hud, "digits"); + align[elem] = HUD_FindVar(hud, "align"); + } + SCR_HUD_DrawNum (hud, abs(*vxdmgcnt), 1, + scale[elem]->value, style[elem]->value, digits[elem]->ival, align[elem]->string); + } + pDraw_Colour4f(1,1,1,1); +} + static void SCR_HUD_DrawHealthDamage(hud_t *hud) { - // TODO: This is very naughty, HUD_PrepareDraw(hud, width, height, &x, &y); MUST be called. Draw_AMFStatLoss (STAT_HEALTH, hud); if (HUD_Stats(STAT_HEALTH) <= 0) { @@ -2267,10 +2331,8 @@ static void SCR_HUD_DrawHealthDamage(hud_t *hud) static void SCR_HUD_DrawArmorDamage(hud_t *hud) { - // TODO: NAUGHTY!! HUD_PrepareDraw(hud, width, height, &x, &y); plz Draw_AMFStatLoss (STAT_ARMOR, hud); } -#endif void SCR_HUD_DrawAmmo(hud_t *hud, int num, float scale, int style, int digits, char *s_align) @@ -5760,18 +5822,18 @@ void SCR_HUD_DrawScoresTeam(hud_t *hud) void SCR_HUD_DrawScoresEnemy(hud_t *hud) { - static cvar_t *scale = NULL, *style, *digits, *align, *colorize; + static cvar_t *scale = NULL, *style, *digits, *align, *colorize; int value = 0; int i; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - digits = HUD_FindVar(hud, "digits"); - align = HUD_FindVar(hud, "align"); + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + digits = HUD_FindVar(hud, "digits"); + align = HUD_FindVar(hud, "align"); colorize = HUD_FindVar(hud, "colorize"); - } + } // // AAS: voodoo, again @@ -5806,23 +5868,23 @@ void SCR_HUD_DrawScoresEnemy(hud_t *hud) } } - SCR_HUD_DrawNum(hud, value, (colorize->ival) ? (value < 0 || colorize->ival > 1) : false, scale->value, style->value, digits->value, align->string); + SCR_HUD_DrawNum(hud, value, (colorize->ival) ? (value < 0 || colorize->ival > 1) : false, scale->value, style->value, digits->value, align->string); } void SCR_HUD_DrawScoresDifference(hud_t *hud) { - static cvar_t *scale = NULL, *style, *digits, *align, *colorize; + static cvar_t *scale = NULL, *style, *digits, *align, *colorize; int value = 0; int i; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - digits = HUD_FindVar(hud, "digits"); - align = HUD_FindVar(hud, "align"); + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + digits = HUD_FindVar(hud, "digits"); + align = HUD_FindVar(hud, "align"); colorize = HUD_FindVar(hud, "colorize"); - } + } // // AAS: more voodoo @@ -5876,23 +5938,23 @@ void SCR_HUD_DrawScoresDifference(hud_t *hud) } } - SCR_HUD_DrawNum(hud, value, (colorize->ival) ? (value < 0 || colorize->ival > 1) : false, scale->value, style->value, digits->value, align->string); + SCR_HUD_DrawNum(hud, value, (colorize->ival) ? (value < 0 || colorize->ival > 1) : false, scale->value, style->value, digits->value, align->string); } void SCR_HUD_DrawScoresPosition(hud_t *hud) { - static cvar_t *scale = NULL, *style, *digits, *align, *colorize; + static cvar_t *scale = NULL, *style, *digits, *align, *colorize; int value = 0; int i; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); - digits = HUD_FindVar(hud, "digits"); - align = HUD_FindVar(hud, "align"); + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); + digits = HUD_FindVar(hud, "digits"); + align = HUD_FindVar(hud, "align"); colorize = HUD_FindVar(hud, "colorize"); - } + } // // AAS: someone, please stop me @@ -5924,7 +5986,7 @@ void SCR_HUD_DrawScoresPosition(hud_t *hud) } } - SCR_HUD_DrawNum(hud, value, (colorize->ival) ? (value < 0 || colorize->ival > 1) : false, scale->value, style->value, digits->value, align->string); + SCR_HUD_DrawNum(hud, value, (colorize->ival) ? (value < 0 || colorize->ival > 1) : false, scale->value, style->value, digits->value, align->string); } /* @@ -5943,13 +6005,13 @@ void SCR_HUD_DrawScoresBar(hud_t *hud) char buf[256]; char c, *out, *temp, *in; - if (scale == NULL) // first time called - { - scale = HUD_FindVar(hud, "scale"); - style = HUD_FindVar(hud, "style"); + if (scale == NULL) // first time called + { + scale = HUD_FindVar(hud, "scale"); + style = HUD_FindVar(hud, "style"); format_big = HUD_FindVar(hud, "format_big"); format_small= HUD_FindVar(hud, "format_small"); - } + } // // AAS: nightmare comes back @@ -6170,7 +6232,7 @@ void SCR_HUD_DrawBarArmor(hud_t *hud) qbool alive = cl.stats[STAT_HEALTH] > 0; if (width == NULL) // first time called - { + { width = HUD_FindVar(hud, "width"); height = HUD_FindVar(hud, "height"); direction = HUD_FindVar(hud, "direction"); @@ -6190,7 +6252,7 @@ void SCR_HUD_DrawBarArmor(hud_t *hud) { SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_unnatural->vec4, x, y, width->ival, height->ival); } - else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR3 && alive) + else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR3 && alive) { SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_noarmor->vec4, x, y, width->ival, height->ival); SCR_HUD_DrawBar(direction->ival, armor, 200.0, color_ra->vec4, x, y, width->ival, height->ival); @@ -6200,7 +6262,7 @@ void SCR_HUD_DrawBarArmor(hud_t *hud) SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_noarmor->vec4, x, y, width->ival, height->ival); SCR_HUD_DrawBar(direction->ival, armor, 150.0, color_ya->vec4, x, y, width->ival, height->ival); } - else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR1 && alive) + else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR1 && alive) { SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_noarmor->vec4, x, y, width->ival, height->ival); SCR_HUD_DrawBar(direction->ival, armor, 100.0, color_ga->vec4, x, y, width->ival, height->ival); @@ -6219,7 +6281,7 @@ void SCR_HUD_DrawBarHealth(hud_t *hud) int health = cl.stats[STAT_HEALTH]; if (width == NULL) // first time called - { + { width = HUD_FindVar(hud, "width"); height = HUD_FindVar(hud, "height"); direction = HUD_FindVar(hud, "direction"); @@ -6262,60 +6324,177 @@ void SCR_HUD_DrawBarHealth(hud_t *hud) } } -#ifdef WITH_PNG - void SCR_HUD_DrawOwnFrags(hud_t *hud) { - // not implemented yet: scale, color - // fixme: add appropriate opengl functions that will add alpha, scale and color - int width = VX_OwnFragTextLen() * LETTERWIDTH; - int height = LETTERHEIGHT; - int x, y; - double alpha; - static cvar_t - *hud_ownfrags_timeout = NULL, - *hud_ownfrags_scale = NULL; -// *hud_ownfrags_color = NULL; + // not implemented yet: scale, color + // fixme: add appropriate opengl functions that will add alpha, scale and color + char ownfragtext[256]; + float age; + int width; + int height = 8; + int x, y; + double alpha; + static cvar_t + *hud_ownfrags_timeout = NULL, + *hud_ownfrags_scale = NULL; +// *hud_ownfrags_color = NULL; extern qbool hud_editor; if (hud_ownfrags_timeout == NULL) // first time - { + { hud_ownfrags_scale = HUD_FindVar(hud, "scale"); - // hud_ownfrags_color = HUD_FindVar(hud, "color"); - hud_ownfrags_timeout = HUD_FindVar(hud, "timeout"); - } + // hud_ownfrags_color = HUD_FindVar(hud, "color"); + hud_ownfrags_timeout = HUD_FindVar(hud, "timeout"); + } if (hud_editor) - HUD_PrepareDraw(hud, 10 * LETTERWIDTH , height * hud_ownfrags_scale->value, &x, &y); + { + strcpy(ownfragtext, "Own Frags"); + age = 0; + } + else if (BUILTINISVALID(GetTrackerOwnFrags)) + age = pGetTrackerOwnFrags(0, ownfragtext, sizeof(ownfragtext)); + else + { + strcpy(ownfragtext, "Engine does not support OwnFrags"); + age = 0; + } + width = strlen(ownfragtext); + + width *= hud_ownfrags_scale->value; + height *= hud_ownfrags_scale->value; + + alpha = 2 - hud_ownfrags_timeout->value / age * 2; + alpha = bound(0, alpha, 1); + + if (!HUD_PrepareDraw(hud, width , height, &x, &y)) + return; if (!width) return; - if (VX_OwnFragTime() > hud_ownfrags_timeout->value) + if (age > hud_ownfrags_timeout->value) return; - width *= hud_ownfrags_scale->value; - height *= hud_ownfrags_scale->value; + if (age < hud_ownfrags_timeout->value) + Draw_SString(x, y, ownfragtext, hud_ownfrags_scale->value); +} - alpha = 2 - hud_ownfrags_timeout->value / VX_OwnFragTime() * 2; - alpha = bound(0, alpha, 1); +static struct wstats_s *findweapon(struct wstats_s *w, size_t wc, char *wn) +{ + for (; wc>0; wc--, w++) + { + if (!strcmp(wn, w->wname)) + return w; + } + return NULL; +} +static void SCR_HUD_DrawWeaponStats(hud_t *hud) +{ + char line[1024], *o, *i; + int width; + int height = 8; + int x, y; + static cvar_t *hud_weaponstats_scale = NULL; + static cvar_t *hud_weaponstats_fmt = NULL; + extern qbool hud_editor; - if (!HUD_PrepareDraw(hud, width , height, &x, &y)) - return; + int ws; + struct wstats_s wstats[16]; + if (BUILTINISVALID(GetWeaponStats)) + ws = pGetWeaponStats(-1, wstats, countof(wstats)); + else + ws = 0; - if (VX_OwnFragTime() < hud_ownfrags_timeout->value) - Draw_SString(x, y, VX_OwnFragText(), hud_ownfrags_scale->value); + if (hud_editor) + { + ws = 0; + strcpy(wstats[ws].wname, "axe"); + wstats[ws].hit = 20; + wstats[ws].total = 100; + ws++; + strcpy(wstats[ws].wname, "rl"); + wstats[ws].hit = 60; + wstats[ws].total = 120; + ws++; + strcpy(wstats[ws].wname, "lg"); + wstats[ws].hit = 20; + wstats[ws].total = 100; + ws++; + } + + if (hud_weaponstats_scale == NULL) // first time + { + hud_weaponstats_scale = HUD_FindVar(hud, "scale"); + hud_weaponstats_fmt = HUD_FindVar(hud, "fmt"); +// "&c990sg&r:[%sg] &c099ssg&r:[%ssg] &c900rl&r:[#rl] &c009lg&r:[%lg]" + } + + height = 8; + for (o = line, i = hud_weaponstats_fmt->string; ws && *i && o < line+countof(line)-1; ) + { + if (i[0] == '[' && (i[1] == '%' || i[1] == '#')) + { + struct wstats_s *w; + char wname[16]; + int pct = i[1]=='%', j; + i+=2; + for (j = 0; *i && j < countof(wname)-1; j++) + { + if (*i == ']') + { + i++; + break; + } + wname[j] = *i++; + } + wname[j] = 0; + w = findweapon(wstats, ws, wname); + if (pct && w && w->total) + snprintf(wname, sizeof(wname), "%.1f", (100.0 * w->hit) / w->total); + else if (pct) + snprintf(wname, sizeof(wname), "%.1f", 0.0); + else if (w) + snprintf(wname, sizeof(wname), "%u", w->hit); + else + snprintf(wname, sizeof(wname), "%u", 0); + + for (j = 0; wname[j] && o < line+countof(line)-1; j++) + *o++ = wname[j]; + } + else if (*i == '\n') + { + height += 8; + *o++ = *i++; + } + else + *o++ = *i++; + } + *o++ = 0; + + width = 8*strlen_color(line); + + width *= hud_weaponstats_scale->value; + height *= hud_weaponstats_scale->value; + + if (!HUD_PrepareDraw(hud, width, height, &x, &y)) + return; + + Draw_SString(x, y, line, hud_weaponstats_scale->value); } void SCR_HUD_DrawKeys(hud_t *hud) { - char line1[4], line2[4]; + char line1[32], line2[32]; int width, height, x, y; - usermainbuttons_t b = CL_GetLastCmd(); - int i; + usercmd_t b; static cvar_t* vscale = NULL; float scale; + memset(&b, 0, sizeof(b)); + if (BUILTINISVALID(GetLastInputFrame)) + pGetLastInputFrame(0, &b); + if (!vscale) { vscale = HUD_FindVar(hud, "scale"); } @@ -6323,27 +6502,26 @@ void SCR_HUD_DrawKeys(hud_t *hud) scale = vscale->value; scale = max(0, scale); - i = 0; - line1[i++] = b.attack ? 'x' + 128 : 'x'; - line1[i++] = b.forward ? '^' + 128 : '^'; - line1[i++] = b.jump ? 'J' + 128 : 'J'; - line1[i++] = '\0'; - i = 0; - line2[i++] = b.left ? '<' + 128 : '<'; - line2[i++] = b.back ? '_' + 128 : '_'; - line2[i++] = b.right ? '>' + 128 : '>'; - line2[i++] = '\0'; + snprintf(line1, sizeof(line1), "^{%x}^{%x}^{%x}", + 0xe000 + 'x' + ((b.buttons & 1)?0x80:0), + 0xe000 + '^' + ((b.forwardmove > 0)?0x80:0), + 0xe000 + 'J' + ((b.buttons & 2)?0x80:0)); + snprintf(line2, sizeof(line2), "^{%x}^{%x}^{%x}", + 0xe000 + '<' + ((b.sidemove < 0)?0x80:0), + 0xe000 + '_' + ((b.forwardmove < 0)?0x80:0), + 0xe000 + '>' + ((b.sidemove > 0)?0x80:0)); - width = LETTERWIDTH * strlen(line1) * scale; - height = LETTERHEIGHT * 2 * scale; + width = 8 * 3 * scale; + height = 8 * 2 * scale; - if (!HUD_PrepareDraw(hud, width ,height, &x, &y)) - return; + if (!HUD_PrepareDraw(hud, width, height, &x, &y)) + return; Draw_SString(x, y, line1, scale); - Draw_SString(x, y + LETTERHEIGHT*scale, line2, scale); + Draw_SString(x, y + 8*scale, line2, scale); } +#ifdef WITH_PNG // What stats to draw. #define HUD_RADAR_STATS_NONE 0 #define HUD_RADAR_STATS_BOTH_TEAMS_HOLD 1 @@ -7485,6 +7663,30 @@ void HUD_AfterDraw() { } + +#ifndef HAXX +static void SCR_HUD_DrawNotImplemented(hud_t *hud) +{ + char line1[64]; + int width, height, x, y; + + snprintf(line1, sizeof(line1), "%s not implemented", hud->name); + + width = 8 * strlen(line1); + height = 8; + + if (!HUD_PrepareDraw(hud, width, height, &x, &y)) + return; + + Draw_SString(x, y, line1, 1); +} +#define SCR_HUD_DrawSpeed SCR_HUD_DrawNotImplemented +#define SCR_HUD_DrawTeamHoldBar SCR_HUD_DrawNotImplemented +#define SCR_HUD_DrawTeamHoldInfo SCR_HUD_DrawNotImplemented +#define SCR_HUD_DrawItemsClock SCR_HUD_DrawNotImplemented +#endif + + // ---------------- // Init // and add some common elements to hud (clock etc) @@ -7543,7 +7745,6 @@ void CommonDraw_Init(void) "offset","0", NULL); -#ifdef HAXX HUD_Register("notify", NULL, "Shows last console lines", HUD_PLUSMINUS, ca_disconnected, 8, SCR_HUD_DrawNotify, "0", "top", "left", "top", "0", "0", "0", "0 0 0", NULL, @@ -7552,7 +7753,6 @@ void CommonDraw_Init(void) "scale", "1", "time", "4", NULL); -#endif // fps HUD_Register("fps", NULL, @@ -7622,7 +7822,6 @@ void CommonDraw_Init(void) "period", "1", NULL); -#ifdef HAXX // init speed HUD_Register("speed", NULL, "Shows your current running speed. It is measured over XY or XYZ axis depending on \'xyz\' property.", HUD_PLUSMINUS, ca_active, 7, SCR_HUD_DrawSpeed, @@ -7642,7 +7841,6 @@ void CommonDraw_Init(void) "text_align", "1", "style", "0", NULL); -#endif // Init speed2 (half circle thingie). HUD_Register("speed2", NULL, "Shows your current running speed. It is measured over XY or XYZ axis depending on \'xyz\' property.", @@ -7993,7 +8191,6 @@ void CommonDraw_Init(void) "pic_scalemode", "0", NULL); -#ifdef HAXX // healthdamage HUD_Register("healthdamage", NULL, "Shows amount of damage done to your health.", HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawHealthDamage, @@ -8015,7 +8212,6 @@ void CommonDraw_Init(void) "digits", "3", "duration", "0.8", NULL); -#endif HUD_Register("frags", NULL, "Show list of player frags in short form.", 0, ca_active, 0, SCR_HUD_DrawFrags, @@ -8123,7 +8319,6 @@ void CommonDraw_Init(void) NULL); #endif // WITH_PNG -#ifdef HAXX HUD_Register("teamholdbar", NULL, "Shows how much of the level (in percent) that is currently being held by either team.", HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawTeamHoldBar, "0", "top", "left", "bottom", "0", "0", "0", "0 0 0", NULL, @@ -8135,9 +8330,7 @@ void CommonDraw_Init(void) "show_text", "1", "onlytp", "0", NULL); -#endif -#ifdef HAXX HUD_Register("teamholdinfo", NULL, "Shows which important items in the level that are being held by the teams.", HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawTeamHoldInfo, "0", "top", "left", "bottom", "0", "0", "0", "0 0 0", NULL, @@ -8148,9 +8341,7 @@ void CommonDraw_Init(void) "style", "1", "itemfilter", "quad ra ya ga mega pent rl quad", NULL); -#endif -#ifdef WITH_PNG HUD_Register("ownfrags" /* jeez someone give me a better name please */, NULL, "Highlights your own frags", 0, ca_active, 1, SCR_HUD_DrawOwnFrags, "1", "screen", "center", "top", "0", "50", "0.2", "0 0 100", NULL, @@ -8168,9 +8359,7 @@ void CommonDraw_Init(void) "scale", "2", NULL ); -#endif -#ifdef HAXX HUD_Register("itemsclock", NULL, "Displays upcoming item respawns", 0, ca_active, 1, SCR_HUD_DrawItemsClock, "0", "screen", "right", "center", "0", "0", "0", "0 0 0", NULL, @@ -8178,7 +8367,6 @@ void CommonDraw_Init(void) "style", "0", NULL ); -#endif HUD_Register("score_team", NULL, "Own scores or team scores.", 0, ca_active, 0, SCR_HUD_DrawScoresTeam, @@ -8263,6 +8451,14 @@ void CommonDraw_Init(void) NULL ); + HUD_Register("weaponstats", NULL, "Weapon Stats", + HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawWeaponStats, + "0", "screen", "right", "center", "0", "0", "0", "0 0 0", NULL, + "scale", "1", + "fmt", "&c990sg&r:[%sg] &c099ssg&r:[%ssg] &c900rl&r:[#rl] &c009lg&r:[%lg]", + NULL + ); + /* hexum -> FIXME? this is used only for debug purposes, I wont bother to port it (it shouldnt be too difficult if anyone cares) #ifdef _DEBUG HUD_Register("framegraph", NULL, "Shows different frame times for debug/profiling purposes.", diff --git a/plugins/plugin.c b/plugins/plugin.c index 4cc731165..dcae00c42 100644 --- a/plugins/plugin.c +++ b/plugins/plugin.c @@ -150,6 +150,13 @@ BUILTIN(void, GetServerInfo, (char *info, int infolen)); #define ARGNAMES ,key,value BUILTIN(void, SetUserInfo, (const char *key, const char *value)); #undef ARGNAMES +#define ARGNAMES ,seat,playercmd +BUILTINR(int, GetLastInputFrame, (int seat, usercmd_t *playercmd)); +#undef ARGNAMES +#define ARGNAMES ,seat,text,textsize +BUILTINR(float, GetTrackerOwnFrags, (int seat, char *text, size_t textsize)); +#undef ARGNAMES + #define ARGNAMES ,pos,buffer,bufferlen BUILTIN(void, GetLocationName, (const float *pos, char *buffer, int bufferlen)); @@ -158,6 +165,9 @@ BUILTIN(void, GetLocationName, (const float *pos, char *buffer, int bufferlen)); #define ARGNAMES ,clients,maxclients,showenemies,showself BUILTINR(int, GetTeamInfo, (teamplayerinfo_t *clients, unsigned int maxclients, int showenemies, int showself)); #undef ARGNAMES +#define ARGNAMES ,player,result,maxresults +BUILTINR(int, GetWeaponStats, (int player, struct wstats_s *result, unsigned int maxresults)); +#undef ARGNAMES #define ARGNAMES ,soundname BUILTIN(void, LocalSound, (const char *soundname)); @@ -204,6 +214,9 @@ BUILTIN(void, Draw_CharacterH, (float x, float y, float h, unsigned int flags, u #define ARGNAMES ,PASSFLOAT(x),PASSFLOAT(y),PASSFLOAT(h),flags,string BUILTIN(void, Draw_StringH, (float x, float y, float h, unsigned int flags, const char *string)); #undef ARGNAMES +#define ARGNAMES ,PASSFLOAT(h),flags,string +BUILTINR(float, Draw_StringWidth, (float h, unsigned int flags, const char *string)); +#undef ARGNAMES #define ARGNAMES ,palcol,PASSFLOAT(a) BUILTIN(void, Draw_Colourpa, (int palcol, float a)); #undef ARGNAMES @@ -421,6 +434,8 @@ void Plug_InitStandardBuiltins(void) CHECKBUILTIN(GetPlayerInfo); CHECKBUILTIN(LocalPlayerNumber); CHECKBUILTIN(GetLocalPlayerNumbers); + CHECKBUILTIN(GetLastInputFrame); + CHECKBUILTIN(GetTrackerOwnFrags); CHECKBUILTIN(GetServerInfo); CHECKBUILTIN(SetUserInfo); CHECKBUILTIN(LocalSound); @@ -428,6 +443,7 @@ void Plug_InitStandardBuiltins(void) CHECKBUILTIN(Key_GetKeyCode); CHECKBUILTIN(GetLocationName); CHECKBUILTIN(GetTeamInfo); + CHECKBUILTIN(GetWeaponStats); CHECKBUILTIN(GetNetworkInfo); //drawing routines @@ -442,6 +458,7 @@ void Plug_InitStandardBuiltins(void) CHECKBUILTIN(Draw_String); CHECKBUILTIN(Draw_CharacterH); CHECKBUILTIN(Draw_StringH); + CHECKBUILTIN(Draw_StringWidth); CHECKBUILTIN(Draw_Colourpa); CHECKBUILTIN(Draw_Colourp); CHECKBUILTIN(Draw_Colour3f); diff --git a/plugins/plugin.h b/plugins/plugin.h index b4259f129..70b91b2d5 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -235,6 +235,8 @@ EBUILTIN(int, GetLocalPlayerNumbers, (int firstseat, int numseats, int *playernu EBUILTIN(void, GetServerInfo, (char *info, int infolen)); EBUILTIN(void, SetUserInfo, (const char *key, const char *value)); EBUILTIN(void, GetLocationName, (const float *pos, char *buffer, int bufferlen)); +EBUILTIN(int, GetLastInputFrame, (int seat, usercmd_t *playercmd)); +EBUILTIN(float, GetTrackerOwnFrags, (int seat, char *text, size_t textsize)); typedef struct { @@ -246,6 +248,8 @@ typedef struct char nick[16]; } teamplayerinfo_t; EBUILTIN(int, GetTeamInfo, (teamplayerinfo_t *clients, unsigned int maxclients, int showenemies, int showself)); +struct wstats_s; +EBUILTIN(int, GetWeaponStats, (int player, struct wstats_s *result, unsigned int maxresults)); typedef struct { int seats; @@ -305,7 +309,8 @@ EBUILTIN(void, Draw_Line, (float x1, float y1, float x2, float y2)); EBUILTIN(void, Draw_Character, (int x, int y, unsigned int character)); EBUILTIN(void, Draw_String, (float x, float y, const char *string)); EBUILTIN(void, Draw_CharacterH, (float x, float y, float h, unsigned int flags, unsigned int character)); -EBUILTIN(void, Draw_StringH, (float x, float y, float h, unsigned int flags, const char *string)); +EBUILTIN(void, Draw_StringH, (float x, float y, float h, unsigned int flags, const char *string)); //returns the vpixel width of the (coloured) string, in the current (variable-width) font. +EBUILTIN(float, Draw_StringWidth, (float h, unsigned int flags, const char *string)); EBUILTIN(void, Draw_Colourpa, (int palcol, float a)); EBUILTIN(void, Draw_Colourp, (int palcol)); EBUILTIN(void, Draw_Colour3f, (float r, float g, float b)); diff --git a/plugins/qvm_api.c b/plugins/qvm_api.c index 3e3606559..2d42cabd3 100644 --- a/plugins/qvm_api.c +++ b/plugins/qvm_api.c @@ -21,7 +21,8 @@ int Q_vsnprintf(char *buffer, size_t maxlen, const char *format, va_list vargs) float _float; int i; int use0s; - int precision, useprepad, plus; + int width, useprepad, plus; + int precision; if (!maxlen) return 0; @@ -33,9 +34,10 @@ maxlen--; { case '%': plus = 0; - precision= 0; + width= 0; + precision=-1; useprepad=0; - use0s=0; + use0s= 0; retry: switch(*(++format)) { @@ -45,8 +47,13 @@ retry: case '+': plus = true; goto retry; + case '.': + precision = 0; + while (format[1] >= '0' && format[1] <= '9') + precision = precision*10+*++format-'0'; + goto retry; case '0': - if (!precision) + if (!width) { use0s=true; goto retry; @@ -60,7 +67,7 @@ retry: case '7': case '8': case '9': - precision=precision*10+*format-'0'; + width=width*10+*format-'0'; goto retry; case '%': /*emit a %*/ if (maxlen-- == 0) @@ -71,9 +78,9 @@ retry: string = va_arg(vargs, char *); if (!string) string = "(null)"; - if (precision) + if (width) { - while (*string && precision--) + while (*string && width--) { if (maxlen-- == 0) {*buffer++='\0';return tokens;} @@ -120,15 +127,15 @@ retry: string[1] = '\0'; } - precision -= 62-i; - while (precision>0) + width -= 62-i; + while (width>0) { string--; if (use0s) *string = '0'; else *string = ' '; - precision--; + width--; } while (*string) @@ -203,15 +210,15 @@ Con_Printf("%i bytes left\n", maxlen); string[1] = '\0'; } - precision -= 62-i; -/* while (precision>0) + width -= 62-i; +/* while (width>0) { string--; *string = ' '; - precision--; + width--; } */ - while(precision>0) + while(width>0) { if (maxlen-- == 0) {*buffer++='\0';return tokens;} @@ -219,7 +226,7 @@ Con_Printf("%i bytes left\n", maxlen); *buffer++ = '0'; else *buffer++ = ' '; - precision--; + width--; } while (*string) @@ -270,9 +277,11 @@ Con_Printf("%i bytes left\n", maxlen); _float -= (int)_float; i = 0; tempbuffer[i++] = '.'; + if (precision < 0) + precision = 7; while(_float - (int)_float) { - if (i + _int > 7) //remove the excess presision. + if (i > precision) //remove the excess presision. break; _float*=10; diff --git a/specs/particles.txt b/specs/particles.txt index e33e0acbb..1493131f3 100644 --- a/specs/particles.txt +++ b/specs/particles.txt @@ -87,10 +87,11 @@ alpha alphadelta specifies how much the alpha value of the effect changes per second (subtracted) -die +die specifies the maximum age of the particle diesubrand + obsolete (set by die) specifies the maximum starting age of the particle. basically the particle will live up to this much less time. the alpha value will also be aged by the amount chosen by this value @@ -104,8 +105,8 @@ veladd orgadd biases how much to add to the starting origin relative to the requested velocity. -friction <1> <2> <3> - FIXME +friction <| | > + Proportion of the particle's speed that should be lost from friction. Negative values are accepted. gravity amount that the particle's velocity changes per second, in quake units. @@ -130,12 +131,19 @@ assoc Thus allowing two sets of particles from one effect. inwater + obsolete Specifies a replacement effect to use when this one is spawned underwater. assoc used is the replacement effect. the assoc value from the replaced effect is ignored (this includes +foo chains). -overwater - specifies that this -underwater +overwater [content names] + Specifies that this particle should ONLY be spawned when out of water. + The particle will not spawn under water (this does not affect assoc chains). + Content names are a space-separated list of: water slime lava sky solid fluid. Default is fluid if not specified. + The r_part_contentswitch cvar must be enabled for this to function correctly. + +underwater [content names] + Specifies that this particle should ONLY be spawned when underwater. + The particle will not spawn if the spawn position is non-water (this does not affect assoc chains). colorindex [rand] Specifies a palette index to spawn the particle with. @@ -282,13 +290,15 @@ emitstart spawnorg [vert] spawnvel [vert] + obsolete viewspace [frac] Specifies that this particle type should move relative to the camera. Not compatible with splitscreen. + Should not normally be used in combination with clipping/bouncing. perframe - apply inverse frametime to count (causes emits to be per frame) + apply inverse frametime to count (causes emits to be per frame). averageout average trail points from start to end, useful with t_lightning, etc