in_forceseat will not break clientcmds any more.

tweak drawtextfield to understand fonts. now available to menuqc too.
provide player and full server info to qc server browsers.
allow qc to actually use cfg_save. I've been issuing that on quit for a while now and not noticed that it was getting denied.
fix some focus issues with cwindows.
tweak splitscreens to display centerprints+scoreboards in more suitable places. harder to glitch out.
path command can now displays hashes (in tooltips), which can be useful for creating fmf files.
fix q3game crash.
fix some qcc issues with hexenc and -O0.
fix some qccgui unicode issues, now preserves encoding when saving.
provide easy upgrade path for qccx syntax to fteqcc: string[%1] -> string+1 (which is still potentially unsafe (tempstrings), and thus generates a compiler warning).
rework xmpp plugin to use cwindows for chats and the buddylist. this should make it more intuitive and thus more userfriendly.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4865 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2015-04-27 06:19:33 +00:00
parent 57248e9f64
commit 410db5d6b0
33 changed files with 1992 additions and 695 deletions

View File

@ -62,10 +62,12 @@ typedef enum
SLKEY_ISFAVORITE,//eep!
SLKEY_ISLOCAL,
SLKEY_ISPROXY,
SLKEY_SERVERINFO,
SLKEY_TOOMANY,
SLKEY_CUSTOM
SLKEY_PLAYER0,
SLKEY_CUSTOM = SLKEY_PLAYER0+MAX_CLIENTS
} hostcachekey_t;
typedef enum

View File

@ -5729,6 +5729,8 @@ void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds from n
#endif
else
{
if (!strncmp(stufftext, "cmd ", 4))
Cbuf_AddText (va("p%i ", destsplit+1), RESTRICT_SERVER+destsplit); //without this, in_forceseat can break directed cmds.
Cbuf_AddText (stufftext, RESTRICT_SERVER+destsplit);
Cbuf_AddText ("\n", RESTRICT_SERVER+destsplit);
}

View File

@ -581,6 +581,8 @@ void SCR_DrawCenterString (vrect_t *rect, cprint_t *p, struct font_s *font)
for (l = 0; l < linecount; l++, y += Font_CharHeight())
{
if (y >= bottom)
break;
if (p->flags & CPRINT_RALIGN)
{
x = right - Font_LineWidth(line_start[l], line_end[l]);
@ -609,7 +611,6 @@ void SCR_CheckDrawCenterString (void)
extern qboolean sb_showscores;
int pnum;
cprint_t *p;
vrect_t rect;
for (pnum = 0; pnum < cl.splitclients; pnum++)
{
@ -626,12 +627,12 @@ void SCR_CheckDrawCenterString (void)
if (sb_showscores) //this was annoying
continue;
SCR_VRectForPlayer(&rect, pnum);
SCR_DrawCenterString(&rect, p, font_default);
if (cl.playerview[pnum].gamerectknown == cls.framecount)
SCR_DrawCenterString(&cl.playerview[pnum].gamerect, p, font_default);
}
}
void R_DrawTextField(int x, int y, int w, int h, const char *text, unsigned int defaultmask, unsigned int fieldflags)
void R_DrawTextField(int x, int y, int w, int h, const char *text, unsigned int defaultmask, unsigned int fieldflags, struct font_s *font, vec2_t fontscale)
{
cprint_t p;
vrect_t r;
@ -647,7 +648,7 @@ void R_DrawTextField(int x, int y, int w, int h, const char *text, unsigned int
p.time_start = cl.time;
*p.titleimage = 0;
SCR_DrawCenterString(&r, &p, font_default);
SCR_DrawCenterString(&r, &p, font);
}
qboolean SCR_HardwareCursorIsActive(void)
@ -2419,7 +2420,7 @@ void SCR_TileClear (void)
{
if (r_refdef.vrect.width < r_refdef.grect.width)
{
int w;
float w;
// left
R2D_TileClear (r_refdef.grect.x, r_refdef.grect.y, r_refdef.vrect.x-r_refdef.grect.x, r_refdef.grect.height - sb_lines);
// right
@ -2445,7 +2446,7 @@ void SCR_TileClear (void)
// The 2d refresh stuff.
void SCR_DrawTwoDimensional(int uimenu, qboolean nohud)
{
qboolean consolefocused = !!Key_Dest_Has(kdm_console);
qboolean consolefocused = !!Key_Dest_Has(kdm_console|kdm_cwindows);
RSpeedMark();
R2D_ImageColours(1, 1, 1, 1);

View File

@ -596,6 +596,9 @@ struct playerview_s
float driftmove;
double laststop;
int gamerectknown; //equals cls.framecount if valid
vrect_t gamerect; //position the player's main view was drawn at this frame.
//prediction state
int pmovetype;
float entgravity;

View File

@ -445,22 +445,22 @@ static void SL_SliderDraw (int x, int y, menucustom_t *ths, menu_t *menu)
mpic_t *pic;
pic = R2D_SafeCachePic("scrollbars/slidebg.png");
pic = R2D_SafeCachePic("scrollbars/slidebg.tga");
if (pic)
{
R2D_ScalePic(x + ths->common.width - 8, y+8, 8, ths->common.height-16, pic);
pic = R2D_SafeCachePic("scrollbars/arrow_up.png");
pic = R2D_SafeCachePic("scrollbars/arrow_up.tga");
R2D_ScalePic(x + ths->common.width - 8, y, 8, 8, pic);
pic = R2D_SafeCachePic("scrollbars/arrow_down.png");
pic = R2D_SafeCachePic("scrollbars/arrow_down.tga");
R2D_ScalePic(x + ths->common.width - 8, y + ths->common.height - 8, 8, 8, pic);
y += ((info->scrollpos) / ((float)info->numslots - info->visibleslots)) * (float)(ths->common.height-(64+16-1));
y += 8;
pic = R2D_SafeCachePic("scrollbars/slider.png");
pic = R2D_SafeCachePic("scrollbars/slider.tga");
R2D_ScalePic(x + ths->common.width - 8, y, 8, 64, pic);
}
else
@ -484,7 +484,7 @@ static void SL_SliderDraw (int x, int y, menucustom_t *ths, menu_t *menu)
my = mousecursor_y;
my -= ths->common.posy;
if (R2D_SafeCachePic("scrollbars/slidebg.png"))
if (R2D_SafeCachePic("scrollbars/slidebg.tga"))
{
my -= 32+8;
my /= ths->common.height - (64+16);

View File

@ -2646,6 +2646,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
entity_t ent;
vec3_t fwd, rgt, up;
const char *fname;
vec2_t fs = {8,8};
modelview_t *mods = c->dptr;
@ -2732,7 +2733,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
"end: skin+=1\n"
"pgup: frame+=1\n"
"pgdn: frame-=1\n"
, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN);
, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs);
break;
case MV_BONES:
#ifdef SKELETALMODELS
@ -2746,7 +2747,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
M_BoneDisplay(&ent, b, &y, 0, -1, 0, bonecount);
}
else
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+y, r_refdef.grect.width, r_refdef.grect.height-y, "No bones in model", CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN);
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+y, r_refdef.grect.width, r_refdef.grect.height-y, "No bones in model", CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs);
}
#endif
break;
@ -2757,7 +2758,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
char *body = Shader_GetShaderBody(Mod_ShaderForSkin(ent.model, mods->skingroup));
mods->shadertext = Z_StrDup(body);
}
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+16, r_refdef.grect.width, r_refdef.grect.height-16, mods->shadertext, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN);
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+16, r_refdef.grect.width, r_refdef.grect.height-16, mods->shadertext, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs);
//fixme: draw the shader's textures.
}

View File

@ -294,13 +294,16 @@ void M_ToggleMenu_f (void)
#ifdef CSQC_DAT
if (CSQC_ConsoleCommand("togglemenu"))
{
Key_Dest_Remove(kdm_console);
Key_Dest_Remove(kdm_console|kdm_cwindows);
return;
}
#endif
#ifdef MENU_DAT
if (MP_Toggle())
{
Key_Dest_Remove(kdm_console|kdm_cwindows);
return;
}
#endif
#ifdef VM_UI
if (UI_OpenMenu())
@ -314,8 +317,8 @@ void M_ToggleMenu_f (void)
m_state = m_none;
return;
}
if (Key_Dest_Has(kdm_console))
Key_Dest_Remove(kdm_console);
if (Key_Dest_Has(kdm_console|kdm_cwindows))
Key_Dest_Remove(kdm_console|kdm_cwindows);
/*
{
if (cls.state != ca_active)

View File

@ -10,6 +10,7 @@ struct entity_s;
struct dlight_s;
struct galiasbone_s;
struct dlight_s;
struct font_s;
typedef enum
{
@ -108,7 +109,7 @@ extern void SCR_SetUpToDrawConsole (void);
extern void SCR_EraseCenterString (void);
extern void SCR_CenterPrint (int pnum, char *str, qboolean skipgamecode);
void R_DrawTextField(int x, int y, int w, int h, const char *text, unsigned int defaultmask, unsigned int fieldflags);
void R_DrawTextField(int x, int y, int w, int h, const char *text, unsigned int defaultmask, unsigned int fieldflags, struct font_s *font, vec2_t fontscale);
#define CPRINT_LALIGN (1<<0) //L
#define CPRINT_TALIGN (1<<1) //T
#define CPRINT_RALIGN (1<<2) //R

View File

@ -1052,6 +1052,17 @@ float Master_ReadKeyFloat(serverinfo_t *server, int keynum)
return 0;
}
void Master_DecodeColour(vec3_t ret, int col)
{
if (col < 16)
{
col = Sbar_ColorForMap(col);
VectorSet(ret, host_basepal[col*3+0]/255.0, host_basepal[col*3+1]/255.0, host_basepal[col*3+2]/255.0);
}
else
VectorSet(ret, ((col&0xff0000)>>16)/255.0, ((col&0x00ff00)>>8)/255.0, ((col&0x0000ff)>>0)/255.0);
}
char *Master_ReadKeyString(serverinfo_t *server, int keynum)
{
static char adr[MAX_ADR_SIZE];
@ -1059,7 +1070,41 @@ char *Master_ReadKeyString(serverinfo_t *server, int keynum)
if (!server)
return "";
if (keynum < SLKEY_CUSTOM)
if (keynum >= SLKEY_CUSTOM)
{
if (server->moreinfo)
{
keynum -= SLKEY_CUSTOM;
if (keynum < sizeof(slist_keyname)/sizeof(slist_keyname[0]))
return Info_ValueForKey(server->moreinfo->info, slist_keyname[keynum]);
}
else if (!(server->special & SS_KEEPINFO))
{
server->special |= SS_KEEPINFO;
server->sends++;
}
}
else if (keynum >= SLKEY_PLAYER0)
{
if (server->moreinfo)
{
keynum -= SLKEY_PLAYER0;
if (keynum < server->moreinfo->numplayers)
{
vec3_t top, bot;
Master_DecodeColour(top, server->moreinfo->players[keynum].topc);
Master_DecodeColour(bot, server->moreinfo->players[keynum].botc);
return va("%i %i %g %i \"%s\" \"%s\" '%g %g %g' '%g %g %g'", server->moreinfo->players[keynum].userid, server->moreinfo->players[keynum].frags, server->moreinfo->players[keynum].time, server->moreinfo->players[keynum].ping, server->moreinfo->players[keynum].name, server->moreinfo->players[keynum].skin, top[0],top[1],top[2], bot[0], bot[1], bot[2]);
}
}
else if (!(server->special & SS_KEEPINFO))
{
server->special |= SS_KEEPINFO;
server->sends++;
}
}
else
{
switch(keynum)
{
@ -1076,6 +1121,8 @@ char *Master_ReadKeyString(serverinfo_t *server, int keynum)
return server->modname;
case SLKEY_QCSTATUS:
return server->qcstatus;
case SLKEY_SERVERINFO:
return server->moreinfo->info;
default:
{
@ -1085,8 +1132,6 @@ char *Master_ReadKeyString(serverinfo_t *server, int keynum)
}
}
}
else if (server->moreinfo)
return Info_ValueForKey(server->moreinfo->info, slist_keyname[keynum-SLKEY_CUSTOM]);
return "";
}
@ -1130,6 +1175,10 @@ int Master_KeyForName(const char *keyname)
return SLKEY_ISLOCAL;
else if (!strcmp(keyname, "isproxy"))
return SLKEY_ISPROXY;
else if (!strcmp(keyname, "serverinfo"))
return SLKEY_SERVERINFO;
else if (!strncmp(keyname, "player", 6))
return SLKEY_PLAYER0 + atoi(keyname+6);
else if (slist_customkeys == SLIST_MAXKEYS)
return SLKEY_TOOMANY;
@ -2694,7 +2743,7 @@ int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolean favor
details.players[clnum].botc = 0;
details.players[clnum].time = 0;
}
else //qw responce
else //qw response
{
details.players[clnum].time = atoi(token);
msg = token;

View File

@ -232,6 +232,8 @@ static void CSQC_ChangeLocalPlayer(int seat)
*csqcg.player_localentnum = csqc_playerview->viewentity;
else if (cl.spectator && Cam_TrackNum(csqc_playerview) >= 0)
*csqcg.player_localentnum = Cam_TrackNum(csqc_playerview) + 1;
else if (csqc_playerview == &csqc_nullview)
*csqcg.player_localentnum = 0;
else
*csqcg.player_localentnum = csqc_playerview->playernum+1;
}
@ -1570,8 +1572,12 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
case VF_ACTIVESEAT:
if (prinst == csqc_world.progs)
{
CSQC_ChangeLocalPlayer(*p);
V_CalcRefdef(csqc_playerview); //set up the default position+angles for the named player.
if (csqc_playerseat != *p)
{
CSQC_ChangeLocalPlayer(*p);
if (prinst->callargc < 3 || G_FLOAT(OFS_PARM2))
V_CalcRefdef(csqc_playerview); //set up the default position+angles for the named player.
}
}
break;
case VF_VIEWENTITY:
@ -2868,7 +2874,10 @@ static void QCBUILTIN PF_cs_getentitytoken (pubprogfuncs_t *prinst, struct globa
{
csqcmapentitydata = COM_ParseToken(csqcmapentitydata, "{}()\'\":,");
}
RETURN_TSTRING(com_token);
if (!csqcmapentitydata) //hit the end
G_INT(OFS_RETURN) = 0;
else
RETURN_TSTRING(com_token);
}
}

View File

@ -107,12 +107,13 @@ struct font_s *PR_CL_ChooseFont(float *fontsel, float szx, float szy)
void PR_CL_BeginString(pubprogfuncs_t *prinst, float vx, float vy, float szx, float szy, float *px, float *py)
{
world_t *world = prinst->parms->user;
struct font_s *font = PR_CL_ChooseFont(world->g.drawfont, szx, szy);
struct font_s *font;
if (world->g.drawfontscale && (world->g.drawfontscale[0] || world->g.drawfontscale[1]))
{
szx *= world->g.drawfontscale[0];
szy *= world->g.drawfontscale[1];
}
font = PR_CL_ChooseFont(world->g.drawfont, szx, szy);
Font_BeginScaledString(font, vx, vy, szx, szy, px, py);
}
int PR_findnamedfont(const char *name, qboolean isslotname)
@ -367,7 +368,17 @@ void QCBUILTIN PF_CL_DrawTextField (pubprogfuncs_t *prinst, struct globalvars_s
unsigned int flags = G_FLOAT(OFS_PARM2);
const char *text = PR_GetStringOfs(prinst, OFS_PARM3);
R_DrawTextField(pos[0], pos[1], size[0], size[1], text, CON_WHITEMASK, flags);
world_t *world = prinst->parms->user;
vec2_t scale = {8, 8};
struct font_s *font;
if (world->g.drawfontscale && (world->g.drawfontscale[0] || world->g.drawfontscale[1]))
{
scale[0] *= world->g.drawfontscale[0];
scale[1] *= world->g.drawfontscale[1];
}
font = PR_CL_ChooseFont(world->g.drawfont, scale[0], scale[1]);
R_DrawTextField(pos[0], pos[1], size[0], size[1], text, CON_WHITEMASK, flags, font, scale);
}
//float drawstring(vector position, string text, vector scale, float alpha, float flag) = #455;
@ -2002,6 +2013,7 @@ static struct {
{"stringwidth", PF_CL_stringwidth, 468},
{"drawsubpic", PF_CL_drawsubpic, 469},
{"drawrotsubpic", PF_CL_drawrotsubpic, 0},
{"drawtextfield", PF_CL_DrawTextField, 0},
//470
//MERGES WITH CLIENT+SERVER BUILTIN MAPPINGS BELOW
{"asin", PF_asin, 471},

View File

@ -254,7 +254,8 @@ static qboolean largegame = false;
#ifdef Q2CLIENT
static void DrawHUDString (char *string, float x, float y, int centerwidth, qboolean alt)
{
R_DrawTextField(x, y, centerwidth, 1024, string, alt?CON_ALTMASK:CON_WHITEMASK, CPRINT_TALIGN);
vec2_t fontscale = {8,8};
R_DrawTextField(x, y, centerwidth, 1024, string, alt?CON_ALTMASK:CON_WHITEMASK, CPRINT_TALIGN, font_default, fontscale);
}
#define STAT_MINUS 10 // num frame for '-' stats digit
static char *q2sb_nums[2][11] =
@ -3089,6 +3090,8 @@ void Sbar_DeathmatchOverlay (int start)
int startx, rank_width;
playerview_t *pv = r_refdef.playerview;
vrect_t gr = r_refdef.grect;
if (!pv)
return;
@ -3124,7 +3127,7 @@ void Sbar_DeathmatchOverlay (int start)
if (R_GetShaderSizes(pic, &w, &h, false)>0)
{
k = (w * 24) / h;
R2D_ScalePic ((vid.width-k)/2, 0, k, 24, pic);
R2D_ScalePic (gr.x + (gr.width-k)/2, gr.y, k, 24, pic);
}
}
y += 24;
@ -3146,11 +3149,13 @@ void Sbar_DeathmatchOverlay (int start)
y += 8;
}
y += gr.y;
showcolumns = 0;
rank_width = 0;
#define COLUMN(title, cwidth, code) if (rank_width+(cwidth)+8 <= vid.width) {showcolumns |= (1<<COLUMN##title); rank_width += cwidth+8;}
#define COLUMN(title, cwidth, code) if (rank_width+(cwidth)+8 <= gr.width) {showcolumns |= (1<<COLUMN##title); rank_width += cwidth+8;}
//columns are listed here in priority order (if the screen is too narrow, later ones will be hidden)
COLUMN_NAME
COLUMN_PING
@ -3183,7 +3188,8 @@ void Sbar_DeathmatchOverlay (int start)
}
#undef COLUMN
startx = (vid.width-rank_width)/2;
startx = (gr.width-rank_width)/2;
startx += gr.x;
if (scr_scoreboard_newstyle.ival)
{

View File

@ -1134,6 +1134,12 @@ void V_ApplyRefdef (void)
//========================================
if (r_refdef.playerview->gamerectknown != cls.framecount)
{
r_refdef.playerview->gamerectknown = cls.framecount;
r_refdef.playerview->gamerect = r_refdef.grect;
}
// intermission is always full screen
if (cl.intermission || !r_refdef.drawsbar)
size = 120;
@ -1554,9 +1560,10 @@ void R_DrawNameTags(void)
entstr = w->progs->saveent(w->progs, asciibuffer, &buflen, sizeof(asciibuffer), (edict_t*)e); //will save just one entities vars
if (entstr)
{
vec2_t scale = {8,8};
x = screenspace[0]*r_refdef.vrect.width+r_refdef.vrect.x;
y = (1-screenspace[1])*r_refdef.vrect.height+r_refdef.vrect.y;
R_DrawTextField(x, y, vid.width - x, vid.height - y, entstr, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN);
R_DrawTextField(x, y, vid.width - x, vid.height - y, entstr, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, scale);
}
}

View File

@ -2937,7 +2937,7 @@ void Cmd_WriteConfig_f(void)
char sysname[MAX_OSPATH];
qboolean all = true;
if (Cmd_IsInsecure())
if (Cmd_IsInsecure() && Cmd_Argc() > 1)
{
Con_Printf ("%s not allowed\n", Cmd_Argv(0));
return;

View File

@ -581,12 +581,13 @@ COM_Path_f
*/
static void COM_PathLine(searchpath_t *s)
{
Con_Printf("%s %s%s%s%s%s\n", s->logicalpath,
Con_Printf("%s %s%s%s%s%s%s\n", s->logicalpath,
(s->flags & SPF_REFERENCED)?"^[(ref)\\tip\\Referenced\\desc\\Package will auto-download to clients^]":"",
(s->flags & SPF_TEMPORARY)?"^[(temp)\\tip\\Temporary\\desc\\Flushed on map change^]":"",
(s->flags & SPF_COPYPROTECTED)?"^[(c)\\tip\\Copyrighted\\desc\\Copy-Protected and is not downloadable^]":"",
(s->flags & SPF_EXPLICIT)?"^[(e)\\tip\\Explicit\\desc\\Loaded explicitly by the gamedir^]":"",
(s->flags & SPF_UNTRUSTED)?"^[(u)\\tip\\Untrusted\\desc\\Configs and scripts will not be given access to passwords^]":"" );
(s->flags & SPF_UNTRUSTED)?"^[(u)\\tip\\Untrusted\\desc\\Configs and scripts will not be given access to passwords^]":"",
(s->handle->GeneratePureCRC)?va("^[(h)\\tip\\Hash: %x^]", s->handle->GeneratePureCRC(s->handle, 0, 0)):"");
}
void COM_Path_f (void)
{

View File

@ -5927,102 +5927,6 @@ static qboolean CM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3
return trace->fraction != 1;
}
/*
==================
CM_TransformedBoxTrace
Handles offseting and rotation of the end points for moving and
rotating entities
==================
*/
#ifdef _MSC_VER
#pragma warning(disable : 4748)
#pragma optimize( "", off )
#endif
trace_t CM_TransformedBoxTrace (model_t *mod, vec3_t start, vec3_t end,
vec3_t mins, vec3_t maxs,
int brushmask,
vec3_t origin, vec3_t angles)
{
#ifdef _MSC_VER
#pragma warning(default : 4748)
#endif
trace_t trace;
vec3_t start_l, end_l;
vec3_t a;
vec3_t forward, right, up;
vec3_t temp;
qboolean rotated;
qboolean capsule = false;
// subtract origin offset
VectorSubtract (start, origin, start_l);
VectorSubtract (end, origin, end_l);
// rotate start and end into the models frame of reference
if (mod != &box_model &&
(angles[0] || angles[1] || angles[2]) )
rotated = true;
else
rotated = false;
if (rotated)
{
AngleVectors (angles, forward, right, up);
VectorCopy (start_l, temp);
start_l[0] = DotProduct (temp, forward);
start_l[1] = -DotProduct (temp, right);
start_l[2] = DotProduct (temp, up);
VectorCopy (end_l, temp);
end_l[0] = DotProduct (temp, forward);
end_l[1] = -DotProduct (temp, right);
end_l[2] = DotProduct (temp, up);
VectorSet(trace_up, forward[2], -right[2], up[2]);
}
else
{
VectorSet(trace_up, 0, 0, 1);
}
// sweep the box through the model
trace = CM_BoxTrace (mod, start_l, end_l, mins, maxs, capsule, brushmask);
if (rotated && trace.fraction != 1.0)
{
// FIXME: figure out how to do this with existing angles
VectorNegate (angles, a);
AngleVectors (a, forward, right, up);
VectorCopy (trace.plane.normal, temp);
trace.plane.normal[0] = DotProduct (temp, forward);
trace.plane.normal[1] = -DotProduct (temp, right);
trace.plane.normal[2] = DotProduct (temp, up);
}
if (trace.fraction == 1)
{
VectorCopy(end, trace.endpos);
}
else
{
trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]);
trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]);
trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]);
}
return trace;
}
#ifdef _MSC_VER
#pragma optimize( "", on )
#endif
/*
===============================================================================

View File

@ -5689,7 +5689,8 @@ void QCBUILTIN PF_brush_get(pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
//assume the worst.
G_INT(OFS_RETURN) = 0;
*out_contents = 0;
if (G_INT(OFS_PARM4))
*out_contents = 0;
if (!hm)
return;
@ -5699,23 +5700,29 @@ void QCBUILTIN PF_brush_get(pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
br = &hm->wbrushes[i];
if (br->id == brushid)
{
*out_contents = br->contents;
maxfaces = min(br->numplanes, maxfaces);
for (fa = 0; fa < maxfaces; fa++)
if (G_INT(OFS_PARM4))
*out_contents = br->contents;
if (!G_INT(OFS_PARM2))
G_INT(OFS_RETURN) = br->numplanes;
else
{
out_faces->shadername = PR_TempString(prinst, br->faces[fa].tex->shadername);
VectorCopy(br->planes[fa], out_faces->planenormal);
out_faces->planedist = br->planes[fa][3];
maxfaces = min(br->numplanes, maxfaces);
VectorCopy(br->faces[fa].stdir[0], out_faces->sdir);
out_faces->sbias = br->faces[fa].stdir[0][3];
VectorCopy(br->faces[fa].stdir[1], out_faces->tdir);
out_faces->tbias = br->faces[fa].stdir[1][3];
for (fa = 0; fa < maxfaces; fa++)
{
out_faces->shadername = PR_TempString(prinst, br->faces[fa].tex->shadername);
VectorCopy(br->planes[fa], out_faces->planenormal);
out_faces->planedist = br->planes[fa][3];
out_faces++;
VectorCopy(br->faces[fa].stdir[0], out_faces->sdir);
out_faces->sbias = br->faces[fa].stdir[0][3];
VectorCopy(br->faces[fa].stdir[1], out_faces->tdir);
out_faces->tbias = br->faces[fa].stdir[1][3];
out_faces++;
}
G_INT(OFS_RETURN) = fa;
}
G_INT(OFS_RETURN) = fa;
return;
}
}

View File

@ -1042,7 +1042,7 @@ int CM_BoxLeafnums (struct model_s *mod, vec3_t mins, vec3_t maxs, int *list, i
int CM_PointContents (struct model_s *mod, vec3_t p);
int CM_TransformedPointContents (struct model_s *mod, vec3_t p, int headnode, vec3_t origin, vec3_t angles);
int CM_HeadnodeForBox (struct model_s *mod, vec3_t mins, vec3_t maxs);
struct trace_s CM_TransformedBoxTrace (struct model_s *mod, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int brushmask, vec3_t origin, vec3_t angles);
//struct trace_s CM_TransformedBoxTrace (struct model_s *mod, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int brushmask, vec3_t origin, vec3_t angles);
struct model_s *CM_TempBoxModel(vec3_t mins, vec3_t maxs);
void CMQ2_SetAreaPortalState (model_t *mod, unsigned int portalnum, qboolean open);

View File

@ -419,14 +419,14 @@ void R_SetupGL (float stereooffset)
}
else
{
x = r_refdef.vrect.x * (int)vid.fbpwidth/(int)vid.width;
x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * (int)vid.fbpwidth/(int)vid.width;
y = (r_refdef.vrect.y) * (int)vid.fbpheight/(int)vid.height;
y2 = (r_refdef.vrect.y + r_refdef.vrect.height) * (int)vid.fbpheight/(int)vid.height;
x = floor(r_refdef.vrect.x * (float)vid.fbpwidth/(float)vid.width);
x2 = ceil((r_refdef.vrect.x + r_refdef.vrect.width) * (float)vid.fbpwidth/(float)vid.width);
y = floor(r_refdef.vrect.y * (float)vid.fbpheight/(float)vid.height);
y2 = ceil((r_refdef.vrect.y + r_refdef.vrect.height) * (float)vid.fbpheight/(float)vid.height);
// fudge around because of frac screen scale
if (x > 0)
/* if (x > 0)
x--;
if (x2 < vid.fbpwidth)
x2++;
@ -434,7 +434,7 @@ void R_SetupGL (float stereooffset)
y2++;
if (y > 0)
y--;
*/
w = x2 - x;
h = y2 - y;

View File

@ -109,4 +109,15 @@ extern int qcc_eof;
#define qcc_iswhitesameline(c) ((c) == ' ' || (c) == '\t')
enum
{
UTF8_RAW,
UTF8_BOM,
UTF_ANSI,
UTF16LE,
UTF16BE,
UTF32LE,
UTF32BE,
};
#endif

View File

@ -380,6 +380,7 @@ enum qcop_e {
OP_BITCLR_F,
OP_BITCLR_I,
OP_ADD_SI,
OP_ADD_PF,
OP_ADD_FP,
OP_ADD_PI,

View File

@ -889,14 +889,6 @@ pbool SafeClose(int hand)
qcc_cachedsourcefile_t *qcc_sourcefile;
enum
{
UTF16LE,
UTF16BE,
UTF32LE,
UTF32BE,
};
//return 0 if the input is not valid utf-8.
unsigned int utf8_check(const void *in, unsigned int *value)
{
@ -968,14 +960,15 @@ static char *decodeUTF(int type, unsigned char *inputf, unsigned int inbytes, un
maxperchar = 4;
break;
default:
*outlen = inbytes;
return (char*)inputf;
//error
*outlen = 0;
return NULL;
}
chars = inbytes / w;
if (usemalloc)
utf8 = start = malloc(chars * maxperchar + 2);
utf8 = start = malloc(chars * maxperchar + 2+1);
else
utf8 = start = qccHunkAlloc(chars * maxperchar + 2);
utf8 = start = qccHunkAlloc(chars * maxperchar + 2+1);
for (i = 0; i < chars; i++)
{
switch(type)
@ -1048,6 +1041,7 @@ static char *decodeUTF(int type, unsigned char *inputf, unsigned int inbytes, un
}
}
*outlen = utf8 - start;
*utf8 = 0;
return start;
}
@ -1107,6 +1101,66 @@ unsigned short *QCC_makeutf16(char *mem, unsigned int len, int *outlen)
return outstart;
}
//input is a raw file (will not be changed
//output is utf-8 data
char *QCC_SanitizeCharSet(char *mem, unsigned int *len, pbool *freeresult, int *origfmt)
{
if (freeresult)
*freeresult = true;
if (*len >= 4 && mem[0] == '\xff' && mem[1] == '\xfe' && mem[2] == '\x00' && mem[3] == '\x00')
mem = decodeUTF(*origfmt=UTF32LE, (unsigned char*)mem+4, *len-4, len, !!freeresult);
else if (*len >= 4 && mem[0] == '\x00' && mem[1] == '\x00' && mem[2] == '\xfe' && mem[3] == '\xff')
mem = decodeUTF(*origfmt=UTF32BE, (unsigned char*)mem+4, *len-4, len, !!freeresult);
else if (*len >= 2 && mem[0] == '\xff' && mem[1] == '\xfe')
mem = decodeUTF(*origfmt=UTF16LE, (unsigned char*)mem+2, *len-2, len, !!freeresult);
else if (*len >= 2 && mem[0] == '\xfe' && mem[1] == '\xff')
mem = decodeUTF(*origfmt=UTF16BE, (unsigned char*)mem+2, *len-2, len, !!freeresult);
//utf-8 BOM, for compat with broken text editors (like windows notepad).
else if (*len >= 3 && mem[0] == '\xef' && mem[1] == '\xbb' && mem[2] == '\xbf')
{
*origfmt=UTF8_BOM;
mem += 3;
*len -= 3;
if (freeresult)
*freeresult = false;
}
else
{
*origfmt=UTF8_RAW;
if (freeresult)
*freeresult = false;
/*
#ifdef _WIN32
//even if we wrote the bom, resaving with wordpad will translate the file to the system's active code page, which will fuck up any comments. thanks for that, wordpad.
//(weirdly, notepad does the right thing)
int wchars = MultiByteToWideChar(CP_ACP, 0, mem, *len, NULL, 0);
if (wchars)
{
BOOL failed = false;
wchar_t *wc = malloc(wchars * sizeof(wchar_t));
int mchars;
MultiByteToWideChar(CP_ACP, 0, mem, *len, wc, wchars);
mchars = WideCharToMultiByte(CP_UTF8, 0, wc, wchars, NULL, 0, NULL, NULL);
if (mchars && !failed)
{
mem = (freeresult?malloc(mchars+2):qccHunkAlloc(mchars+2));
mem[mchars] = 0;
*len = mchars;
if (freeresult)
*freeresult = true;
WideCharToMultiByte(CP_UTF8, 0, wc, wchars, mem, mchars, NULL, NULL);
}
free(wc);
}
#endif
*/
}
return mem;
}
long QCC_LoadFile (char *filename, void **bufferptr)
{
char *mem;
@ -1114,6 +1168,7 @@ long QCC_LoadFile (char *filename, void **bufferptr)
int flen;
unsigned int len;
int line;
int orig;
pbool warned = false;
flen = externs->FileSize(filename);
if (flen < 0)
@ -1132,20 +1187,8 @@ long QCC_LoadFile (char *filename, void **bufferptr)
externs->ReadFile(filename, mem, len+2, NULL);
if (len >= 4 && mem[0] == '\xff' && mem[1] == '\xfe' && mem[2] == '\x00' && mem[3] == '\x00')
mem = decodeUTF(UTF32LE, (unsigned char*)mem+4, len-4, &len, false);
else if (len >= 4 && mem[0] == '\x00' && mem[1] == '\x00' && mem[2] == '\xfe' && mem[3] == '\xff')
mem = decodeUTF(UTF32BE, (unsigned char*)mem+4, len-4, &len, false);
else if (len >= 2 && mem[0] == '\xff' && mem[1] == '\xfe')
mem = decodeUTF(UTF16LE, (unsigned char*)mem+2, len-2, &len, false);
else if (len >= 2 && mem[0] == '\xfe' && mem[1] == '\xff')
mem = decodeUTF(UTF16BE, (unsigned char*)mem+2, len-2, &len, false);
//utf-8 BOM, for compat with broken text editors (like windows notepad).
else if (len >= 3 && mem[0] == '\xef' && mem[1] == '\xbb' && mem[2] == '\xbf')
{
mem += 3;
len -= 3;
}
mem = QCC_SanitizeCharSet(mem, &len, NULL, &orig);
//actual utf-8 handling is somewhat up to the engine. the qcc can only ensure that utf8 works in symbol names etc.
//its only in strings where it actually makes a difference, and the interpretation of those is basically entirely up to the engine.
//that said, we could insert a utf-8 BOM into ones with utf-8 chars, but that would mess up a lot of builtins+mods, so we won't.

View File

@ -620,6 +620,7 @@ QCC_opcode_t pr_opcodes[] =
{7, "&~", "BITCLR_F", 6, ASSOC_LEFT, &type_float, &type_float, &type_float},
{7, "&~", "BITCLR_I", 6, ASSOC_LEFT, &type_integer, &type_integer, &type_integer},
{7, "+", "ADD_SI", 4, ASSOC_LEFT, &type_string, &type_integer, &type_string},
{7, "+", "ADD_PF", 6, ASSOC_LEFT, &type_pointer, &type_float, &type_pointer},
{7, "+", "ADD_FP", 6, ASSOC_LEFT, &type_float, &type_pointer, &type_pointer},
{7, "+", "ADD_PI", 6, ASSOC_LEFT, &type_pointer, &type_integer, &type_pointer},
@ -1600,6 +1601,8 @@ static QCC_sref_t QCC_GetTemp(QCC_type_t *type)
tempsinfo[u].lastfunc = pr_scope;
tempsinfo[u].laststatement = numstatements;
var_c.sym->referenced = true;
return var_c;
}
@ -2536,7 +2539,10 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
{
//you're allowed to assign 0i to anything
if (op - pr_opcodes == OP_STORE_V) //make sure vectors get set properly.
{
QCC_FreeTemp(var_a);
var_a = QCC_MakeVectorConst(0, 0, 0);
}
}
/*else
{
@ -2570,7 +2576,10 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
{
//you're allowed to assign 0i to anything
if (op - pr_opcodes == OP_STOREP_V) //make sure vectors get set properly.
{
QCC_FreeTemp(var_a);
var_a = QCC_MakeVectorConst(0, 0, 0);
}
}
/*else
{
@ -2765,6 +2774,29 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
// QCC_PR_ParseWarning(0, "OP_LOADA_STRUCT: cannot emulate");
break;
case OP_ADD_SF:
var_c = QCC_PR_GetSRef(NULL, "AddStringFloat", NULL, false, 0, 0);
if (var_c.cast)
{
QCC_type_t *types[2] = {type_string, type_float};
QCC_sref_t evals[2];
evals[0] = var_a; //stupid msvc bug
evals[1] = var_b;
var_a = QCC_PR_GenerateFunctionCall(nullsref, var_c, evals, types, 2);
}
else
{
QCC_PR_ParseWarning(0, "string(string,float) AddStringFloat: emulation depends upon denormals");
var_b = QCC_SupplyConversion(var_b, ev_integer, true); //FIXME: this should be an unconditional float->int conversion
var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_F], var_a, var_b, NULL, 0);
}
var_c.cast = type_string;
return var_c;
case OP_ADD_SI:
QCC_PR_ParseWarning(0, "OP_ADD_SI: denormals may be unsafe");
var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_F], var_a, var_b, NULL, 0);
var_c.cast = type_string;
return var_c;
case OP_ADD_PF:
case OP_ADD_FP:
case OP_ADD_PI:
@ -2933,7 +2965,9 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
{
var_c = QCC_PR_GetSRef(NULL, "itof", NULL, false, 0, 0);
if (!var_c.cast)
{
QCC_PR_ParseError(0, "itof function not defined: cannot emulate int -> float conversions");
}
var_a = QCC_PR_GenerateFunctionCall(nullsref, var_c, &var_a, &type_integer, 1);
var_a.cast = type_float;
}
@ -2954,8 +2988,13 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
{
var_c = QCC_PR_GetSRef(NULL, "ftoi", NULL, false, 0, 0);
if (!var_c.cast)
QCC_PR_ParseError(0, "ftoi function not defined: cannot emulate float -> int conversions");
var_a = QCC_PR_GenerateFunctionCall(nullsref, var_c, &var_a, &type_float, 1);
{
//with denormals, 5 * 1i -> 5i
QCC_PR_ParseWarning(0, "ftoi emulation: denormals have limited precision");
var_a = QCC_PR_StatementFlags(&pr_opcodes[OP_MUL_F], var_a, QCC_MakeIntConst(1), NULL, 0);
}
else
var_a = QCC_PR_GenerateFunctionCall(nullsref, var_c, &var_a, &type_float, 1);
var_a.cast = type_integer;
}
if (var_b.cast)
@ -3178,6 +3217,11 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
var_c = var_b;
var_b = var_a;
var_a = var_c;
if (QCC_OPCodeValid(&pr_opcodes[OP_BITCLRSTORE_I]))
{
op = &pr_opcodes[OP_BITCLRSTORE_I];
break;
}
//fallthrough
case OP_BITCLRSTORE_I:
//b = var, a = bit field.
@ -3192,6 +3236,11 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
var_c = var_b;
var_b = var_a;
var_a = var_c;
if (QCC_OPCodeValid(&pr_opcodes[OP_BITCLRSTORE_F]))
{
op = &pr_opcodes[OP_BITCLRSTORE_F];
break;
}
//fallthrough
case OP_BITCLRSTORE_F:
//b = var, a = bit field.
@ -3594,11 +3643,20 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
statement->b = var_b;
if (var_c.cast && var_c.sym && !var_c.sym->referenced)
printf("that wasn't referenced\n");
if (var_b.cast && var_a.sym && !var_b.sym->referenced)
printf("that wasn't referenced\n");
if (var_a.cast && var_b.sym && !var_a.sym->referenced)
printf("that wasn't referenced\n");
{
QCC_PR_ParseWarning(WARN_DEBUGGING, "INTERNAL: var_c was not referenced");
QCC_PR_ParsePrintSRef(WARN_DEBUGGING, var_c);
}
if (var_b.cast && var_b.sym && !var_b.sym->referenced)
{
QCC_PR_ParseWarning(WARN_DEBUGGING, "INTERNAL: var_b was not referenced");
QCC_PR_ParsePrintSRef(WARN_DEBUGGING, var_b);
}
if (var_a.cast && var_a.sym && !var_a.sym->referenced)
{
QCC_PR_ParseWarning(WARN_DEBUGGING, "INTERNAL: var_a was not referenced");
QCC_PR_ParsePrintSRef(WARN_DEBUGGING, var_a);
}
if (var_c.cast)
statement->c = var_c;
@ -5692,6 +5750,8 @@ static QCC_ref_t *QCC_PR_ParseField(QCC_ref_t *refbuf, QCC_ref_t *lhs)
}
lhs = QCC_PR_ParseField(refbuf, lhs);
lhs = QCC_PR_ParseRefArrayPointer (refbuf, lhs, false, false);
}
else if (t->accessors && (QCC_PR_CheckToken(".") || QCC_PR_CheckToken("->")))
{
@ -9177,7 +9237,8 @@ void QCC_PR_ParseState (void)
s1 = QCC_PR_Expression (TOP_PRIORITY, EXPR_DISALLOW_COMMA);
s1 = QCC_SupplyConversion(s1, ev_float, true);
QCC_PR_Expect (",");
if (!QCC_PR_CheckToken (","))
QCC_PR_ParseWarning(WARN_UNEXPECTEDPUNCT, "missing comma in state definition");
pr_assumetermtype = type_function;
def = QCC_PR_Expression (TOP_PRIORITY, EXPR_DISALLOW_COMMA);
@ -11225,7 +11286,7 @@ QCC_sref_t QCC_PR_GetSRef (QCC_type_t *type, char *name, QCC_function_t *scope,
return nullsref;
}
QCC_def_t *QCC_PR_DummyFieldDef(QCC_type_t *type, char *name, QCC_function_t *scope, int arraysize, unsigned int *fieldofs, pbool saved)
QCC_def_t *QCC_PR_DummyFieldDef(QCC_type_t *type, char *name, QCC_function_t *scope, int arraysize, unsigned int *fieldofs, unsigned int saved)
{
char array[64];
char newname[256];
@ -11326,7 +11387,7 @@ QCC_def_t *QCC_PR_DummyFieldDef(QCC_type_t *type, char *name, QCC_function_t *sc
def = QCC_PR_GetDef(ftype, newname, scope, true, 0, saved);
if (parttype->type == ev_function)
def->initialized = true;
((int *)qcc_pr_globals)[def->ofs] = *fieldofs;
def->symboldata->_int = *fieldofs;
*fieldofs += parttype->size;
}
else
@ -11334,6 +11395,7 @@ QCC_def_t *QCC_PR_DummyFieldDef(QCC_type_t *type, char *name, QCC_function_t *sc
QCC_PR_ParseWarning(WARN_CONFLICTINGUNIONMEMBER, "conflicting offsets for union/struct expansion of %s. Ignoring new def.", newname);
QCC_PR_ParsePrintDef(WARN_CONFLICTINGUNIONMEMBER, def);
}
QCC_FreeDef(def);
break;
case ev_void:
break;
@ -11355,7 +11417,7 @@ QCC_def_t *QCC_PR_DummyFieldDef(QCC_type_t *type, char *name, QCC_function_t *sc
void QCC_PR_ExpandUnionToFields(QCC_type_t *type, unsigned int *fields)
{
QCC_type_t *pass = type->aux_type;
QCC_PR_DummyFieldDef(pass, "", pr_scope, 1, fields, true);
QCC_PR_DummyFieldDef(pass, "", pr_scope, 1, fields, GDF_SAVED|GDF_CONST);
}
void QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *basedef, QCC_sref_t def)

View File

@ -234,6 +234,7 @@ typedef struct editor_s {
int curline;
pbool modified;
pbool scintilla;
int savefmt;
time_t filemodifiedtime;
struct editor_s *next;
} editor_t;
@ -1069,7 +1070,7 @@ void GenericMenu(WPARAM wParam)
break;
case IDM_ABOUT:
MessageBox(NULL, "FTE QuakeC Compiler ("__DATE__" "__TIME__")\nWritten by Forethought Entertainment, whoever that is.\n\n", "About", 0);
MessageBox(NULL, "FTE QuakeC Compiler ("__DATE__" "__TIME__")\nWritten by Forethought Entertainment, whoever that is.\n\nIf you have problems with wordpad corrupting your qc files, try saving them using utf-16 encoding via notepad.", "About", 0);
break;
case IDM_CASCADE:
@ -1796,23 +1797,31 @@ static LRESULT CALLBACK EditorWndProc(HWND hWnd,UINT message,
}
unsigned short *QCC_makeutf16(char *mem, unsigned int len, int *outlen);
char *QCC_SanitizeCharSet(char *mem, unsigned int *len, pbool *freeresult, int *origfmt);
static void EditorReload(editor_t *editor)
{
struct stat sbuf;
int flen;
char *rawfile;
char *file;
pbool dofree;
flen = QCC_RawFileSize(editor->filename);
if (flen >= 0)
{
file = malloc(flen+1);
rawfile = malloc(flen+1);
QCC_ReadFile(editor->filename, file, flen, NULL);
QCC_ReadFile(editor->filename, rawfile, flen, NULL);
file[flen] = 0;
rawfile[flen] = 0;
}
else
file = NULL;
{
rawfile = NULL;
flen = 0;
}
file = QCC_SanitizeCharSet(rawfile, &flen, &dofree, &editor->savefmt);
stat(editor->filename, &sbuf);
editor->filemodifiedtime = sbuf.st_mtime;
@ -1849,7 +1858,9 @@ static void EditorReload(editor_t *editor)
SendMessage(editor->editpane, EM_SETEVENTMASK, 0, ENM_SELCHANGE|ENM_CHANGE);
}
free(file);
if (dofree)
free(file);
free(rawfile);
editor->modified = false;
}
@ -1916,6 +1927,7 @@ void EditFile(char *name, int line, pbool setcontrol)
neweditor->next = editors;
editors = neweditor;
neweditor->savefmt = UTF8_RAW;
strncpy(neweditor->filename, name, sizeof(neweditor->filename)-1);
if (!mdibox)
@ -2016,24 +2028,88 @@ int EditorSave(editor_t *edit)
int len;
wchar_t *wfile;
char *afile;
BOOL failed = TRUE;
int saved = false;
if (edit->scintilla)
{
//wordpad will corrupt any embedded quake chars if we force a bom, because it'll re-save using the wrong char encoding by default.
int bomlen = 0;
if (edit->savefmt == UTF32BE || edit->savefmt == UTF32LE || edit->savefmt == UTF16BE)
edit->savefmt = UTF16LE;
if (edit->savefmt == UTF8_BOM)
bomlen = 3;
else if (edit->savefmt == UTF16BE || edit->savefmt == UTF16LE)
bomlen = 2;
else if (edit->savefmt == UTF32BE || edit->savefmt == UTF32LE)
bomlen = 4;
len = SendMessage(edit->editpane, SCI_GETLENGTH, 0, 0);
afile = malloc(len+1);
afile = malloc(bomlen+len+1);
if (!afile)
{
MessageBox(NULL, "Save failed - not enough mem", "Error", 0);
return false;
}
SendMessage(edit->editpane, SCI_GETTEXT, len+1, (LPARAM)afile);
if (!QCC_WriteFile(edit->filename, afile, len))
if (bomlen == 3)
memcpy(afile, "\xEF\xBB\xBF", bomlen);
else
memcpy(afile, "\xFF\xFE\x00\x00", bomlen); //utf-16le or utf-32le. don't bother with be
SendMessage(edit->editpane, SCI_GETTEXT, len+1, bomlen+(LPARAM)afile);
//because wordpad saves in ansi by default instead of the format the file was originally saved in, we HAVE to use ansi without
if (edit->savefmt != UTF8_BOM && edit->savefmt != UTF8_RAW)
{
int mchars;
char *mc;
int wchars = MultiByteToWideChar(CP_UTF8, 0, afile, len, NULL, 0);
if (wchars)
{
wchar_t *wc = malloc(wchars * sizeof(wchar_t));
MultiByteToWideChar(CP_UTF8, 0, afile, len, wc, wchars);
if (edit->savefmt == UTF_ANSI)
{
mchars = WideCharToMultiByte(CP_ACP, 0, wc, wchars, NULL, 0, "", &failed);
if (mchars)
{
mc = malloc(mchars);
WideCharToMultiByte(CP_ACP, 0, wc, wchars, mc, mchars, "", &failed);
if (!failed)
{
if (!QCC_WriteFile(edit->filename, mc, mchars))
saved = -1;
else
saved = true;
}
free(mc);
}
}
else
{
if (!QCC_WriteFile(edit->filename, wc, wchars))
saved = -1;
else
saved = true;
}
free(wc);
}
}
if (!saved)
{
if (!QCC_WriteFile(edit->filename, afile, bomlen+len))
saved = -1;
else
saved = true;
}
free(afile);
if (saved < 0)
{
free(afile);
MessageBox(NULL, "Save failed\nCheck path and ReadOnly flags", "Failure", 0);
return false;
}
SendMessage(edit->editpane, SCI_SETSAVEPOINT, 0, 0);
free(afile);
}
else
{
@ -3771,9 +3847,202 @@ void GUIPrint(HWND wnd, char *msg)
}
writing=false;
}
unsigned int utf8_decode(int *error, const void *in, char **out)
{
//uc is the output unicode char
unsigned int uc = 0xfffdu; //replacement character
//l is the length
unsigned int l = 1;
const unsigned char *str = in;
if ((*str & 0xe0) == 0xc0)
{
if ((str[1] & 0xc0) == 0x80)
{
l = 2;
uc = ((str[0] & 0x1f)<<6) | (str[1] & 0x3f);
if (!uc || uc >= (1u<<7)) //allow modified utf-8
*error = 0;
else
*error = 2;
}
else *error = 1;
}
else if ((*str & 0xf0) == 0xe0)
{
if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80)
{
l = 3;
uc = ((str[0] & 0x0f)<<12) | ((str[1] & 0x3f)<<6) | ((str[2] & 0x3f)<<0);
if (uc >= (1u<<11))
*error = 0;
else
*error = 2;
}
else *error = 1;
}
else if ((*str & 0xf8) == 0xf0)
{
if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 && (str[3] & 0xc0) == 0x80)
{
l = 4;
uc = ((str[0] & 0x07)<<18) | ((str[1] & 0x3f)<<12) | ((str[2] & 0x3f)<<6) | ((str[3] & 0x3f)<<0);
if (uc >= (1u<<16))
*error = 0;
else
*error = 2;
}
else *error = 1;
}
else if ((*str & 0xfc) == 0xf8)
{
if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 && (str[3] & 0xc0) == 0x80 && (str[4] & 0xc0) == 0x80)
{
l = 5;
uc = ((str[0] & 0x03)<<24) | ((str[1] & 0x3f)<<18) | ((str[2] & 0x3f)<<12) | ((str[3] & 0x3f)<<6) | ((str[4] & 0x3f)<<0);
if (uc >= (1u<<21))
*error = 0;
else
*error = 2;
}
else *error = 1;
}
else if ((*str & 0xfe) == 0xfc)
{
//six bytes
if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 && (str[3] & 0xc0) == 0x80 && (str[4] & 0xc0) == 0x80)
{
l = 6;
uc = ((str[0] & 0x01)<<30) | ((str[1] & 0x3f)<<24) | ((str[2] & 0x3f)<<18) | ((str[3] & 0x3f)<<12) | ((str[4] & 0x3f)<<6) | ((str[5] & 0x3f)<<0);
if (uc >= (1u<<26))
*error = 0;
else
*error = 2;
}
else *error = 1;
}
//0xfe and 0xff, while plausable leading bytes, are not permitted.
#if 0
else if ((*str & 0xff) == 0xfe)
{
if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 && (str[3] & 0xc0) == 0x80 && (str[4] & 0xc0) == 0x80)
{
l = 7;
uc = 0 | ((str[1] & 0x3f)<<30) | ((str[2] & 0x3f)<<24) | ((str[3] & 0x3f)<<18) | ((str[4] & 0x3f)<<12) | ((str[5] & 0x3f)<<6) | ((str[6] & 0x3f)<<0);
if (uc >= (1u<<31))
*error = 0;
else
*error = 2;
}
else *error = 1;
}
else if ((*str & 0xff) == 0xff)
{
if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 && (str[3] & 0xc0) == 0x80 && (str[4] & 0xc0) == 0x80)
{
l = 8;
uc = 0 | ((str[1] & 0x3f)<<36) | ((str[2] & 0x3f)<<30) | ((str[3] & 0x3f)<<24) | ((str[4] & 0x3f)<<18) | ((str[5] & 0x3f)<<12) | ((str[6] & 0x3f)<<6) | ((str[7] & 0x3f)<<0);
if (uc >= (1llu<<36))
*error = false;
else
*error = 2;
}
else *error = 1;
}
#endif
else if (*str & 0x80)
{
//sequence error
*error = 1;
uc = 0xe000u + *str;
}
else
{
//ascii char
*error = 0;
uc = *str;
}
*out = (void*)(str + l);
if (!*error)
{
//try to deal with surrogates by decoding the low if we see a high.
if (uc >= 0xd800u && uc < 0xdc00u)
{
#if 1
//cesu-8
char *lowend;
unsigned int lowsur = utf8_decode(error, str + l, &lowend);
if (*error == 4)
{
*out = lowend;
uc = (((uc&0x3ffu) << 10) | (lowsur&0x3ffu)) + 0x10000;
*error = false;
}
else
#endif
{
*error = 3; //bad - lead surrogate without tail.
}
}
if (uc >= 0xdc00u && uc < 0xe000u)
*error = 4; //bad - tail surrogate
//these are meant to be illegal too
if (uc == 0xfffeu || uc == 0xffffu || uc > 0x10ffffu)
*error = 2; //illegal code
}
return uc;
}
//outlen is the size of out in _BYTES_.
wchar_t *widen(wchar_t *out, size_t outbytes, const char *utf8, const char *stripchars)
{
size_t outlen;
wchar_t *ret = out;
//utf-8 to utf-16, not ucs-2.
unsigned int codepoint;
int error;
outlen = outbytes/sizeof(wchar_t);
if (!outlen)
return L"";
outlen--;
while (*utf8)
{
if (stripchars && strchr(stripchars, *utf8))
{ //skip certain ascii chars
utf8++;
continue;
}
codepoint = utf8_decode(&error, utf8, (void*)&utf8);
if (error || codepoint > 0x10FFFFu)
codepoint = 0xFFFDu;
if (codepoint > 0xffff)
{
if (outlen < 2)
break;
outlen -= 2;
codepoint -= 0x10000u;
*out++ = 0xD800 | (codepoint>>10);
*out++ = 0xDC00 | (codepoint&0x3ff);
}
else
{
if (outlen < 1)
break;
outlen -= 1;
*out++ = codepoint;
}
}
*out = 0;
return ret;
}
int GUIEmitOutputText(HWND wnd, int start, char *text, int len, DWORD colour)
{
int c, cr;
wchar_t wc[2048];
int c;
CHARFORMAT cf;
if (!len)
@ -3781,17 +4050,12 @@ int GUIEmitOutputText(HWND wnd, int start, char *text, int len, DWORD colour)
c = text[len];
text[len] = '\0';
Edit_SetSel(wnd,start,start);
Edit_ReplaceSel(wnd,text);
// wc = QCC_makeutf16(text, len, &ol);
widen(wc, sizeof(wc), text, "\r");
text[len] = c;
cr = 0;
for (c = 0; c < len; c++)
if (text[c] == '\r')
cr++;
if (cr)
len-=cr;
Edit_SetSel(wnd,start,start);
SendMessageW(wnd, EM_REPLACESEL, 0L, (LPARAM)wc);
len = wcslen(wc);
Edit_SetSel(wnd,start,start+len);
memset(&cf, 0, sizeof(cf));
@ -3806,6 +4070,7 @@ int GUIEmitOutputText(HWND wnd, int start, char *text, int len, DWORD colour)
}
int outlen;
int outstatus;
pbool gui_doannotates;
int GUIprintf(const char *msg, ...)
{
va_list argptr;
@ -3847,10 +4112,13 @@ int GUIprintf(const char *msg, ...)
outstatus = 0;
for (ed = editors; ed; ed = ed->next)
if (gui_doannotates)
{
if (ed->scintilla)
SendMessage(ed->editpane, SCI_ANNOTATIONCLEARALL, 0, 0);
for (ed = editors; ed; ed = ed->next)
{
if (ed->scintilla)
SendMessage(ed->editpane, SCI_ANNOTATIONCLEARALL, 0, 0);
}
}
return 0;
}
@ -3891,6 +4159,7 @@ int GUIprintf(const char *msg, ...)
outlen = GUIEmitOutputText(outputbox, outlen, rn, 1, col);
}
if (gui_doannotates)
{
char *colon1 = strchr(st, ':');
if (colon1)
@ -4060,11 +4329,13 @@ void RunCompiler(char *args, pbool quick)
}
void CreateOutputWindow(void)
void CreateOutputWindow(pbool doannoates)
{
WNDCLASS wndclass;
MDICREATESTRUCT mcs;
gui_doannotates = doannoates;
if (!mdibox) //should already be created
return;
@ -4149,7 +4420,7 @@ int GrepSubFiles(HTREEITEM node, char *string)
void GrepAllFiles(char *string)
{
int found;
CreateOutputWindow();
CreateOutputWindow(false);
GUIprintf("");
found = GrepSubFiles(TreeView_GetChild(projecttree, TVI_ROOT), string);
if (found)
@ -4456,7 +4727,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
if (fl_compileonstart)
{
CreateOutputWindow();
CreateOutputWindow(false);
RunCompiler(lpCmdLine, false);
}
else
@ -4500,7 +4771,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
{
if (buttons[ID_COMPILE].washit)
{
CreateOutputWindow();
CreateOutputWindow(true);
RunCompiler(parameters, false);
buttons[ID_COMPILE].washit = false;

View File

@ -90,9 +90,9 @@ void GoToDefinition(char *name)
{
//with functions, the def is the prototype.
//we want the body, so zoom to the first statement of the function instead
if (def->type->type == ev_function && def->constant)
if (def->type->type == ev_function && def->constant && !def->arraysize)
{
fnc = &functions[((int *)qcc_pr_globals)[def->ofs]];
fnc = &functions[def->symboldata->function];
if (fnc->code>=0 && fnc->s_file)
{
EditFile(strings+fnc->s_file, statements[fnc->code].linenum-1, false);

View File

@ -815,7 +815,8 @@ void QCC_UnmarshalLocals(void)
}
}
numpr_globals = biggest;
printf("%i shared locals, %i private, %i total\n", biggest - onum, onum - eog, numpr_globals-eog);
if (verbose)
printf("%i shared locals, %i private, %i total\n", biggest - onum, onum - eog, numpr_globals-eog);
}

View File

@ -1772,7 +1772,10 @@ void SV_ClientProtocolExtensionsChanged(client_t *client)
{
client->max_net_clients = NQMAX_CLIENTS;
client->datagram.maxsize = MAX_NQDATAGRAM; //vanilla limit
client->max_net_ents = bound(512, pr_maxedicts.ival, 600);
if (client->protocol == SCP_PROQUAKE)
client->max_net_ents = bound(512, pr_maxedicts.ival, 8192);
else
client->max_net_ents = bound(512, pr_maxedicts.ival, 600);
}
if (client->fteprotocolextensions2 & PEXT2_MAXPLAYERS)

View File

@ -1538,7 +1538,7 @@ void SVQW_Spawn_f (void)
}
if (host_client->prespawn_stage != PRESPAWN_DONE)
{
Con_Printf ("client sent spawn without prespawn!\n");
Con_Printf ("%s sent spawn without prespawn!\n", host_client->name);
SV_New_f ();
return;
}

View File

@ -574,16 +574,23 @@ static int SVQ3_Contact(vec3_t mins, vec3_t maxs, q3sharedEntity_t *ent, qboolea
{
model_t *mod;
trace_t tr;
float *ang;
if (ent->r.bmodel)
{
ang = ent->r.currentAngles;
mod = Q3G_GetCModel(ent->s.modelindex);
}
else
{
ang = vec3_origin;
mod = CM_TempBoxModel(ent->r.mins, ent->r.maxs);
}
if (!mod || !mod->funcs.NativeTrace)
return false;
tr = CM_TransformedBoxTrace(mod, vec3_origin, vec3_origin, mins, maxs, 0xffffffff, ent->r.currentOrigin, ent->r.currentAngles);
World_TransformedTrace(mod, 0, 0, vec3_origin, vec3_origin, mins, maxs, capsule, &tr, ent->r.currentOrigin, ang, 0xffffffff);
if (tr.startsolid)
return true;

File diff suppressed because it is too large Load Diff

View File

@ -556,10 +556,10 @@ void JCL_Join(jclient_t *jcl, char *target, char *sid, qboolean allow, int proto
JCL_GenLink(jcl, convolink, sizeof(convolink), NULL, target, NULL, NULL, "%s", target);
JCL_GenLink(jcl, hanguplink, sizeof(hanguplink), "jdeny", target, NULL, c2c->sid, "%s", "Hang Up");
Con_SubPrintf(b->name, "%s %s %s.\n", protocol==ICEP_VOICE?"Calling":"Requesting session with", convolink, hanguplink);
XMPP_ConversationPrintf(b->accountdomain, b->name, "%s %s %s.\n", protocol==ICEP_VOICE?"Calling":"Requesting session with", convolink, hanguplink);
}
else
Con_SubPrintf(b->name, "That session has expired.\n");
XMPP_ConversationPrintf(b->accountdomain, b->name, "That session has expired.\n");
}
else if (c2c->creator)
{
@ -567,16 +567,16 @@ void JCL_Join(jclient_t *jcl, char *target, char *sid, qboolean allow, int proto
//resend initiate if they've not acked it... I dunno...
JCL_JingleSend(jcl, c2c, "session-initiate");
JCL_GenLink(jcl, convolink, sizeof(convolink), NULL, target, NULL, NULL, "%s", target);
Con_SubPrintf(b->name, "Restarting session with %s.\n", convolink);
XMPP_ConversationPrintf(b->accountdomain, b->name, "Restarting session with %s.\n", convolink);
}
else if (c2c->accepted)
Con_SubPrintf(b->name, "That session was already accepted.\n");
XMPP_ConversationPrintf(b->accountdomain, b->name, "That session was already accepted.\n");
else
{
char convolink[512];
JCL_JingleSend(jcl, c2c, "session-accept");
JCL_GenLink(jcl, convolink, sizeof(convolink), NULL, target, NULL, NULL, "%s", target);
Con_SubPrintf(b->name, "Accepting session from %s.\n", convolink);
XMPP_ConversationPrintf(b->accountdomain, b->name, "Accepting session from %s.\n", convolink);
}
}
else
@ -586,10 +586,10 @@ void JCL_Join(jclient_t *jcl, char *target, char *sid, qboolean allow, int proto
char convolink[512];
JCL_JingleSend(jcl, c2c, "session-terminate");
JCL_GenLink(jcl, convolink, sizeof(convolink), NULL, target, NULL, NULL, "%s", target);
Con_SubPrintf(b->name, "Terminating session with %s.\n", convolink);
XMPP_ConversationPrintf(b->accountdomain, b->name, "Terminating session with %s.\n", convolink);
}
else
Con_SubPrintf(b->name, "That session has already expired.\n");
XMPP_ConversationPrintf(b->accountdomain, b->name, "That session has already expired.\n");
}
}
@ -805,7 +805,7 @@ static qboolean JCL_JingleHandleInitiate_GoogleSession(jclient_t *jcl, xmltree_t
char convolink[512];
JCL_JingleSend(jcl, c2c, "terminate");
JCL_GenLink(jcl, convolink, sizeof(convolink), NULL, from, NULL, NULL, "%s", b->name);
Con_SubPrintf(b->name, "%s does not support any compatible audio codecs, and is unable to call you.\n", convolink);
XMPP_ConversationPrintf(b->accountdomain, b->name, "%s does not support any compatible audio codecs, and is unable to call you.\n", convolink);
return false;
}
}
@ -822,14 +822,14 @@ static qboolean JCL_JingleHandleInitiate_GoogleSession(jclient_t *jcl, xmltree_t
JCL_GenLink(jcl, denylink, sizeof(denylink), "jdeny", from, NULL, sid, "%s", "Reject");
//show a prompt for it, send the reply when the user decides.
Con_SubPrintf(b->name,
XMPP_ConversationPrintf(b->accountdomain, b->name,
"%s %s. %s %s\n", convolink, offer, authlink, denylink);
pCon_SetActive(b->name);
return true;
}
else
{
Con_SubPrintf(b->name, "Auto-accepting session from %s\n", convolink);
XMPP_ConversationPrintf(b->accountdomain, b->name, "Auto-accepting session from %s\n", convolink);
response = "accept";
}
}
@ -938,7 +938,7 @@ static struct c2c_s *JCL_JingleHandleInitiate(jclient_t *jcl, xmltree_t *inj, ch
{
char convolink[512];
JCL_GenLink(jcl, convolink, sizeof(convolink), NULL, from, NULL, NULL, "%s", b->name);
Con_SubPrintf(b->name, "%s does not support any compatible codecs, and is unable to call you.\n", convolink);
XMPP_ConversationPrintf(b->accountdomain, b->name, "%s does not support any compatible codecs, and is unable to call you.\n", convolink);
if (c2c->content[c].ice)
piceapi->ICE_Close(c2c->content[c].ice);
@ -974,14 +974,14 @@ static qboolean JCL_JingleHandleSessionTerminate(jclient_t *jcl, xmltree_t *tree
int c;
if (!c2c)
{
Con_Printf("Received session-terminate without an active session\n");
XMPP_ConversationPrintf(b->accountdomain, b->name, "Received session-terminate without an active session\n");
return false;
}
if (reason && reason->child)
Con_SubPrintf(b->name, "Session ended: %s\n", reason->child->name);
XMPP_ConversationPrintf(b->accountdomain, b->name, "Session ended: %s\n", reason->child->name);
else
Con_SubPrintf(b->name, "Session ended\n");
XMPP_ConversationPrintf(b->accountdomain, b->name, "Session ended\n");
//unlink it
for (link = &jcl->c2c; *link; link = &(*link)->next)
@ -1032,7 +1032,7 @@ static qboolean JCL_JingleHandleSessionAccept(jclient_t *jcl, xmltree_t *tree, c
{
return false;
}
Con_SubPrintf(b->name, "Session Accepted!\n");
XMPP_ConversationPrintf(b->accountdomain, b->name, "Session Accepted!\n");
// XML_ConPrintTree(tree, 0);
JCL_JingleParsePeerPorts(jcl, c2c, tree, from, XML_GetParameter(tree, "sid", ""));
@ -1324,13 +1324,13 @@ qboolean JCL_ParseJingle(jclient_t *jcl, xmltree_t *tree, char *from, char *id)
JCL_GenLink(jcl, denylink, sizeof(denylink), "jdeny", from, NULL, sid, "%s", "Reject");
//show a prompt for it, send the reply when the user decides.
Con_SubPrintf(b->name,
XMPP_ConversationPrintf(b->accountdomain, b->name,
"%s %s. %s %s\n", convolink, offer, authlink, denylink);
pCon_SetActive(b->name);
pCon_SetActive(b->accountdomain);
}
else
{
Con_SubPrintf(b->name, "Auto-accepting session from %s\n", convolink);
XMPP_ConversationPrintf(b->accountdomain, b->name, "Auto-accepting session from %s\n", convolink);
JCL_Join(jcl, from, sid, true, ICEP_INVALID);
}
}

View File

@ -2,7 +2,7 @@ typedef struct xmlparams_s
{
char val[256]; //FIXME: make pointer
struct xmlparams_s *next;
char name[64]; //FIXME: make variable sized
char name[128]; //FIXME: make variable sized
} xmlparams_t;
typedef struct subtree_s
@ -34,4 +34,4 @@ xmltree_t *XML_ChildOfTreeNS(xmltree_t *t, char *xmlns, char *name, int childnum
char *XML_GetChildBody(xmltree_t *t, char *paramname, char *def);
void XML_ConPrintTree(xmltree_t *t, char *subconsole, int indent);
xmltree_t *XML_FromJSON(xmltree_t *t, char *name, char *json, int *jsonpos, int jsonlen);
xmltree_t *XML_FromJSON(xmltree_t *t, char *name, char *json, int *jsonpos, int jsonlen);

View File

@ -9,7 +9,7 @@
#define FILETRANSFERS //IBB only, speeds suck. autoaccept is forced on. no protection from mods stuffcmding sendfile commands. needs more extensive testing
#define QUAKECONNECT //including quake ICE connections (depends upon jingle)
#define VOIP //enables voice chat (depends upon jingle)
#define VOIP_LEGACY //enables google-only voice chat compat. google have not kept up with the standardisation of jingle (aka: gingle).
//#define VOIP_LEGACY //enables google-only voice chat compat. google have not kept up with the standardisation of jingle (aka: gingle).
//#define VOIP_LEGACY_ONLY //disables jingle feature (advert+detection only)
#define JINGLE //enables jingle signalling
@ -21,7 +21,7 @@
#endif
#define JCL_BUILD "3"
#define JCL_BUILD "4"
#define DEFAULTDOMAIN ""
#define DEFAULTRESOURCE "Quake"
#define QUAKEMEDIAXMLNS "http://fteqw.com/protocol/quake"
@ -34,7 +34,7 @@
#define JCL_MAXMSGLEN 10000
#define JCL_MAXMSGLEN 0x10000
//values are not on the wire or anything
#define CAP_VOICE (1u<<0) //supports voice
@ -60,6 +60,7 @@ typedef struct bresource_s
char fstatus[128]; //full status
char server[256];
int servertype; //0=none, 1=already a client, 2=joinable
int priority;
unsigned int buggycaps;
unsigned int caps;
@ -102,6 +103,7 @@ typedef struct jclient_s
JCL_ACTIVE //we're connected, we got a buddy list and everything
} status;
unsigned int timeout; //reconnect/ping timer
char errormsg[256];
unsigned int enabledcapabilities;
@ -260,7 +262,20 @@ typedef struct jclient_s
int privateidseq;
#endif
//persistant achived info about buddies, to avoid spamming the server every time we connect
//such things might result in lag mid game!
struct buddyinfo_s
{
struct buddyinfo_s *next;
char *image;
char *imagehash;
char *imagemime;
char accountdomain[1];
} *buddyinfo;
buddy_t *buddies;
struct iq_s *avatarupdate; //we only grab one buddy's photo at a time, this is to avoid too much spam.
} jclient_t;
@ -279,7 +294,8 @@ qboolean JCL_FindBuddy(jclient_t *jcl, char *jid, buddy_t **buddy, bresource_t *
//quake functionality
void JCL_GenLink(jclient_t *jcl, char *out, int outlen, char *action, char *context, char *contextres, char *sid, char *txtfmt, ...);
void Con_SubPrintf(char *subname, char *format, ...);
void Con_SubPrintf(const char *subname, char *format, ...);
void XMPP_ConversationPrintf(const char *context, const char *title, char *format, ...);
//jingle functions
void JCL_Join(jclient_t *jcl, char *target, char *sid, qboolean allow, int protocol);