From 365c11181c552cd149d6669c22cb60c49847d230 Mon Sep 17 00:00:00 2001 From: Spoike Date: Mon, 29 Jun 2015 23:46:31 +0000 Subject: [PATCH] wait now correctly waits until the start of the next input frame (thus ensuring that -attack is delayed for long enough). implemented hud_teaminfo_show ezhud element. _LOTS_ of hacks. ezhud needs updated engine. fix issue with overly friendly prints. handle svc_setinfo more gracefully, for the next time OMC makes a bug. allow glsl to embed default values for float cvars, in case they're not already set. this can save some docs... removed prints about "wad" "foo\", fixing a crash concerning just which print function to call. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4925 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/cl_input.c | 4 ++ engine/client/cl_parse.c | 46 +++++++++--- engine/client/cl_plugin.inc | 90 +++++++++++++++++++++++ engine/client/client.h | 10 +++ engine/common/cmd.c | 15 ++++ engine/common/cmd.h | 1 + engine/common/cvar.c | 5 -- engine/dotnet2005/ftequake.vcproj | 1 + engine/gl/gl_shader.c | 15 +++- engine/gl/gl_vidcommon.c | 10 ++- engine/qclib/qcc_cmdlib.c | 24 ++++--- engine/server/pr_cmds.c | 8 +-- plugins/ezhud/ezquakeisms.c | 35 ++++++++- plugins/ezhud/hud_common.c | 116 +++++++++++++++++------------- plugins/plugin.c | 5 ++ plugins/plugin.h | 12 +++- plugins/qvm_api.c | 18 +++-- 17 files changed, 326 insertions(+), 89 deletions(-) diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index c7977fbbf..d7291716e 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -1714,6 +1714,8 @@ void CL_SendCmd (double frametime, qboolean mainloop) } IN_Move (NULL, 0, frametime); + + Cbuf_Waited(); //its okay to stop waiting now return; // sendcmds come from the demo } @@ -1803,6 +1805,8 @@ void CL_SendCmd (double frametime, qboolean mainloop) { CL_BaseMove (&independantphysics[plnum], plnum, (msecstouse - independantphysics[plnum].msec), wantfps); CL_FinishMove(&independantphysics[plnum], msecstouse, plnum); + + Cbuf_Waited(); //its okay to stop waiting now } // if we are spectator, try autocam diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 206582425..8d48a923f 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -4663,19 +4663,22 @@ void CL_ParseSetInfo (void) char value[MAX_QWMSGLEN]; slot = MSG_ReadByte (); - if (slot >= MAX_CLIENTS) - Host_EndGame ("CL_ParseServerMessage: svc_setinfo > MAX_SCOREBOARD"); - - player = &cl.players[slot]; Q_strncpyz (key, MSG_ReadString(), sizeof(key)); Q_strncpyz (value, MSG_ReadString(), sizeof(value)); - Con_DPrintf("SETINFO %s: %s=%s\n", player->name, key, value); + if (slot >= MAX_CLIENTS) + Con_Printf("INVALID SETINFO %i: %s=%s\n", slot, key, value); + else + { + player = &cl.players[slot]; - Info_SetValueForStarKey (player->userinfo, key, value, sizeof(player->userinfo)); + Con_DPrintf("SETINFO %s: %s=%s\n", player->name, key, value); - CL_ProcessUserInfo (slot, player); + Info_SetValueForStarKey (player->userinfo, key, value, sizeof(player->userinfo)); + + CL_ProcessUserInfo (slot, player); + } } /* @@ -5691,6 +5694,32 @@ void CL_ParsePrint(char *msg, int level) } +void CL_ParseTeamInfo(void) +{ + unsigned int pidx = atoi(Cmd_Argv(1)); + vec3_t org = + { + atof(Cmd_Argv(2)), + atof(Cmd_Argv(3)), + atof(Cmd_Argv(4)) + }; + float health = atof(Cmd_Argv(5)); + float armour = atof(Cmd_Argv(6)); + unsigned int items = strtoul(Cmd_Argv(7), NULL, 0); + char *nick = Cmd_Argv(8); + + if (pidx < cl.allocated_client_slots) + { + player_info_t *pl = &cl.players[pidx]; + pl->tinfo.time = cl.time+5; + pl->tinfo.health = health; + pl->tinfo.armour = armour; + pl->tinfo.items = items; + VectorCopy(org, pl->tinfo.org); + Q_strncpyz(pl->tinfo.nick, nick, sizeof(pl->tinfo.nick)); + } +} + char stufftext[4096]; void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds from network segregation. @@ -5781,7 +5810,8 @@ void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds from n else if (!strncmp(stufftext, "//tinfo ", 8)) { Cmd_TokenizeString(stufftext+2, false, false); - Plug_Command_f(); + CL_ParseTeamInfo(); + Plug_Command_f(); //FIXME: deprecate this call } else if (!strncmp(stufftext, "//sn ", 5)) { diff --git a/engine/client/cl_plugin.inc b/engine/client/cl_plugin.inc index 6e97129b3..be7037373 100644 --- a/engine/client/cl_plugin.inc +++ b/engine/client/cl_plugin.inc @@ -695,6 +695,95 @@ static qintptr_t VARGS Plug_GetLocationName(void *offset, quintptr_t mask, const return VM_LONG(arg[1]); } +typedef struct +{ + unsigned int client; + unsigned int items; + float armor; + float health; + vec3_t org; + char nick[16]; +} teamplayerinfo_t; +static qintptr_t VARGS Plug_GetTeamInfo(void *offset, quintptr_t mask, const qintptr_t *arg) +{ + teamplayerinfo_t *players = VM_POINTER(arg[0]); + size_t maxplayers = VM_LONG(arg[1]); + qboolean showenemies = VM_LONG(arg[2]); + qboolean showself = VM_LONG(arg[3]); + int count = 0; + int i; + int self; + lerpents_t *le; + player_info_t *pl; + + if (VM_OOB(arg[0], maxplayers*sizeof(*players))) + return 0; + maxplayers = min(maxplayers, cl.allocated_client_slots); + + Cvar_Get("ti", "1", CVAR_USERINFO, "Hacks because ktx sucks. Must be 1 in order to receive team information in ktx."); + + self = cl.playerview[0].playernum; + if (cl.playerview[0].cam_state != CAM_FREECAM) + self = cl.playerview[0].cam_spec_track; + + for (i = 0; i < cl.allocated_client_slots && maxplayers > 0; i++) + { + if (!*cl.players[i].name) //empty slot + continue; + if (cl.players[i].spectator) //shoo! + continue; + if (i == self && !showself) + continue; + if (!showenemies && strcmp(cl.players[i].team, cl.players[self].team)) + continue; + players->client = i; + + pl = &cl.players[i]; + if (pl->tinfo.time > cl.time) + { //mod is explicitly telling us this junk + players->items = pl->tinfo.items; + players->health = pl->tinfo.health; + players->armor = pl->tinfo.armour; + VectorCopy(pl->tinfo.org, players->org); + Q_strncpyz(players->nick, pl->tinfo.nick, sizeof(players->nick)); + } + else if (i == self) + { //oh hey look, its me. + players->items = cl.playerview[0].stats[STAT_ITEMS]; + players->armor = cl.playerview[0].statsf[STAT_ARMOR]; + players->health = cl.playerview[0].statsf[STAT_HEALTH]; + Q_strncpyz(players->nick, "", sizeof(players->nick)); + } + else + { //scrape it from the mvd (assuming there is one... + players->items = cl.players[i].stats[STAT_ITEMS]; + players->armor = cl.players[i].statsf[STAT_ARMOR]; + players->health = cl.players[i].statsf[STAT_HEALTH]; + Q_strncpyz(players->nick, "", sizeof(players->nick)); + + VectorClear(players->org); + } + + //scrape origin from interpolation, if its more valid. + if (i+1 < cl.maxlerpents && cl.lerpentssequence && cl.lerpents[i+1].sequence == cl.lerpentssequence) + { + le = &cl.lerpents[i+1]; + VectorCopy(le->origin, players->org); + } + else if (cl.lerpentssequence && cl.lerpplayers[i].sequence == cl.lerpentssequence) + { + le = &cl.lerpplayers[i]; + VectorCopy(le->origin, players->org); + } + + players++; + maxplayers--; + count++; + } + + return VM_LONG(count); +} + static qintptr_t VARGS Plug_Con_SubPrint(void *offset, quintptr_t mask, const qintptr_t *arg) { char *name = VM_POINTER(arg[0]); @@ -1058,6 +1147,7 @@ void Plug_Client_Init(void) Plug_RegisterBuiltin("LocalSound", Plug_LocalSound, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("SCR_CenterPrint", Plug_SCR_CenterPrint, PLUG_BIF_NEEDSRENDERER); + Plug_RegisterBuiltin("GetTeamInfo", Plug_GetTeamInfo, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("GetLocationName", Plug_GetLocationName, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("GetPlayerInfo", Plug_GetPlayerInfo, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("LocalPlayerNumber", Plug_LocalPlayerNumber, PLUG_BIF_NEEDSRENDERER); diff --git a/engine/client/client.h b/engine/client/client.h index 122e6652c..f698f6716 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -164,6 +164,16 @@ typedef struct player_info_s int ping; qbyte pl; + struct + { + float time; //invalid if too old. + int health; + int armour; + unsigned int items; + vec3_t org; + char nick[8]; //kinda short, yes. + } tinfo; + qboolean ignored; qboolean vignored; diff --git a/engine/common/cmd.c b/engine/common/cmd.c index e3e7b5ca0..055343df9 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -153,6 +153,12 @@ struct { } cmd_text[RESTRICT_MAX+3+MAX_SPLITS]; //max is local. //RESTRICT_MAX+1 is the from sever buffer (max+2 is for second player...) +void Cbuf_Waited(void) +{ + //input packet was sent to server, its okay to continue executing stuff like -attack now + cmd_text[RESTRICT_LOCAL].waitattime = 0; +} + /* ============ Cmd_Wait_f @@ -424,6 +430,15 @@ void Cbuf_Execute (void) { int level; +#ifndef SERVERONLY + if (cmd_text[RESTRICT_LOCAL].waitattime && cls.state == ca_active) + { + //keep binds blocked until after the next input frame was sent to the server (at which point it will be cleared + //this ensures that wait and +attack etc works synchronously, as though your client never even supported network independance! yay... I guess. + cmd_text[RESTRICT_LOCAL].waitattime = realtime; + } +#endif + for (level = 0; level < sizeof(cmd_text)/sizeof(cmd_text[0]); level++) if (cmd_text[level].buf.cursize) Cbuf_ExecuteLevel(level); diff --git a/engine/common/cmd.h b/engine/common/cmd.h index 27c4748ea..6b63b3158 100644 --- a/engine/common/cmd.h +++ b/engine/common/cmd.h @@ -34,6 +34,7 @@ The game starts with a Cbuf_AddText ("exec quake.rc\n"); Cbuf_Execute (); */ +void Cbuf_Waited(void); void Cbuf_Init (void); // allocates an initial text buffer that will grow as needed diff --git a/engine/common/cvar.c b/engine/common/cvar.c index fc1cdbd39..ce59f8aaa 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -924,11 +924,6 @@ void Cvar_ForceCheatVars(qboolean semicheats, qboolean absolutecheats) if (!(var->flags & (CVAR_CHEAT|CVAR_SEMICHEAT))) continue; - if (var->flags & CVAR_RULESETLATCH) - { - Con_Printf("Hello\n"); - } - latch = var->latched_string; var->latched_string = NULL; if (!latch) diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index 75e3016bf..cbdba340b 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -1283,6 +1283,7 @@ PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;SERVERONLY;MULTITHREAD" MinimalRebuild="true" BasicRuntimeChecks="3" + SmallerTypeCheck="true" RuntimeLibrary="0" EnableFunctionLevelLinking="true" FloatingPointModel="2" diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 519a5e975..9d1153ee1 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -1031,9 +1031,22 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip { cvar_t *var; char namebuf[64]; + char valuebuf[64]; memcpy(namebuf, script, end - script); namebuf[end - script] = 0; - var = Cvar_Get(namebuf, "0", CVAR_SHADERSYSTEM, "GLSL Variables"); + while (*end == ' ' || *end == '\t') + end++; + if (*end == '=') + { + script = ++end; + while (*end && *end != '\n' && *end != '\r' && end < script+sizeof(namebuf)-1) + end++; + memcpy(valuebuf, script, end - script); + valuebuf[end - script] = 0; + } + else + strcpy(valuebuf, "0"); + var = Cvar_Get(namebuf, valuebuf, CVAR_SHADERSYSTEM, "GLSL Variables"); if (var) permutationdefines[nummodifiers++] = Z_StrDup(va("#define %s %g\n", namebuf, var->value)); } diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index f89b03fd8..c0e1304ac 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -2294,6 +2294,7 @@ static void GLSlang_ProgAutoFields(program_t *prog, char **cvarnames, int *cvart /*set cvar unirforms*/ for (i = 0; cvarnames[i]; i++) { + char *tmpval; if (prog->numparams == SHADER_PROGPARMS_MAX) { Con_Printf("Too many cvar paramters for program\n"); @@ -2302,7 +2303,14 @@ static void GLSlang_ProgAutoFields(program_t *prog, char **cvarnames, int *cvart for (p = 0; cvarnames[i][p] && (unsigned char)cvarnames[i][p] > 32 && p < sizeof(tmpname)-1; p++) tmpname[p] = cvarnames[i][p]; tmpname[p] = 0; - cvar = Cvar_Get(tmpname, "0", CVAR_SHADERSYSTEM, "glsl cvars"); + tmpval = strchr(tmpname, '='); + if (tmpval) + *tmpval++ = 0; + else + tmpval = "0"; + while(p > 0 && (tmpname[p-1] == ' ' || tmpname[p-1] == '\t')) + tmpname[--p] = 0; + cvar = Cvar_Get(tmpname, tmpval, CVAR_SHADERSYSTEM, "glsl cvars"); if (!cvar) continue; cvar->flags |= CVAR_SHADERSYSTEM; diff --git a/engine/qclib/qcc_cmdlib.c b/engine/qclib/qcc_cmdlib.c index 08da76f3f..097c724bb 100644 --- a/engine/qclib/qcc_cmdlib.c +++ b/engine/qclib/qcc_cmdlib.c @@ -4,6 +4,8 @@ #include //#include +#undef progfuncs + #define PATHSEPERATOR '/' #ifndef QCC @@ -131,8 +133,8 @@ void QC_strlcat(char *dest, const char *src, size_t destsize) dest += curlen; while(*src && ++curlen < destsize) *dest++ = *src++; - if (*src) - printf("QC_strlcpy: truncation\n"); +// if (*src) +// printf("QC_strlcpy: truncation\n"); *dest = 0; } void QC_strlcpy(char *dest, const char *src, size_t destsize) @@ -142,8 +144,8 @@ void QC_strlcpy(char *dest, const char *src, size_t destsize) return; //err while(*src && ++curlen < destsize) *dest++ = *src++; - if (*src) - printf("QC_strlcpy: truncation\n"); +// if (*src) +// printf("QC_strlcpy: truncation\n"); *dest = 0; } void QC_strnlcpy(char *dest, const char *src, size_t srclen, size_t destsize) @@ -153,8 +155,8 @@ void QC_strnlcpy(char *dest, const char *src, size_t srclen, size_t destsize) return; //err for(; *src && srclen > 0 && ++curlen < destsize; srclen--) *dest++ = *src++; - if (srclen) - printf("QC_strlcpy: truncation\n"); +// if (srclen) +// printf("QC_strlcpy: truncation\n"); *dest = 0; } @@ -312,7 +314,7 @@ skipwhite: } else if (c=='\0') { - printf("ERROR: Unterminated string\n"); +// printf("ERROR: Unterminated string\n"); qcc_token[len] = 0; return (char*)data; } @@ -324,7 +326,7 @@ skipwhite: //so \r\n terminates the string if the last char was an escaped quote, but not otherwise. if (len > 0 && qcc_token[len-1] == '\"') { - printf("ERROR: new line in string\n"); +// printf("ERROR: new line in string\n"); qcc_token[len] = 0; return (char*)data; } @@ -519,6 +521,7 @@ For abnormal program terminations */ void VARGS QCC_Error (int errortype, const char *error, ...) { + progfuncs_t *progfuncs = qccprogfuncs; extern int numsourcefiles; va_list argptr; char msg[2048]; @@ -877,6 +880,7 @@ int SafeSeek(int hand, int ofs, int mode) } pbool SafeClose(int hand) { + progfuncs_t *progfuncs = qccprogfuncs; pbool ret; ret = externs->WriteFile(qccfile[hand].name, qccfile[hand].buff, qccfile[hand].maxofs); // if (qccfile[hand].buffismalloc) @@ -1163,6 +1167,7 @@ char *QCC_SanitizeCharSet(char *mem, unsigned int *len, pbool *freeresult, int * long QCC_LoadFile (char *filename, void **bufferptr) { + progfuncs_t *progfuncs = qccprogfuncs; char *mem; int check; int flen; @@ -1221,6 +1226,7 @@ long QCC_LoadFile (char *filename, void **bufferptr) } void QCC_AddFile (char *filename) { + progfuncs_t *progfuncs = qccprogfuncs; char *mem; int len; len = externs->FileSize(filename); @@ -1241,6 +1247,7 @@ void QCC_AddFile (char *filename) } void *FS_ReadToMem(char *filename, void *mem, int *len) { + progfuncs_t *progfuncs = qccprogfuncs; if (!mem) { *len = externs->FileSize(filename); @@ -1251,6 +1258,7 @@ void *FS_ReadToMem(char *filename, void *mem, int *len) void FS_CloseFromMem(void *mem) { + progfuncs_t *progfuncs = qccprogfuncs; externs->memfree(mem); } diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 13f189bfd..b2c5d4958 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -6512,15 +6512,15 @@ static void QCBUILTIN PF_clientcommand (pubprogfuncs_t *prinst, struct globalvar { client_t *oldhostclient = host_client; edict_t *oldsvplayer = sv_player; - int i; + unsigned int i; //find client for this entity - i = NUM_FOR_EDICT(prinst, G_EDICT(prinst, OFS_PARM0)) - 1; - if (i < 0 || i >= sv.allocated_client_slots) + i = NUM_FOR_EDICT(prinst, G_EDICT(prinst, OFS_PARM0)); + if (i <= 0 || i > sv.allocated_client_slots) PR_BIError(prinst, "PF_clientcommand: entity is not a client"); else { - host_client = &svs.clients[i]; + host_client = &svs.clients[i-1]; sv_player = host_client->edict; if (host_client->state == cs_connected || host_client->state == cs_spawned) { diff --git a/plugins/ezhud/ezquakeisms.c b/plugins/ezhud/ezquakeisms.c index 4895eaa33..517bd82f9 100644 --- a/plugins/ezhud/ezquakeisms.c +++ b/plugins/ezhud/ezquakeisms.c @@ -57,6 +57,12 @@ void Draw_TextBox (int x, int y, int width, int lines) { } +char *TP_LocationName (vec3_t location) +{ + static char locname[256]; + pGetLocationName(location, locname, sizeof(locname)); + return locname; +} void Draw_SPic(float x, float y, mpic_t *pic, float scale) @@ -224,9 +230,35 @@ int Sbar_BottomColor(player_info_t *pi) { return Sbar_ColorForMap(pi->bottomcolour); } +int dehex(char nib) +{ + if (nib >= '0' && nib <= '9') + return nib - '0'; + if (nib >= 'a' && nib <= 'f') + return nib - 'a' + 10; + if (nib >= 'A' && nib <= 'F') + return nib - 'A' + 10; + return 0; +} char *TP_ParseFunChars(char *str, qbool chat) { - return str; + static char resultbuf[1024]; + char *out = resultbuf, *end = resultbuf+sizeof(resultbuf)-1; + + while (out < end) + { + if (str[0] == '$' && str[1] == 'x' && str[2] && str[3]) + { + *out++ = (dehex(str[2]) << 4) | dehex(str[3]); + str+=4; + } + else if (*str) + *out++ = *str++; + else + break; + } + *out = 0; + return resultbuf; } char *TP_ItemName(unsigned int itbit) { @@ -633,6 +665,7 @@ qintptr_t Plug_Init(qintptr_t *args) CHECKBUILTIN(Cvar_GetNVFDG); if (BUILTINISVALID(Cvar_GetNVFDG) && BUILTINISVALID(Draw_ImageSize) && + BUILTINISVALID(GetTeamInfo) && Plug_Export("SbarBase", EZHud_Draw) && Plug_Export("MenuEvent", EZHud_MenuEvent) && Plug_Export("Tick", EZHud_Tick) && diff --git a/plugins/ezhud/hud_common.c b/plugins/ezhud/hud_common.c index 78c365d20..682f1f605 100644 --- a/plugins/ezhud/hud_common.c +++ b/plugins/ezhud/hud_common.c @@ -5265,19 +5265,15 @@ static void SCR_HUD_DrawTeamHoldInfo(hud_t *hud) } #endif -#ifdef HAXX -static int SCR_HudDrawTeamInfoPlayer(ti_player_t *ti_cl, int x, int y, int maxname, int maxloc, qbool width_only, hud_t *hud); -#endif +static int SCR_HudDrawTeamInfoPlayer(teamplayerinfo_t *ti_cl, int x, int y, int maxname, int maxloc, qbool width_only, hud_t *hud); -#ifdef HAXX +#define FONTWIDTH 8 static void SCR_HUD_DrawTeamInfo(hud_t *hud) { int x, y, _y, width, height; - int i, j, k, slots[MAX_CLIENTS], slots_num, maxname, maxloc; + int i, j, k, slots_num, maxname, maxloc; char tmp[1024], *nick; - - // Used for hud_teaminfo, data is collected in screen.c / scr_teaminfo - extern ti_player_t ti_clients[MAX_CLIENTS]; + teamplayerinfo_t ti_clients[MAX_CLIENTS]; extern qbool hud_editor; @@ -5302,45 +5298,29 @@ static void SCR_HUD_DrawTeamInfo(hud_t *hud) } // Don't update hud item unless first view is beeing displayed - if ( CURRVIEW != 1 && CURRVIEW != 0) - return; +// if ( CURRVIEW != 1 && CURRVIEW != 0) +// return; - if (cls.mvdplayback) - Update_TeamInfo(); + slots_num = pGetTeamInfo(ti_clients, countof(ti_clients), hud_teaminfo_show_enemies->ival, hud_teaminfo_show_self->ival); // fill data we require to draw teaminfo - for ( maxloc = maxname = slots_num = i = 0; i < MAX_CLIENTS; i++ ) { - if ( !cl.players[i].name[0] || cl.players[i].spectator - || !ti_clients[i].time || ti_clients[i].time + 5 < cl.time - ) - continue; - - // do not show enemy players unless it's MVD and user wishes to show them - if (VX_TrackerIsEnemy( i ) && (!cls.mvdplayback || !hud_teaminfo_show_enemies->integer)) - continue; - - // do not show tracked player to spectator - if ((cl.spectator && Cam_TrackNum() == i) && hud_teaminfo_show_self->integer == 0) - continue; - + for ( maxloc = maxname = i = 0; i < slots_num; i++ ) { // dynamically guess max length of name/location nick = (ti_clients[i].nick[0] ? ti_clients[i].nick : cl.players[i].name); // we use nick or name maxname = max(maxname, strlen(TP_ParseFunChars(nick, false))); strlcpy(tmp, TP_LocationName(ti_clients[i].org), sizeof(tmp)); maxloc = max(maxloc, strlen(TP_ParseFunChars(tmp, false))); - - slots[slots_num++] = i; } // well, better use fixed loc length - maxloc = bound(0, hud_teaminfo_loc_width->integer, 100); + maxloc = bound(0, hud_teaminfo_loc_width->ival, 100); // limit name length - maxname = bound(0, maxname, hud_teaminfo_name_width->integer); + maxname = bound(0, maxname, hud_teaminfo_name_width->ival); // this does't draw anything, just calculate width width = FONTWIDTH * hud_teaminfo_scale->value * SCR_HudDrawTeamInfoPlayer(&ti_clients[0], 0, 0, maxname, maxloc, true, hud); - height = FONTWIDTH * hud_teaminfo_scale->value * (hud_teaminfo_show_enemies->integer?slots_num+n_teams:slots_num); + height = FONTWIDTH * hud_teaminfo_scale->value * (hud_teaminfo_show_enemies->ival?slots_num+n_teams:slots_num); if (hud_editor) HUD_PrepareDraw(hud, width , FONTWIDTH, &x, &y); @@ -5359,7 +5339,7 @@ static void SCR_HUD_DrawTeamInfo(hud_t *hud) // If multiple teams are displayed then sort the display and print team header on overlay k=0; - if (hud_teaminfo_show_enemies->integer) + if (hud_teaminfo_show_enemies->ival) { while (sorted_teams[k].name) { @@ -5369,10 +5349,10 @@ static void SCR_HUD_DrawTeamInfo(hud_t *hud) _y += FONTWIDTH * hud_teaminfo_scale->value; for ( j = 0; j < slots_num; j++ ) { - i = slots[j]; + i = ti_clients[j].client; if (!strcmp(cl.players[i].team,sorted_teams[k].name)) { - SCR_HudDrawTeamInfoPlayer(&ti_clients[i], x, _y, maxname, maxloc, false, hud); + SCR_HudDrawTeamInfoPlayer(&ti_clients[j], x, _y, maxname, maxloc, false, hud); _y += FONTWIDTH * hud_teaminfo_scale->value; } } @@ -5382,22 +5362,61 @@ static void SCR_HUD_DrawTeamInfo(hud_t *hud) else { for ( j = 0; j < slots_num; j++ ) { - i = slots[j]; - SCR_HudDrawTeamInfoPlayer(&ti_clients[i], x, _y, maxname, maxloc, false, hud); + SCR_HudDrawTeamInfoPlayer(&ti_clients[j], x, _y, maxname, maxloc, false, hud); _y += FONTWIDTH * hud_teaminfo_scale->value; } } } -#endif qbool Has_Both_RL_and_LG (int flags) { return (flags & IT_ROCKET_LAUNCHER) && (flags & IT_LIGHTNING); } -#ifdef HAXX -static int SCR_HudDrawTeamInfoPlayer(ti_player_t *ti_cl, int x, int y, int maxname, int maxloc, qbool width_only, hud_t *hud) +#define FONTWIDTH 8 +void str_align_right (char *target, size_t size, const char *source, size_t length) +{ + if (length > size - 1) + length = size - 1; + + if (strlen(source) >= length) { + strlcpy(target, source, size); + target[length] = 0; + } else { + int i; + + for (i = 0; i < length - strlen(source); i++) { + target[i] = ' '; + } + + strlcpy(target + i, source, size - i); + } +} +int Player_GetTrackId(int uid) +{ + return uid; +} +unsigned int BestWeaponFromStatItems(unsigned int items) +{ + int i; + for (i = 1<<7; i; i>>=1) + { + if (items & i) + return i; + } + return 0; +} +mpic_t * SCR_GetWeaponIconByFlag (int flag) +{ + int i, j; + for (i = 0, j = 1; i < 7; i++, j*=2) + { + if (flag == j) + return sb_weapons[0][i]; + } + return NULL; +} +static int SCR_HudDrawTeamInfoPlayer(teamplayerinfo_t *ti_cl, int x, int y, int maxname, int maxloc, qbool width_only, hud_t *hud) { extern mpic_t * SCR_GetWeaponIconByFlag (int flag); - extern cvar_t tp_name_rlg; - char *s, *loc, tmp[1024], tmp2[MAX_MACRO_STRING], *aclr; + char *s, *loc, tmp[1024], tmp2[1024], *aclr; int x_in = x; // save x int i; mpic_t *pic; @@ -5442,11 +5461,11 @@ static int SCR_HudDrawTeamInfoPlayer(ti_player_t *ti_cl, int x, int y, int maxna break; case 'w': // draw "best" weapon icon/name - switch (HUD_FindVar(hud, "weapon_style")->integer) { + switch (HUD_FindVar(hud, "weapon_style")->ival) { case 1: if(!width_only) { if (Has_Both_RL_and_LG(ti_cl->items)) { - char *weap_str = tp_name_rlg.string; + char *weap_str = pCvar_GetNVFDG("tp_name_rlg", "rlg", 0, NULL, NULL)->string; char weap_white_stripped[32]; Util_SkipChars(weap_str, "{}", weap_white_stripped, 32); Draw_ColoredString (x, y, weap_white_stripped, false); @@ -5475,7 +5494,7 @@ static int SCR_HudDrawTeamInfoPlayer(ti_player_t *ti_cl, int x, int y, int maxna case 'H': // draw health, padding with space on right side if(!width_only) { - snprintf(tmp, sizeof(tmp), (s[0] == 'h' ? "%s%3d" : "%s%-3d"), (ti_cl->health < HUD_FindVar(hud, "low_health")->integer ? "&cf00" : ""), ti_cl->health); + snprintf(tmp, sizeof(tmp), (s[0] == 'h' ? "%s%3d" : "%s%-3d"), (ti_cl->health < HUD_FindVar(hud, "low_health")->ival ? "&cf00" : ""), (int)ti_cl->health); Draw_SString (x, y, tmp, scale); } x += 3 * FONTWIDTH * scale; @@ -5489,7 +5508,7 @@ static int SCR_HudDrawTeamInfoPlayer(ti_player_t *ti_cl, int x, int y, int maxna // // different styles of armor // - switch (HUD_FindVar(hud,"armor_style")->integer) { + switch (HUD_FindVar(hud,"armor_style")->ival) { case 1: // image prefixed armor value if(!width_only) { if (ti_cl->items & IT_ARMOR3) @@ -5546,7 +5565,7 @@ static int SCR_HudDrawTeamInfoPlayer(ti_player_t *ti_cl, int x, int y, int maxna } if(!width_only) { // value drawed no matter which style - snprintf(tmp, sizeof(tmp), (s[0] == 'a' ? "%s%3d" : "%s%-3d"), aclr, ti_cl->armor); + snprintf(tmp, sizeof(tmp), (s[0] == 'a' ? "%s%3d" : "%s%-3d"), aclr, (int)ti_cl->armor); Draw_SString (x, y, tmp, scale); } x += 3 * FONTWIDTH * scale; @@ -5566,7 +5585,7 @@ static int SCR_HudDrawTeamInfoPlayer(ti_player_t *ti_cl, int x, int y, int maxna break; case 'p': // draw powerups - switch (HUD_FindVar(hud, "powerup_style")->integer) { + switch (HUD_FindVar(hud, "powerup_style")->ival) { case 1: // quad/pent/ring image if(!width_only) { if (ti_cl->items & IT_QUAD) @@ -5658,7 +5677,6 @@ static int SCR_HudDrawTeamInfoPlayer(ti_player_t *ti_cl, int x, int y, int maxna return (x - x_in) / (FONTWIDTH * scale); // return width } -#endif #ifdef HAXX void SCR_HUD_DrawItemsClock(hud_t *hud) @@ -8046,7 +8064,6 @@ void CommonDraw_Init(void) "maxname", "16", NULL); -#ifdef HAXX HUD_Register("teaminfo", NULL, "Show information about your team in short form.", 0, ca_active, 0, SCR_HUD_DrawTeamInfo, "0", "", "right", "center", "0", "0", "0.2", "20 20 20", NULL, @@ -8062,7 +8079,6 @@ void CommonDraw_Init(void) "scale","1", "powerup_style","1", NULL); -#endif HUD_Register("mp3_title", NULL, "Shows current mp3 playing.", HUD_PLUSMINUS, ca_disconnected, 0, SCR_HUD_DrawMP3_Title, diff --git a/plugins/plugin.c b/plugins/plugin.c index 6f7915b4d..c8017eefb 100644 --- a/plugins/plugin.c +++ b/plugins/plugin.c @@ -155,6 +155,10 @@ BUILTIN(void, SetUserInfo, (const char *key, const char *value)); BUILTIN(void, GetLocationName, (const float *pos, char *buffer, int bufferlen)); #undef ARGNAMES +#define ARGNAMES ,clients,maxclients,showenemies,showself +BUILTINR(int, GetTeamInfo, (teamplayerinfo_t *clients, unsigned int maxclients, int showenemies, int showself)); +#undef ARGNAMES + #define ARGNAMES ,soundname BUILTIN(void, LocalSound, (const char *soundname)); #undef ARGNAMES @@ -423,6 +427,7 @@ void Plug_InitStandardBuiltins(void) CHECKBUILTIN(Menu_Control); CHECKBUILTIN(Key_GetKeyCode); CHECKBUILTIN(GetLocationName); + CHECKBUILTIN(GetTeamInfo); CHECKBUILTIN(GetNetworkInfo); //drawing routines diff --git a/plugins/plugin.h b/plugins/plugin.h index e881f9dcc..aed7ffff2 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -233,7 +233,17 @@ 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(void, GetLocationName, (const float *pos, char *buffer, int bufferlen)); + +typedef struct +{ + unsigned int client; + unsigned int items; + float armor; + float health; + vec3_t org; + char nick[16]; +} teamplayerinfo_t; +EBUILTIN(int, GetTeamInfo, (teamplayerinfo_t *clients, unsigned int maxclients, int showenemies, int showself)); typedef struct { int seats; diff --git a/plugins/qvm_api.c b/plugins/qvm_api.c index 226a9f333..3e3606559 100644 --- a/plugins/qvm_api.c +++ b/plugins/qvm_api.c @@ -15,6 +15,7 @@ int Q_vsnprintf(char *buffer, size_t maxlen, const char *format, va_list vargs) int tokens=0; char *string; char tempbuffer[64]; + char sign; unsigned int _uint; int _int; float _float; @@ -176,25 +177,22 @@ Con_Printf("%i bytes left\n", maxlen); } if (_int < 0) { - if (maxlen-- == 0) - {*buffer++='\0';return tokens;} - *buffer++ = '-'; + sign = '-'; _int *= -1; } else if (plus) - { - if (maxlen-- == 0) - {*buffer++='\0';return tokens;} - *buffer++ = '+'; - } + sign = '+'; + else + sign = 0; i = sizeof(tempbuffer)-2; tempbuffer[sizeof(tempbuffer)-1] = '\0'; while(_int) { - tempbuffer[i] = _int%10 + '0'; + tempbuffer[i--] = _int%10 + '0'; _int/=10; - i--; } + if (sign) + tempbuffer[i--] = sign; string = tempbuffer+i+1; if (!*string)