2005-12-15 19:41:11 +00:00
|
|
|
//included directly from plugin.c
|
|
|
|
//this is the client-only things.
|
|
|
|
|
|
|
|
static plugin_t *protocolclientplugin;
|
|
|
|
|
|
|
|
|
2021-07-01 21:05:45 +00:00
|
|
|
static void PlugMenu_Close(menu_t *m, qboolean forced)
|
2019-09-04 07:59:40 +00:00
|
|
|
{
|
|
|
|
Z_Free(m);
|
|
|
|
}
|
|
|
|
static qboolean PlugMenu_Event(menu_t *m, int eventtype, int keyparam, int unicodeparam) //eventtype = draw/keydown/keyup, param = time/key
|
|
|
|
{
|
|
|
|
plugin_t *oc=currentplug;
|
|
|
|
qboolean ret;
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
currentplug = m->ctx;
|
|
|
|
ret = currentplug->menufunction(eventtype, keyparam, unicodeparam, mousecursor_x, mousecursor_y, vid.width, vid.height);
|
|
|
|
currentplug=oc;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
static qboolean PlugMenu_KeyEvent(menu_t *m, qboolean isdown, unsigned int devid, int key, int unicode)
|
|
|
|
{
|
|
|
|
return PlugMenu_Event(m, isdown?1:2, key, unicode);
|
|
|
|
}
|
|
|
|
static void PlugMenu_Draw(menu_t *m)
|
|
|
|
{
|
|
|
|
PlugMenu_Event (m, 0, (realtime*1000), 0);
|
|
|
|
}
|
|
|
|
static qboolean QDECL Plug_SetMenuFocus (qboolean wantkeyfocus, const char *cursorname, float hot_x, float hot_y, float scale) //null cursorname=relmouse, set/empty cursorname=absmouse
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
menu_t *m;
|
2010-02-06 01:25:04 +00:00
|
|
|
if (qrenderer == QR_NONE)
|
2019-09-04 07:59:40 +00:00
|
|
|
return false;
|
2006-01-02 23:01:54 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
m = Menu_FindContext(currentplug);
|
|
|
|
|
|
|
|
if (wantkeyfocus)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
if (!m)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
m = Z_Malloc(sizeof(*m));
|
|
|
|
m->ctx = currentplug;
|
|
|
|
m->cursor = &key_customcursor[kc_plugin];
|
|
|
|
m->release = PlugMenu_Close;
|
|
|
|
m->keyevent = PlugMenu_KeyEvent;
|
|
|
|
m->drawmenu = PlugMenu_Draw;
|
|
|
|
Menu_Push(m, false);
|
2005-12-15 19:41:11 +00:00
|
|
|
}
|
|
|
|
}
|
2019-09-04 07:59:40 +00:00
|
|
|
else if (m)
|
2021-07-01 21:05:45 +00:00
|
|
|
Menu_Unlink(m, false);
|
2019-09-04 07:59:40 +00:00
|
|
|
|
|
|
|
if (wantkeyfocus)
|
|
|
|
{
|
|
|
|
struct key_cursor_s *mc = &key_customcursor[kc_plugin];
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
if (cursorname)
|
|
|
|
{
|
|
|
|
if (scale <= 0)
|
|
|
|
scale = 1;
|
|
|
|
if (strcmp(cursorname, mc->name) || mc->hotspot[0] != hot_x || mc->hotspot[1] != hot_y || mc->scale != scale)
|
|
|
|
{
|
|
|
|
Q_strncpyz(mc->name, cursorname, sizeof(mc->name));
|
|
|
|
mc->hotspot[0] = hot_x;
|
|
|
|
mc->hotspot[1] = hot_y;
|
|
|
|
mc->scale = scale;
|
|
|
|
mc->dirty = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
static qboolean QDECL Plug_HasMenuFocus(void)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
return topmenu&&topmenu->ctx==currentplug && Key_Dest_Has(kdm_menu);
|
2005-12-15 19:41:11 +00:00
|
|
|
}
|
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static int QDECL Plug_Key_GetKeyCode(const char *keyname, int *modifier)
|
|
|
|
{
|
|
|
|
int modifier_;
|
|
|
|
if (!modifier)
|
|
|
|
modifier = &modifier_;
|
|
|
|
return Key_StringToKeynum(keyname, modifier);
|
|
|
|
}
|
|
|
|
static const char *QDECL Plug_Key_GetKeyName(int keycode, int modifier)
|
|
|
|
{
|
|
|
|
return Key_KeynumToString(keycode, modifier);
|
|
|
|
}
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
const char *QDECL Plug_Key_GetKeyBind(int bindmap, int keynum, int modifier)
|
|
|
|
{
|
|
|
|
return Key_GetBinding(keynum, bindmap, modifier);
|
|
|
|
}
|
|
|
|
void QDECL Plug_Key_SetKeyBind(int bindmap, int keycode, int modifier, const char *newbinding)
|
|
|
|
{
|
|
|
|
if (bindmap && !modifier)
|
|
|
|
modifier = (bindmap-1) | KEY_MODIFIER_ALTBINDMAP;
|
|
|
|
Key_SetBinding (keycode, modifier, newbinding, RESTRICT_LOCAL);
|
|
|
|
}
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2021-12-20 10:06:25 +00:00
|
|
|
static unsigned int IN_GetKeyDest(void)
|
|
|
|
{
|
|
|
|
return key_dest_mask;
|
|
|
|
}
|
|
|
|
|
2022-03-08 05:31:34 +00:00
|
|
|
qboolean QDECL Plug_Input_IsKeyDown(int key)
|
|
|
|
{
|
|
|
|
extern qboolean keydown[K_MAX];
|
|
|
|
if (key >= 0 && key < K_MAX)
|
|
|
|
return !!keydown[key];
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
void QDECL Plug_Input_ClearKeyStates(void)
|
|
|
|
{
|
|
|
|
Key_ClearStates();
|
|
|
|
}
|
2022-03-08 05:32:15 +00:00
|
|
|
void QDECL Plug_Input_SetSensitivityScale(float scale)
|
|
|
|
{
|
|
|
|
in_sensitivityscale = scale;
|
|
|
|
}
|
2022-03-08 05:31:34 +00:00
|
|
|
unsigned int QDECL Plug_Input_GetMoveCount(void)
|
|
|
|
{
|
|
|
|
return cl.movesequence;
|
|
|
|
}
|
|
|
|
usercmd_t *QDECL Plug_Input_GetMoveEntry(unsigned int move)
|
|
|
|
{
|
|
|
|
if (move == cl.movesequence)
|
|
|
|
return NULL; //the partial
|
|
|
|
else if (move >= cl.movesequence)
|
|
|
|
return NULL; //too new
|
|
|
|
else if (cl.outframes[move&UPDATE_MASK].cmd_sequence != move)
|
|
|
|
return NULL; //too old or otherwise missing
|
|
|
|
else
|
|
|
|
return &cl.outframes[move&UPDATE_MASK].cmd[0];
|
|
|
|
}
|
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
/*
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static void QDECL Plug_SCR_CenterPrint(int seat, const char *text)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
if (qrenderer != QR_NONE)
|
|
|
|
SCR_CenterPrint(seat, text, true);
|
2005-12-15 19:41:11 +00:00
|
|
|
}
|
2019-09-04 07:59:40 +00:00
|
|
|
*/
|
2005-12-15 19:41:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2013-11-21 23:02:28 +00:00
|
|
|
#include "shader.h"
|
|
|
|
|
2022-03-08 05:31:34 +00:00
|
|
|
static qboolean Plug_Draw_GetScreenSize(float *vsize, unsigned int *psize)
|
Too many changes, sorry.
Change revision displays, use the SVN commit date instead of using __DATE__ (when there's no local changes). This should allow reproducible builds.
Added s_al_disable cvar, to block openal and all the various problems people have had with it, without having to name an explicit fallback (which would vary by system).
Add mastervolume cvar (for ss).
Add r_shadows 2 (aka fake shadows - for ss).
Add scr_loadingscreen_aspect -1 setting, to disable levelshots entirely, also disables the progress bar (for ss).
Better support for some effectinfo hacks (for ss).
Added dpcompat_nocsqcwarnings (because of lazy+buggy mods like ss).
Rework the dpcsqc versions of project+unproject builtins for better compat (for ss).
Added dpcompat_csqcinputeventtypes to block unexpected csqc input events (for ss).
Better compat with DP's loadfont console command (for ss).
Added dpcompat_smallerfonts cvar to replicate a DP bug (for ss).
Detect dp's m_draw extension, to work around it (for ss).
Cvar dpcompat_ignoremodificationtimes added. A value of 0 favour the most recently modified file, 1 will use DP-like alphabetically sorted preferences (for ss).
loadfont builtin can now accept outline=1 in the sizes arg for slightly more readable fonts.
Fix bbox calcs for rotated entities, fix needed for r_ignorenetpvs 0.
Hackily parse emoji.json to provide :poop: etc suggestions.
Skip prediction entirely when there's no local entity info. This fixes stair-smoothing in xonotic.
screenshot_cubemap will now capture half-float images when saving to ktx or dds files.
Fix support for xcf files larger than 4gb, mostly to avoid compiler warnings.
Fixed size of gfx/loading.lmp when replacement textures are used.
Added mipmap support for rg8 and l8a8 textures.
r_hdr_framebuffer cvar updated to support format names instead of random negative numbers. Description updated to name some interesting ones.
Perform autoupdate _checks_ ONLY with explicit user confirmation (actual updating already needed user confirmation, but this extra step should reduce the chances of us getting wrongly accused of exfiltrating user data if we're run in a sandbox - we ONLY ever included the updating engine's version in the checks, though there's nothing we can do to avoid sending the user's router's IP).
Removed the 'summon satan all over your harddrive' quit message, in case paranoid security researchers are idiots and don't bother doing actual research.
Removed the triptohell.info and fte.triptohell.info certificates, they really need to stop being self-signed. The updates domain is still self-signed for autoupdates.
Video drivers are now able to report supported video resolutions, visible to menuqc. Currently only works with SDL2 builds.
Added setmousepos builtin. Should work with glx+win32 build.
VF_SKYROOM_CAMERA can now accept an extra two args, setviewprop(VF_SKYROOM_CAMERA, org, axis, degrees).
Removed v_skyroom_origin+v_skyroom_orientation cvars in favour just v_skyroom, which should make it behave more like the 'fog' command (used when csqc isn't overriding).
Added R_EndPolygonRibbon builtin to make it faster+easier to generate textured ribbon/cable/etc wide lines (for TW).
sdl: Fix up sys_sdl.c's file enumeration to support wildcards in directories.
edit command now displays end1.bin/end2.bin correctly, because we can.
Finally add support for f_modified - though ruleset_allow_larger_models and ruleset_allow_overlong_sounds generally make it redundant.
Fix threading race condition in sha1 lookups.
Updated f_ruleset to include the same extra flags reported by ezquake.
A mod's default.fmf file can now contain an eg 'mainconfig config.cfg' line (to explicitly set the main config saved with cfg_save_auto 1 etc).
fmf: basegame steam:GameName/GameDir can be used to try to load a mod directory from an installed steam game. The resulting gamedir will be read-only.
HOMEDIR CHANGE: use homedirs only if the basedir cannot be written or a homedir already exists, which should further reduce the probability of microsoft randomly uploading our data to their cloud (but mostly because its annoying to never know where your data is written).
Fixed buf_cvarlist, should work in xonotic now, and without segfaults.
Added an extra arg to URI_Get_Callback calls - the response size, also changed the tempstring to contain all bytes of the response, you need to be careful about nulls though.
Try to work around nvidia's forced-panning bug on x11 when changing video modes. This might screw with other programs.
sdl: support custom icons.
sdl: support choosing a specific display.
Added some documentation to menuqc builtins.
menusys: use outlines for slightly more readable fonts.
menusys: switch vid_width and vid_height combos into a single video mode combo to set both according to reported video modes.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5581 fc73d0e0-1445-4013-8a0c-d673dee63da5
2019-11-20 03:09:50 +00:00
|
|
|
{
|
2022-03-08 05:31:34 +00:00
|
|
|
if (qrenderer<=0)
|
|
|
|
return false;
|
|
|
|
if (vsize)
|
|
|
|
vsize[0] = vid.width, vsize[1] = vid.height;
|
|
|
|
if (psize)
|
|
|
|
psize[0] = vid.pixelwidth, psize[1] = vid.pixelheight;
|
|
|
|
return true;
|
Too many changes, sorry.
Change revision displays, use the SVN commit date instead of using __DATE__ (when there's no local changes). This should allow reproducible builds.
Added s_al_disable cvar, to block openal and all the various problems people have had with it, without having to name an explicit fallback (which would vary by system).
Add mastervolume cvar (for ss).
Add r_shadows 2 (aka fake shadows - for ss).
Add scr_loadingscreen_aspect -1 setting, to disable levelshots entirely, also disables the progress bar (for ss).
Better support for some effectinfo hacks (for ss).
Added dpcompat_nocsqcwarnings (because of lazy+buggy mods like ss).
Rework the dpcsqc versions of project+unproject builtins for better compat (for ss).
Added dpcompat_csqcinputeventtypes to block unexpected csqc input events (for ss).
Better compat with DP's loadfont console command (for ss).
Added dpcompat_smallerfonts cvar to replicate a DP bug (for ss).
Detect dp's m_draw extension, to work around it (for ss).
Cvar dpcompat_ignoremodificationtimes added. A value of 0 favour the most recently modified file, 1 will use DP-like alphabetically sorted preferences (for ss).
loadfont builtin can now accept outline=1 in the sizes arg for slightly more readable fonts.
Fix bbox calcs for rotated entities, fix needed for r_ignorenetpvs 0.
Hackily parse emoji.json to provide :poop: etc suggestions.
Skip prediction entirely when there's no local entity info. This fixes stair-smoothing in xonotic.
screenshot_cubemap will now capture half-float images when saving to ktx or dds files.
Fix support for xcf files larger than 4gb, mostly to avoid compiler warnings.
Fixed size of gfx/loading.lmp when replacement textures are used.
Added mipmap support for rg8 and l8a8 textures.
r_hdr_framebuffer cvar updated to support format names instead of random negative numbers. Description updated to name some interesting ones.
Perform autoupdate _checks_ ONLY with explicit user confirmation (actual updating already needed user confirmation, but this extra step should reduce the chances of us getting wrongly accused of exfiltrating user data if we're run in a sandbox - we ONLY ever included the updating engine's version in the checks, though there's nothing we can do to avoid sending the user's router's IP).
Removed the 'summon satan all over your harddrive' quit message, in case paranoid security researchers are idiots and don't bother doing actual research.
Removed the triptohell.info and fte.triptohell.info certificates, they really need to stop being self-signed. The updates domain is still self-signed for autoupdates.
Video drivers are now able to report supported video resolutions, visible to menuqc. Currently only works with SDL2 builds.
Added setmousepos builtin. Should work with glx+win32 build.
VF_SKYROOM_CAMERA can now accept an extra two args, setviewprop(VF_SKYROOM_CAMERA, org, axis, degrees).
Removed v_skyroom_origin+v_skyroom_orientation cvars in favour just v_skyroom, which should make it behave more like the 'fog' command (used when csqc isn't overriding).
Added R_EndPolygonRibbon builtin to make it faster+easier to generate textured ribbon/cable/etc wide lines (for TW).
sdl: Fix up sys_sdl.c's file enumeration to support wildcards in directories.
edit command now displays end1.bin/end2.bin correctly, because we can.
Finally add support for f_modified - though ruleset_allow_larger_models and ruleset_allow_overlong_sounds generally make it redundant.
Fix threading race condition in sha1 lookups.
Updated f_ruleset to include the same extra flags reported by ezquake.
A mod's default.fmf file can now contain an eg 'mainconfig config.cfg' line (to explicitly set the main config saved with cfg_save_auto 1 etc).
fmf: basegame steam:GameName/GameDir can be used to try to load a mod directory from an installed steam game. The resulting gamedir will be read-only.
HOMEDIR CHANGE: use homedirs only if the basedir cannot be written or a homedir already exists, which should further reduce the probability of microsoft randomly uploading our data to their cloud (but mostly because its annoying to never know where your data is written).
Fixed buf_cvarlist, should work in xonotic now, and without segfaults.
Added an extra arg to URI_Get_Callback calls - the response size, also changed the tempstring to contain all bytes of the response, you need to be careful about nulls though.
Try to work around nvidia's forced-panning bug on x11 when changing video modes. This might screw with other programs.
sdl: support custom icons.
sdl: support choosing a specific display.
Added some documentation to menuqc builtins.
menusys: use outlines for slightly more readable fonts.
menusys: switch vid_width and vid_height combos into a single video mode combo to set both according to reported video modes.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5581 fc73d0e0-1445-4013-8a0c-d673dee63da5
2019-11-20 03:09:50 +00:00
|
|
|
}
|
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static qhandle_t Plug_Draw_LoadImage(const char *name, int type, const char *script)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
2022-03-08 05:31:34 +00:00
|
|
|
shader_t *pic;
|
2010-02-06 01:25:04 +00:00
|
|
|
if (qrenderer != QR_NONE)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
2013-11-21 23:02:28 +00:00
|
|
|
if (type == 3)
|
|
|
|
pic = NULL;
|
|
|
|
else if (type == 2)
|
|
|
|
pic = R_RegisterShader(name, SUF_NONE, script);
|
2005-12-15 19:41:11 +00:00
|
|
|
else
|
2011-03-31 01:14:01 +00:00
|
|
|
pic = R2D_SafeCachePic(name);
|
2005-12-15 19:41:11 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
pic = NULL;
|
|
|
|
|
2022-03-08 05:31:34 +00:00
|
|
|
if (pic)
|
|
|
|
return pic->id+1;
|
|
|
|
return 0;
|
2005-12-15 19:41:11 +00:00
|
|
|
}
|
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static qhandle_t QDECL Plug_Draw_LoadImageData(const char *name, const char *mimetype, void *codeddata, size_t datalength)
|
2013-11-21 23:02:28 +00:00
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
qhandle_t ret = 0;
|
2014-10-05 20:04:11 +00:00
|
|
|
image_t *t;
|
2013-11-21 23:02:28 +00:00
|
|
|
qbyte *rgbdata;
|
|
|
|
unsigned int width, height;
|
2018-09-29 17:31:58 +00:00
|
|
|
uploadfmt_t format;
|
2013-11-21 23:02:28 +00:00
|
|
|
|
2018-09-29 17:31:58 +00:00
|
|
|
if ((rgbdata = ReadRawImageFile(codeddata, datalength, &width, &height, &format, false, name)))
|
2013-11-21 23:02:28 +00:00
|
|
|
{
|
2017-09-20 11:27:13 +00:00
|
|
|
t = Image_FindTexture(name, NULL, IF_PREMULTIPLYALPHA|IF_NOMIPMAP|IF_UIPIC|IF_CLAMP);
|
2013-11-21 23:02:28 +00:00
|
|
|
if (!TEXVALID(t))
|
2017-09-20 11:27:13 +00:00
|
|
|
t = Image_CreateTexture(name, NULL, IF_PREMULTIPLYALPHA|IF_NOMIPMAP|IF_UIPIC|IF_CLAMP);
|
2013-11-21 23:02:28 +00:00
|
|
|
if (TEXVALID(t))
|
|
|
|
{
|
2020-11-04 10:19:30 +00:00
|
|
|
Image_Upload(t, format, rgbdata, NULL, width, height, 1, IF_PREMULTIPLYALPHA|IF_NOMIPMAP|IF_UIPIC|IF_CLAMP);
|
2013-11-21 23:02:28 +00:00
|
|
|
ret = Plug_Draw_LoadImage(name, 3, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
BZ_Free(rgbdata);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2019-09-04 07:59:40 +00:00
|
|
|
static qhandle_t QDECL Plug_Draw_LoadImageShader(const char *name, const char *script)
|
2013-11-21 23:02:28 +00:00
|
|
|
{
|
|
|
|
return Plug_Draw_LoadImage(name, 2, script);
|
|
|
|
}
|
2022-03-08 05:31:34 +00:00
|
|
|
static qhandle_t QDECL Plug_Draw_LoadImagePic(const char *name)
|
2013-11-21 23:02:28 +00:00
|
|
|
{
|
2022-03-08 05:31:34 +00:00
|
|
|
return Plug_Draw_LoadImage(name, 0, NULL);
|
2013-11-21 23:02:28 +00:00
|
|
|
}
|
2022-03-08 05:31:34 +00:00
|
|
|
static shader_t *Plug_Draw_ShaderFromId(qhandle_t id)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
2022-03-08 05:31:34 +00:00
|
|
|
if (--id >= r_numshaders)
|
|
|
|
return NULL;
|
|
|
|
return r_shaders[id];
|
2005-12-15 19:41:11 +00:00
|
|
|
}
|
2022-03-08 05:32:15 +00:00
|
|
|
static void Plug_Draw_UnloadImage(qhandle_t id)
|
|
|
|
{
|
|
|
|
R_UnloadShader(Plug_Draw_ShaderFromId(id));
|
|
|
|
}
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static int QDECL Plug_Draw_ImageSize(qhandle_t image, float *w, float *h)
|
2015-04-21 04:12:00 +00:00
|
|
|
{
|
|
|
|
int iw, ih, ret;
|
|
|
|
|
2022-03-08 05:31:34 +00:00
|
|
|
if (image > 0 && image <= r_numshaders)
|
2015-04-21 04:12:00 +00:00
|
|
|
{
|
2022-03-08 05:31:34 +00:00
|
|
|
ret = R_GetShaderSizes(r_shaders[image-1], &iw, &ih, true);
|
|
|
|
if (w)
|
|
|
|
*w = iw;
|
|
|
|
if (h)
|
|
|
|
*h = ih;
|
|
|
|
return ret;
|
2015-04-21 04:12:00 +00:00
|
|
|
}
|
2022-03-08 05:31:34 +00:00
|
|
|
return -1;
|
2015-04-21 04:12:00 +00:00
|
|
|
}
|
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static int QDECL Plug_Draw_Image(float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t image)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
2022-03-08 05:31:34 +00:00
|
|
|
if (image > 0 && image <= r_numshaders)
|
2006-01-21 00:06:49 +00:00
|
|
|
{
|
2022-03-08 05:31:34 +00:00
|
|
|
R2D_Image(x, y, w, h, s1, t1, s2, t2, r_shaders[image-1]);
|
|
|
|
return 1;
|
2006-01-21 00:06:49 +00:00
|
|
|
}
|
2022-03-08 05:31:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int QDECL Plug_Draw_Image2dQuad(const vec2_t *points, const vec2_t *texcoords, const vec4_t *colours, qhandle_t image)
|
|
|
|
{
|
|
|
|
if (image > 0 && image <= r_numshaders)
|
|
|
|
{
|
|
|
|
R2D_Image2dQuad(points, texcoords, colours, r_shaders[image-1]);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2005-12-15 19:41:11 +00:00
|
|
|
}
|
|
|
|
//x1,y1,x2,y2
|
2019-09-04 07:59:40 +00:00
|
|
|
static void QDECL Plug_Draw_Line(float x1, float y1, float x2, float y2)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
R2D_Line(x1,y1, x2,y2, NULL);
|
2005-12-15 19:41:11 +00:00
|
|
|
}
|
2019-09-04 07:59:40 +00:00
|
|
|
static void QDECL Plug_Draw_Character(float x, float y, unsigned int character)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
2019-10-18 03:37:15 +00:00
|
|
|
float px, py;
|
2010-02-06 01:25:04 +00:00
|
|
|
if (qrenderer == QR_NONE)
|
2019-09-04 07:59:40 +00:00
|
|
|
return;
|
2019-10-18 03:37:15 +00:00
|
|
|
Font_BeginScaledString(font_default, x, y, 8, 8, &px, &py);
|
|
|
|
Font_DrawScaleChar(px, py, CON_WHITEMASK, character);
|
2013-12-29 22:48:28 +00:00
|
|
|
Font_EndString(font_default);
|
2005-12-15 19:41:11 +00:00
|
|
|
}
|
2019-09-04 07:59:40 +00:00
|
|
|
static void QDECL Plug_Draw_CharacterH(float x, float y, float h, unsigned int flags, unsigned int charc)
|
2015-06-17 13:05:20 +00:00
|
|
|
{
|
|
|
|
conchar_t cmask = CON_WHITEMASK;
|
|
|
|
if (qrenderer == QR_NONE)
|
2019-09-04 07:59:40 +00:00
|
|
|
return;
|
2015-06-17 13:05:20 +00:00
|
|
|
if (flags & 1)
|
|
|
|
cmask |= CON_2NDCHARSETTEXT;
|
|
|
|
if (!(flags & 2))
|
|
|
|
cmask |= 0xe000;
|
|
|
|
Font_BeginScaledString(font_default, x, y, h, h, &x, &y);
|
2015-07-14 14:47:00 +00:00
|
|
|
Font_DrawScaleChar(x, y, cmask, charc);
|
2015-06-17 13:05:20 +00:00
|
|
|
Font_EndString(font_default);
|
|
|
|
}
|
2019-09-04 07:59:40 +00:00
|
|
|
static void QDECL Plug_Draw_String(float x, float y, const char *string)
|
2013-11-21 23:02:28 +00:00
|
|
|
{
|
|
|
|
int ipx, px, py;
|
|
|
|
conchar_t buffer[2048], *str;
|
2015-07-14 14:47:00 +00:00
|
|
|
unsigned int codeflags, codepoint;
|
2013-11-21 23:02:28 +00:00
|
|
|
if (qrenderer == QR_NONE)
|
2019-09-04 07:59:40 +00:00
|
|
|
return;
|
|
|
|
COM_ParseFunString(CON_WHITEMASK, string, buffer, sizeof(buffer), false);
|
2013-11-21 23:02:28 +00:00
|
|
|
str = buffer;
|
2019-09-04 07:59:40 +00:00
|
|
|
Font_BeginString(font_default, x, y, &px, &py);
|
2013-11-21 23:02:28 +00:00
|
|
|
ipx = px;
|
|
|
|
while(*str)
|
|
|
|
{
|
2015-07-14 14:47:00 +00:00
|
|
|
str = Font_Decode(str, &codeflags, &codepoint);
|
|
|
|
if (codepoint == '\n')
|
2013-11-21 23:02:28 +00:00
|
|
|
py += Font_CharHeight();
|
2015-07-14 14:47:00 +00:00
|
|
|
else if (codepoint == '\r')
|
2013-11-21 23:02:28 +00:00
|
|
|
px = ipx;
|
|
|
|
else
|
2015-07-14 14:47:00 +00:00
|
|
|
px = Font_DrawChar(px, py, codeflags, codepoint);
|
2013-11-21 23:02:28 +00:00
|
|
|
}
|
2013-12-29 22:48:28 +00:00
|
|
|
Font_EndString(font_default);
|
2013-11-21 23:02:28 +00:00
|
|
|
}
|
2019-09-04 07:59:40 +00:00
|
|
|
static void QDECL Plug_Draw_StringH(float x, float y, float h, unsigned int flags, const char *instr)
|
2015-06-17 13:05:20 +00:00
|
|
|
{
|
|
|
|
float ipx;
|
|
|
|
conchar_t buffer[2048], *str, cmask = CON_WHITEMASK;
|
2015-07-14 14:47:00 +00:00
|
|
|
unsigned int codeflags, codepoint;
|
2015-06-17 13:05:20 +00:00
|
|
|
unsigned int parseflags = 0;
|
|
|
|
if (qrenderer == QR_NONE)
|
2019-09-04 07:59:40 +00:00
|
|
|
return;
|
2015-06-17 13:05:20 +00:00
|
|
|
if (flags & 1)
|
|
|
|
cmask |= CON_2NDCHARSETTEXT;
|
|
|
|
if (flags & 2)
|
|
|
|
parseflags |= PFS_FORCEUTF8;
|
|
|
|
COM_ParseFunString(CON_WHITEMASK, instr, buffer, sizeof(buffer), parseflags);
|
|
|
|
str = buffer;
|
|
|
|
Font_BeginScaledString(font_default, x, y, h, h, &x, &y);
|
|
|
|
ipx = x;
|
|
|
|
while(*str)
|
|
|
|
{
|
2015-07-14 14:47:00 +00:00
|
|
|
str = Font_Decode(str, &codeflags, &codepoint);
|
|
|
|
if (codepoint == '\n')
|
2015-06-17 13:05:20 +00:00
|
|
|
y += Font_CharScaleHeight();
|
2015-07-14 14:47:00 +00:00
|
|
|
else if (codepoint == '\r')
|
2015-06-17 13:05:20 +00:00
|
|
|
x = ipx;
|
|
|
|
else
|
2015-07-14 14:47:00 +00:00
|
|
|
x = Font_DrawScaleChar(x, y, codeflags, codepoint);
|
2015-06-17 13:05:20 +00:00
|
|
|
}
|
|
|
|
Font_EndString(font_default);
|
|
|
|
}
|
2011-03-31 01:14:01 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static float QDECL Plug_Draw_StringWidth(float h, unsigned int flags, const char *instr)
|
2015-10-27 15:20:15 +00:00
|
|
|
{
|
|
|
|
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
|
2019-09-04 07:59:40 +00:00
|
|
|
return (px*(float)vid.width) / (float)vid.rotpixelwidth;
|
2015-10-27 15:20:15 +00:00
|
|
|
}
|
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static void QDECL Plug_Draw_Fill(float x, float y, float width, float height)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
if (qrenderer != QR_NONE)
|
|
|
|
R2D_FillBlock(x, y, width, height);
|
2005-12-15 19:41:11 +00:00
|
|
|
}
|
2019-09-04 07:59:40 +00:00
|
|
|
static void QDECL Plug_Draw_ColourP(int palcol, float a)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
if (palcol>=0 && palcol<=255)
|
|
|
|
R2D_ImagePaletteColour(palcol, a);
|
2005-12-15 19:41:11 +00:00
|
|
|
}
|
2019-09-04 07:59:40 +00:00
|
|
|
static void QDECL Plug_Draw_Colour4f(float r, float g, float b, float a)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
R2D_ImageColours(r,g,b,a);
|
2005-12-15 19:41:11 +00:00
|
|
|
}
|
|
|
|
|
2022-03-08 05:31:34 +00:00
|
|
|
static void QDECL Plug_Draw_RedrawScreen(void)
|
|
|
|
{
|
|
|
|
SCR_UpdateScreen();
|
|
|
|
}
|
|
|
|
|
2022-05-28 17:58:27 +00:00
|
|
|
#ifdef HAVE_MEDIA_DECODER
|
2022-03-08 05:32:15 +00:00
|
|
|
static void QDECL Plug_Media_SetState(cin_t *cin, int state)
|
|
|
|
{
|
|
|
|
Media_SetState(cin, state);
|
|
|
|
}
|
|
|
|
static int QDECL Plug_Media_GetState(cin_t *cin)
|
|
|
|
{
|
|
|
|
return Media_GetState(cin);
|
|
|
|
}
|
2022-05-28 17:58:27 +00:00
|
|
|
#endif
|
2022-03-08 05:31:34 +00:00
|
|
|
|
|
|
|
static qhandle_t Plug_Scene_ModelToId(model_t *mod)
|
|
|
|
{
|
|
|
|
if (!mod)
|
|
|
|
return 0;
|
|
|
|
return (mod-mod_known)+1;
|
|
|
|
}
|
|
|
|
static model_t *Plug_Scene_ModelFromId(qhandle_t id)
|
|
|
|
{
|
|
|
|
extern int mod_numknown;
|
|
|
|
if ((unsigned)(--id) >= mod_numknown)
|
|
|
|
return NULL;
|
|
|
|
return mod_known+id;
|
|
|
|
}
|
|
|
|
static qhandle_t Plug_Scene_ShaderForSkin(qhandle_t modelid, int surfaceidx, int skinnum, float time)
|
|
|
|
{
|
|
|
|
shader_t *s = Mod_ShaderForSkin(Plug_Scene_ModelFromId(modelid), surfaceidx, skinnum, time, NULL);
|
|
|
|
return s->id+1;
|
|
|
|
}
|
|
|
|
static void QDECL Plug_Scene_Clear(void)
|
|
|
|
{
|
|
|
|
CL_ClearEntityLists();
|
|
|
|
rtlights_first = RTL_FIRST;
|
|
|
|
}
|
|
|
|
static unsigned int Plug_Scene_AddPolydata(struct shader_s *s, unsigned int beflags, size_t numverts, size_t numidx, vecV_t **vertcoord, vec2_t **texcoord, vec4_t **colour, index_t **indexes)
|
|
|
|
{
|
|
|
|
unsigned int ret;
|
|
|
|
scenetris_t *t;
|
|
|
|
|
|
|
|
/*reuse the previous trigroup if its the same shader*/
|
|
|
|
if (cl_numstris && cl_stris[cl_numstris-1].shader == s && cl_stris[cl_numstris-1].flags == beflags)
|
|
|
|
t = &cl_stris[cl_numstris-1];
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (cl_numstris == cl_maxstris)
|
|
|
|
{
|
|
|
|
cl_maxstris += 8;
|
|
|
|
cl_stris = BZ_Realloc(cl_stris, sizeof(*cl_stris)*cl_maxstris);
|
|
|
|
}
|
|
|
|
t = &cl_stris[cl_numstris++];
|
|
|
|
t->shader = s;
|
|
|
|
t->flags = beflags;
|
|
|
|
t->numidx = 0;
|
|
|
|
t->numvert = 0;
|
|
|
|
t->firstidx = cl_numstrisidx;
|
|
|
|
t->firstvert = cl_numstrisvert;
|
|
|
|
}
|
|
|
|
ret = cl_numstrisvert - t->firstvert;
|
|
|
|
|
|
|
|
if (cl_maxstrisvert < cl_numstrisvert+numverts)
|
|
|
|
cl_stris_ExpandVerts(cl_numstrisvert+numverts + 64);
|
|
|
|
if (cl_maxstrisidx < cl_numstrisidx+numidx)
|
|
|
|
{
|
|
|
|
cl_maxstrisidx = cl_numstrisidx+numidx + 64;
|
|
|
|
cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx);
|
|
|
|
}
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2022-03-08 05:31:34 +00:00
|
|
|
*vertcoord = cl_strisvertv+cl_numstrisvert;
|
|
|
|
*texcoord = cl_strisvertt+cl_numstrisvert;
|
|
|
|
*colour = cl_strisvertc+cl_numstrisvert;
|
|
|
|
*indexes = cl_strisidx+cl_numstrisidx;
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2022-03-08 05:31:34 +00:00
|
|
|
t->numvert += numverts;
|
|
|
|
t->numidx += numidx;
|
|
|
|
cl_numstrisvert += numverts;
|
|
|
|
cl_numstrisidx += numidx;
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2022-03-08 05:31:34 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2022-03-08 05:31:34 +00:00
|
|
|
void R_DrawNameTags(void);
|
|
|
|
static void Plug_Scene_RenderScene(plugrefdef_t *in, size_t areabytes, const qbyte *areadata)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
extern cvar_t r_torch;
|
|
|
|
if (R2D_Flush)
|
|
|
|
R2D_Flush();
|
|
|
|
|
|
|
|
VectorCopy(in->viewaxisorg[0], r_refdef.viewaxis[0]);
|
|
|
|
VectorCopy(in->viewaxisorg[1], r_refdef.viewaxis[1]);
|
|
|
|
VectorCopy(in->viewaxisorg[2], r_refdef.viewaxis[2]);
|
|
|
|
VectorCopy(in->viewaxisorg[3], r_refdef.vieworg);
|
2022-03-08 05:32:03 +00:00
|
|
|
|
|
|
|
VectorSet(r_refdef.weaponmatrix[0], 1,0,0);
|
|
|
|
VectorSet(r_refdef.weaponmatrix[1], 0,1,0);
|
|
|
|
VectorSet(r_refdef.weaponmatrix[2], 0,0,1);
|
|
|
|
VectorSet(r_refdef.weaponmatrix[3], 0,0,0);
|
|
|
|
|
|
|
|
VectorSet(r_refdef.weaponmatrix_bob[0], 1,0,0);
|
|
|
|
VectorSet(r_refdef.weaponmatrix_bob[1], 0,1,0);
|
|
|
|
VectorSet(r_refdef.weaponmatrix_bob[2], 0,0,1);
|
|
|
|
VectorSet(r_refdef.weaponmatrix_bob[3], 0,0,0);
|
|
|
|
|
2022-03-08 05:31:34 +00:00
|
|
|
VectorAngles(r_refdef.viewaxis[0], r_refdef.viewaxis[2], r_refdef.viewangles, false); //do we actually still need this?
|
|
|
|
r_refdef.flags = in->flags;
|
|
|
|
r_refdef.fov_x = in->fov[0];
|
|
|
|
r_refdef.fov_y = in->fov[1];
|
|
|
|
r_refdef.fovv_x = in->fov_viewmodel[0];
|
|
|
|
r_refdef.fovv_y = in->fov_viewmodel[1];
|
|
|
|
r_refdef.vrect.x = in->rect.x;
|
|
|
|
r_refdef.vrect.y = in->rect.y;
|
|
|
|
r_refdef.vrect.width = in->rect.w;
|
|
|
|
r_refdef.vrect.height = in->rect.h;
|
|
|
|
r_refdef.time = in->time;
|
|
|
|
r_refdef.useperspective = true;
|
|
|
|
r_refdef.mindist = bound(0.1, gl_mindist.value, 4);
|
|
|
|
r_refdef.maxdist = gl_maxdist.value;
|
|
|
|
r_refdef.playerview = &cl.playerview[0];
|
|
|
|
|
|
|
|
if (in->flags & RDF_SKYROOMENABLED)
|
|
|
|
{
|
|
|
|
r_refdef.skyroom_enabled = true;
|
|
|
|
VectorCopy(in->skyroom_org, r_refdef.skyroom_pos);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
r_refdef.skyroom_enabled = false;
|
|
|
|
|
|
|
|
if (r_refdef.vrect.y < 0)
|
|
|
|
{ //evil hack to work around player model ui bug.
|
|
|
|
//if the y coord is off screen, reduce the height to keep things centred, and reduce the fov to compensate.
|
|
|
|
r_refdef.vrect.height += r_refdef.vrect.y*2;
|
|
|
|
r_refdef.fov_y = in->fov[1] * r_refdef.vrect.height / in->rect.h;
|
|
|
|
r_refdef.fovv_y = in->fov_viewmodel[1] * r_refdef.vrect.height / in->rect.h;
|
|
|
|
r_refdef.vrect.y = 0;
|
|
|
|
}
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2022-03-08 05:31:34 +00:00
|
|
|
memset(&r_refdef.globalfog, 0, sizeof(r_refdef.globalfog));
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2022-03-08 05:31:34 +00:00
|
|
|
if (r_torch.ival)
|
|
|
|
{
|
|
|
|
dlight_t *dl;
|
|
|
|
dl = CL_NewDlight(0, r_refdef.vieworg, 300, r_torch.ival, 0.5, 0.5, 0.2);
|
|
|
|
dl->flags |= LFLAG_SHADOWMAP|LFLAG_FLASHBLEND;
|
|
|
|
dl->fov = 60;
|
|
|
|
VectorCopy(r_refdef.viewaxis[0], dl->axis[0]);
|
|
|
|
VectorCopy(r_refdef.viewaxis[1], dl->axis[1]);
|
|
|
|
VectorCopy(r_refdef.viewaxis[2], dl->axis[2]);
|
|
|
|
}
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2022-03-08 05:31:34 +00:00
|
|
|
r_refdef.areabitsknown = areabytes>0;
|
|
|
|
for (i = 0; i < sizeof(r_refdef.areabits)/sizeof(int) && i < areabytes/sizeof(int); i++)
|
|
|
|
((int*)r_refdef.areabits)[i] = ((int*)areadata)[i] ^ ~0;
|
|
|
|
R_PushDlights();
|
|
|
|
R_RenderView();
|
|
|
|
R_DrawNameTags();
|
|
|
|
r_refdef.playerview = NULL;
|
|
|
|
r_refdef.time = 0;
|
|
|
|
}
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static void QDECL Plug_LocalSound(const char *soundname, int channel, float volume)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
if (qrenderer != QR_NONE)
|
2023-06-26 00:54:59 +00:00
|
|
|
S_LocalSound2(soundname, channel, volume);
|
2005-12-15 19:41:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-03-08 05:32:15 +00:00
|
|
|
static void QDECL Plug_CL_SetLoadscreenState(qboolean state)
|
|
|
|
{
|
|
|
|
if (state)
|
|
|
|
SCR_BeginLoadingPlaque();
|
|
|
|
else
|
|
|
|
SCR_EndLoadingPlaque();
|
|
|
|
}
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static int QDECL Plug_CL_GetStats(int pnum, unsigned int *stats, int maxstats)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
2016-08-25 00:12:14 +00:00
|
|
|
int i = 0;
|
2005-12-15 19:41:11 +00:00
|
|
|
int max;
|
|
|
|
|
2013-03-31 04:21:08 +00:00
|
|
|
if (qrenderer == QR_NONE || !cls.state)
|
|
|
|
return 0;
|
2006-01-02 23:01:54 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
max = maxstats;
|
2005-12-15 19:41:11 +00:00
|
|
|
if (max > MAX_CL_STATS)
|
|
|
|
max = MAX_CL_STATS;
|
2016-08-25 00:12:14 +00:00
|
|
|
if (pnum < 0)
|
|
|
|
{
|
|
|
|
pnum = -pnum-1;
|
|
|
|
if (pnum < MAX_CLIENTS)
|
|
|
|
{
|
|
|
|
for (i = 0; i < max; i++)
|
|
|
|
stats[i] = cl.players[pnum].stats[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (pnum < cl.splitclients)
|
|
|
|
{
|
|
|
|
for (i = 0; i < max; i++)
|
|
|
|
{ //fill stats with the right player's stats
|
|
|
|
stats[i] = cl.playerview[pnum].stats[i];
|
|
|
|
}
|
2005-12-15 19:41:11 +00:00
|
|
|
}
|
2016-08-25 00:12:14 +00:00
|
|
|
|
|
|
|
max = i;
|
2019-09-04 07:59:40 +00:00
|
|
|
for (; i < maxstats; i++) //plugin has too many stats (wow)
|
2005-12-15 19:41:11 +00:00
|
|
|
stats[i] = 0; //fill the rest.
|
|
|
|
return max;
|
|
|
|
}
|
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static void QDECL Plug_GetPlayerInfo(int playernum, plugclientinfo_t *out)
|
2006-01-21 00:06:49 +00:00
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
int i;
|
2006-01-21 00:06:49 +00:00
|
|
|
|
2019-10-18 03:37:15 +00:00
|
|
|
//queries for the local seats
|
|
|
|
if (playernum < 0)
|
|
|
|
playernum = cl.playerview[-playernum-1].playernum;
|
|
|
|
|
|
|
|
if (playernum < 0 || playernum >= MAX_CLIENTS)
|
|
|
|
{
|
|
|
|
memset(out, 0, sizeof(*out));
|
2019-09-04 07:59:40 +00:00
|
|
|
return;
|
2019-10-18 03:37:15 +00:00
|
|
|
}
|
2006-01-21 00:06:49 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
i = playernum;
|
2007-10-05 10:46:26 +00:00
|
|
|
if (out)
|
2006-01-21 00:06:49 +00:00
|
|
|
{
|
2007-10-05 10:46:26 +00:00
|
|
|
out->bottomcolour = cl.players[i].rbottomcolor;
|
|
|
|
out->topcolour = cl.players[i].rtopcolor;
|
|
|
|
out->frags = cl.players[i].frags;
|
|
|
|
Q_strncpyz(out->name, cl.players[i].name, PLUGMAX_SCOREBOARDNAME);
|
|
|
|
out->ping = cl.players[i].ping;
|
|
|
|
out->pl = cl.players[i].pl;
|
2015-06-24 17:59:57 +00:00
|
|
|
out->activetime = realtime - cl.players[i].realentertime;
|
2007-10-05 10:46:26 +00:00
|
|
|
out->userid = cl.players[i].userid;
|
|
|
|
out->spectator = cl.players[i].spectator;
|
2018-07-05 16:21:44 +00:00
|
|
|
InfoBuf_ToString(&cl.players[i].userinfo, out->userinfo, sizeof(out->userinfo), basicuserinfos, NULL, NULL, NULL, NULL);
|
2007-10-05 10:46:26 +00:00
|
|
|
Q_strncpyz(out->team, cl.players[i].team, sizeof(out->team));
|
2006-01-21 00:06:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static size_t QDECL Plug_GetLocalPlayerNumbers(size_t first, size_t count, int *playernums, int *spectracks)
|
2007-02-23 00:21:33 +00:00
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
size_t i;
|
2015-04-21 04:12:00 +00:00
|
|
|
if (count < 0 || count > 1000) count = 0;
|
|
|
|
if (first > cl.splitclients) first = cl.splitclients;
|
|
|
|
if (first+count > cl.splitclients) count = cl.splitclients-first;
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
playernums[i] = cl.playerview[first+i].playernum;
|
|
|
|
spectracks[i] = Cam_TrackNum(&cl.playerview[first+i]);
|
2015-04-21 04:12:00 +00:00
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
2007-02-23 00:21:33 +00:00
|
|
|
|
2022-06-19 15:18:23 +00:00
|
|
|
static void QDECL Plug_GetServerInfoRaw(char *outptr, size_t outlen)
|
2007-02-23 00:21:33 +00:00
|
|
|
{
|
2015-04-21 04:12:00 +00:00
|
|
|
extern float demtime;
|
2007-02-23 00:21:33 +00:00
|
|
|
|
2018-07-05 16:21:44 +00:00
|
|
|
InfoBuf_ToString(&cl.serverinfo, outptr, outlen, NULL, NULL, NULL, NULL, NULL);
|
2015-09-01 04:45:15 +00:00
|
|
|
Q_strncatz(outptr, va("\\intermission\\%i", cl.intermissionmode), outlen);
|
2015-04-21 04:12:00 +00:00
|
|
|
switch(cls.demoplayback)
|
|
|
|
{
|
|
|
|
case DPB_NONE:
|
|
|
|
break;
|
|
|
|
case DPB_MVD:
|
|
|
|
case DPB_EZTV:
|
|
|
|
Q_strncatz(outptr, "\\demotype\\mvd", outlen);
|
|
|
|
break;
|
|
|
|
case DPB_QUAKEWORLD:
|
|
|
|
Q_strncatz(outptr, "\\demotype\\qw", outlen);
|
|
|
|
break;
|
|
|
|
#ifdef NQPROT
|
|
|
|
case DPB_NETQUAKE:
|
|
|
|
Q_strncatz(outptr, "\\demotype\\nq", outlen);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef Q2CLIENT
|
|
|
|
case DPB_QUAKE2:
|
|
|
|
Q_strncatz(outptr, "\\demotype\\q2", outlen);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
Q_strncatz(outptr, va("\\demotime\\%f", demtime-cls.demostarttime), outlen);
|
2007-02-23 00:21:33 +00:00
|
|
|
|
2015-09-01 04:45:15 +00:00
|
|
|
#ifdef QUAKEHUD
|
2015-06-17 13:05:20 +00:00
|
|
|
if (cl.playerview[0].statsf[STAT_MATCHSTARTTIME])
|
2015-07-04 02:04:46 +00:00
|
|
|
Q_strncatz(outptr, va("\\matchstart\\%f", cl.playerview[0].statsf[STAT_MATCHSTARTTIME]/1000), outlen);
|
2015-09-01 04:45:15 +00:00
|
|
|
else
|
|
|
|
#endif
|
2015-06-17 13:05:20 +00:00
|
|
|
Q_strncatz(outptr, va("\\matchstart\\%f", cl.matchgametimestart), outlen);
|
2007-02-23 00:21:33 +00:00
|
|
|
}
|
2022-06-19 15:18:23 +00:00
|
|
|
static size_t QDECL Plug_GetServerInfoBlob(const char *key, void *outptr, size_t outsize)
|
|
|
|
{
|
|
|
|
char tmp[32];
|
|
|
|
size_t blobsize;
|
|
|
|
const char *blob = InfoBuf_BlobForKey(&cl.serverinfo, key, &blobsize, NULL);
|
|
|
|
if (!blob)
|
|
|
|
{ //inescapable hacks
|
|
|
|
if (!strcmp(key, "matchstart"))
|
2022-06-20 04:54:54 +00:00
|
|
|
{
|
|
|
|
float matchstart = cl.matchgametimestart;
|
|
|
|
#ifdef QUAKEHUD
|
|
|
|
if (cl.playerview[0].statsf[STAT_MATCHSTARTTIME])
|
|
|
|
matchstart = cl.playerview[0].statsf[STAT_MATCHSTARTTIME]/1000;
|
|
|
|
#endif
|
|
|
|
snprintf(tmp, sizeof(tmp), "%f", matchstart), blob=tmp;
|
|
|
|
}
|
2022-06-19 15:18:23 +00:00
|
|
|
else if (!strcmp(key, "demotime"))
|
|
|
|
{
|
|
|
|
extern float demtime;
|
|
|
|
snprintf(tmp, sizeof(tmp), "%f", demtime-cls.demostarttime), blob=tmp;
|
|
|
|
}
|
|
|
|
else if (!strcmp(key, "demotype"))
|
|
|
|
{
|
|
|
|
switch(cls.demoplayback)
|
|
|
|
{
|
|
|
|
case DPB_NONE:
|
|
|
|
break;
|
|
|
|
case DPB_MVD:
|
|
|
|
case DPB_EZTV:
|
|
|
|
blob = "mvd";
|
|
|
|
break;
|
|
|
|
case DPB_QUAKEWORLD:
|
|
|
|
blob = "qw";
|
|
|
|
break;
|
|
|
|
#ifdef NQPROT
|
|
|
|
case DPB_NETQUAKE:
|
|
|
|
blob = "nq";
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef Q2CLIENT
|
|
|
|
case DPB_QUAKE2:
|
|
|
|
blob = "q2";
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!strcmp(key, "intermission"))
|
|
|
|
snprintf(tmp, sizeof(tmp), "%i", cl.intermissionmode), blob=tmp;
|
|
|
|
if (blob)
|
|
|
|
blobsize = strlen(blob);
|
|
|
|
}
|
|
|
|
if (outptr)
|
|
|
|
{
|
|
|
|
if (blobsize > outsize)
|
|
|
|
return 0; //error
|
|
|
|
memcpy(outptr, blob, blobsize);
|
|
|
|
return blobsize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return blobsize;
|
|
|
|
}
|
2007-02-23 00:21:33 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static void QDECL Plug_SetUserInfo(int seat, const char *key, const char *value)
|
2007-02-23 00:21:33 +00:00
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
CL_SetInfo(seat, key, value);
|
|
|
|
}
|
2022-06-19 15:18:23 +00:00
|
|
|
static void QDECL Plug_SetUserInfoBlob(int seat, const char *key, const void *value, size_t size)
|
|
|
|
{
|
|
|
|
CL_SetInfoBlob(seat, key, value, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t QDECL Plug_GetUserInfoBlob(int seat, const char *key, void *outptr, size_t outsize)
|
|
|
|
{
|
|
|
|
size_t blobsize;
|
|
|
|
const char *blob;
|
|
|
|
if (seat >= countof(cls.userinfo))
|
|
|
|
blob = NULL, blobsize = 0;
|
|
|
|
else
|
|
|
|
blob = InfoBuf_BlobForKey(&cls.userinfo[seat], key, &blobsize, NULL);
|
|
|
|
if (outptr)
|
|
|
|
{
|
|
|
|
if (blobsize > outsize)
|
|
|
|
return 0; //error
|
|
|
|
memcpy(outptr, blob, blobsize);
|
|
|
|
return blobsize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return blobsize;
|
|
|
|
}
|
2007-02-23 00:21:33 +00:00
|
|
|
|
2022-03-08 05:31:34 +00:00
|
|
|
void QDECL Plug_CL_ClearState(void)
|
|
|
|
{
|
|
|
|
CL_ClearState(true);
|
|
|
|
}
|
|
|
|
void QDECL Plug_CL_UpdateGameTime(double servertime)
|
|
|
|
{
|
|
|
|
cl.oldgametime = cl.gametime;
|
|
|
|
cl.oldgametimemark = cl.gametimemark;
|
|
|
|
cl.gametime = servertime;
|
|
|
|
cl.gametimemark = realtime;
|
|
|
|
}
|
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static qboolean QDECL Plug_GetLastInputFrame(int seat, usercmd_t *outcmd)
|
|
|
|
{
|
|
|
|
unsigned int curframe = (cl.movesequence-1u) & UPDATE_MASK;
|
|
|
|
if (!cl.movesequence || seat < 0 || seat >= cl.splitclients)
|
|
|
|
return false;
|
|
|
|
*outcmd = cl.outframes[curframe].cmd[seat];
|
2007-02-23 00:21:33 +00:00
|
|
|
return true;
|
|
|
|
}
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
#define has(x) (((quintptr_t)&((plugnetinfo_t*)NULL)->x + sizeof(((plugnetinfo_t*)NULL)->x)) <= outlen)
|
2015-04-21 04:12:00 +00:00
|
|
|
//aka: misc other hud timing crap
|
2019-09-04 07:59:40 +00:00
|
|
|
static size_t QDECL Plug_GetNetworkInfo(plugnetinfo_t *outptr, size_t outlen)
|
2015-04-21 04:12:00 +00:00
|
|
|
{
|
2015-06-12 14:44:50 +00:00
|
|
|
if (has(capturing))
|
|
|
|
{
|
2017-02-21 20:22:07 +00:00
|
|
|
#ifdef HAVE_MEDIA_ENCODER
|
dpp7: Treat 'dropped' c2s packets as choked when using dpp7 protocols. This is because the protocol provides no way to disambiguate, and I don't like false reports of packetloss (only reliables loss can be detected, and that's not frequent enough to be meaningful). Pings can still be determined with dpp7, for those few packets which are acked.
package manager: reworked to enable/disable plugins when downloaded, which can also be present-but-disabled.
package manager: display a confirmation prompt before applying changes. do not allow other changes to be made while applying. prompt may be skipped with 'pkg apply' in dedicated servers.
sv: downloads are no longer forced to lower case.
sv: added sv_demoAutoCompress cvar. set to 1 to directly record to *.mvd.gz
cl: properly support directly playing .mvd.gz files
menus: reworked to separate mouse and keyboard focus. mouse focus becomes keyboard focus only on mouse clicks. tooltips follow mouse cursors.
menus: cleaned up menu heirachy a little. now simpler.
server browser: changed 'hide *' filters to 'show *' instead. I felt it was more logical.
deluxmapping: changed to disabled, load, generate, like r_loadlit is.
render targets api now supports negative formats to mean nearest filtering, where filtering is part of texture state.
drawrotpic fixed, now batches and interacts with drawpic correctly.
drawline fixed, no interacts with draw* correctly, but still does not batch.
fixed saving games.
provide proper userinfo to nq clients, where supported.
qcc: catch string table overflows safely, giving errors instead of crashes. switch to 32bit statements if some over-sized function requires it.
qtv: some bigcoords support tweaks
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5073 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-03-21 05:27:07 +00:00
|
|
|
outptr->capturing = Media_Capturing();
|
2015-06-12 14:44:50 +00:00
|
|
|
#else
|
2017-02-21 20:22:07 +00:00
|
|
|
outptr->capturing = 0;
|
2015-06-12 14:44:50 +00:00
|
|
|
#endif
|
|
|
|
}
|
2015-04-21 04:12:00 +00:00
|
|
|
|
|
|
|
if (has(seats))
|
|
|
|
outptr->seats = cl.splitclients;
|
|
|
|
if (has(ping))
|
2015-06-12 14:44:50 +00:00
|
|
|
CL_CalcNet2 (&outptr->ping.s_avg, &outptr->ping.s_mn, &outptr->ping.s_mx, &outptr->ping.ms_stddev, &outptr->ping.fr_avg, &outptr->ping.fr_mn, &outptr->ping.fr_mx, &outptr->loss.dropped, &outptr->loss.choked, &outptr->loss.invalid);
|
2015-04-21 04:12:00 +00:00
|
|
|
|
|
|
|
if (has(mlatency))
|
|
|
|
outptr->mlatency = 0;
|
|
|
|
if (has(mrate))
|
Reworked client support for DPP5+. less code now, its much more graceful.
added waterfog command. waterfog overrides regular fog only when the view is in water.
fixed 64bit printf format specifiers. should work better on winxp64.
fixed some spec angle weirdness.
fixed viewsize 99.99 weirdness with ezhud.
fixed extra offset on the console (exhibited in 64bit builds, but not limited to).
fixed .avi playback, can now actually display frames again.
reimplemented line sparks.
fixed r_editlights_save flipping the light's pitch.
fixed issue with oggs failing to load.
fixed condump to cope with unicode properly.
made sv_bigcoords default except in quake. hexen2 kinda needs it for bsp angle precision.
fixed nq server to not stall weirdly on map changes.
fixed qwprogs svc_cdtrack not bugging out with nq clients on the server.
fixed restart command to load the last map run by the server, instead of start.bsp (when idle)
optimised d3d9 renderer a little. now uses less draw calls, especially with complex scenes. seems to get higher framerates than opengl now.
fixed d3d9 renderer to not bug out quite so much when run fullscreen (shader subsystem is now correctly initialised).
fixed a couple of bugs from font change. also now supports utf-8 in a few more places.
r_editlights_reload no longer generates rtlights inside the void. this resolves a few glitches (but should also help framerates a little).
fixed so corona-only lights won't generate shadowmaps and waste lots of time.
removed lots of #defines from qclib. I should never have made them in the first place, but I was lazy. obviously there's more left that I cba to remove yet.
fixed nested calls with variant-vectors. this fixes csaddon's light editor.
fixed qcc hc calling conventions using redundant stores.
disabled keywords can still be used by using __keyword instead.
fixed ftegccgui grep feature.
fixed motionless-dog qcc bug.
tweaked qcc warnings a little. -Wall is now a viable setting. you should be able to fix all those warnings.
fixed qw svc_intermission + dpp5+ clients bug.
fixed annoying spam about disconnecting in hexen2.
rewrote status command a little to cope with ipv6 addresses more gracefully
fixed significant stall when hibernating/debugging a server with a player sitting on it.
fixed truelightning.
fixed rocketlight overriding pflags.
fixed torches vanishing on vid_restart.
fixed issue with decal scaling.
fixed findentityfield builtin.
fixed fteqcc issue with ptr+1
fixed use of arrays inside class functions.
fixed/implemented fteqcc emulation of pointer opcodes.
added __inout keyword to fteqcc, so that it doesn't feel so horrendous.
fixed sizeof(*foo)
fixed *struct = struct;
fixed recursive structs.
fixed fteqcc warning report.
fixed sdl2 controller support, hopefully.
attempted to implement xinput, including per-player audio playback.
slightly fixed relaxed attitude to mouse focus when running fullscreen.
fixed weird warnings/errors with 'ent.arrayhead' terms. now generates sane errors.
implemented bindmaps (for csqc).
fixed crashing bug with eprint builtin.
implemented subset of music_playlist_* functionality. significant changes to music playback.
fixed some more dpcsqc compat.
fixed binds menu. now displays and accepts modifiers.
fixed issues with huge lightmaps.
fixed protocol determinism with dp clients connecting to fte servers. the initial getchallenge request now inhibits vanilla nq connection requests.
implemented support for 'dupe' userinfo key, allowing clients to request client->server packet duplication. should probably queue them tbh.
implemented sv_saveentfile command.
fixed resume after breaking inside a stepped-over function.
fixed erroneous footer after debugging.
(I wonder just how many things I broke with these fixes)
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4946 fc73d0e0-1445-4013-8a0c-d673dee63da5
2015-07-26 10:56:18 +00:00
|
|
|
outptr->mrate = IN_DetermineMouseRate();
|
2015-04-21 04:12:00 +00:00
|
|
|
if (has(vlatency))
|
|
|
|
outptr->vlatency = 0;
|
|
|
|
|
|
|
|
if (has(speed))
|
|
|
|
VectorCopy(outptr->speed, r_refdef.playerview->simvel);
|
|
|
|
|
|
|
|
if (has(clrate))
|
|
|
|
NET_GetRates(cls.sockets, &outptr->clrate.in_pps, &outptr->clrate.out_pps, &outptr->clrate.in_bps, &outptr->clrate.out_bps);
|
|
|
|
if (has(svrate))
|
|
|
|
{
|
|
|
|
memset(&outptr->svrate, 0, sizeof(outptr->svrate));
|
|
|
|
#ifndef CLIENTONLY
|
|
|
|
NET_GetRates(svs.sockets, &outptr->svrate.in_pps, &outptr->svrate.out_pps, &outptr->svrate.in_bps, &outptr->svrate.out_bps);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
return min(outlen,sizeof(*outptr));
|
2015-04-21 04:12:00 +00:00
|
|
|
}
|
|
|
|
#undef has
|
|
|
|
|
2018-04-27 16:40:50 +00:00
|
|
|
#ifdef QUAKEHUD
|
2019-09-04 07:59:40 +00:00
|
|
|
static float QDECL Plug_GetTrackerOwnFrags(int seat, char *outptr, size_t outlen)
|
2015-11-18 07:37:39 +00:00
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
if (!outlen)
|
|
|
|
return 0;
|
2015-11-18 07:37:39 +00:00
|
|
|
else
|
2019-09-04 07:59:40 +00:00
|
|
|
return Stats_GetLastOwnFrag(seat, outptr, outlen);
|
2015-11-18 07:37:39 +00:00
|
|
|
}
|
2020-02-11 18:06:10 +00:00
|
|
|
static void QDECL Plug_GetPredInfo(int seat, vec3_t outvel)
|
|
|
|
{
|
|
|
|
if ((unsigned)seat < MAX_SPLITS)
|
|
|
|
VectorCopy(cl.playerview[seat].simvel, outvel);
|
|
|
|
}
|
2018-04-27 16:40:50 +00:00
|
|
|
#endif
|
2015-11-18 07:37:39 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static void QDECL Plug_GetLocationName(const float *locpoint, char *outbuffer, size_t bufferlen)
|
2007-10-05 10:46:26 +00:00
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
const char *result = TP_LocationName(locpoint);
|
|
|
|
Q_strncpyz(outbuffer, result, bufferlen);
|
2007-10-05 10:46:26 +00:00
|
|
|
}
|
|
|
|
|
2015-09-01 04:45:15 +00:00
|
|
|
#ifdef QUAKEHUD
|
2019-09-04 07:59:40 +00:00
|
|
|
static size_t QDECL Plug_GetTeamInfo(teamplayerinfo_t *players, size_t maxplayers, qboolean showenemies, int seat)
|
2015-06-29 23:46:31 +00:00
|
|
|
{
|
|
|
|
int count = 0;
|
|
|
|
int i;
|
|
|
|
int self;
|
|
|
|
lerpents_t *le;
|
|
|
|
player_info_t *pl;
|
|
|
|
|
|
|
|
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.");
|
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
if (seat >= 0)
|
|
|
|
{
|
|
|
|
self = cl.playerview[seat].playernum;
|
|
|
|
if (cl.playerview[seat].cam_state != CAM_FREECAM)
|
|
|
|
self = cl.playerview[seat].cam_spec_track;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
self = -1;
|
2015-06-29 23:46:31 +00:00
|
|
|
|
|
|
|
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;
|
2019-09-04 07:59:40 +00:00
|
|
|
if (i == self)
|
2015-06-29 23:46:31 +00:00
|
|
|
continue;
|
|
|
|
if (!showenemies && strcmp(cl.players[i].team, cl.players[self].team))
|
|
|
|
continue;
|
|
|
|
players->client = i;
|
2015-06-30 14:05:45 +00:00
|
|
|
|
2015-06-29 23:46:31 +00:00
|
|
|
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.
|
2019-09-04 07:59:40 +00:00
|
|
|
players->items = cl.playerview[seat].stats[STAT_ITEMS];
|
|
|
|
players->armor = cl.playerview[seat].statsf[STAT_ARMOR];
|
|
|
|
players->health = cl.playerview[seat].statsf[STAT_HEALTH];
|
2015-06-29 23:46:31 +00:00
|
|
|
Q_strncpyz(players->nick, "", sizeof(players->nick));
|
|
|
|
}
|
2015-06-30 14:05:45 +00:00
|
|
|
else if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
|
2015-06-29 23:46:31 +00:00
|
|
|
{ //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);
|
|
|
|
}
|
2015-06-30 14:05:45 +00:00
|
|
|
else
|
|
|
|
continue; //no stats, don't bother telling the plugin.
|
|
|
|
|
2015-06-29 23:46:31 +00:00
|
|
|
//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++;
|
|
|
|
}
|
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
return count;
|
2015-06-29 23:46:31 +00:00
|
|
|
}
|
2015-09-01 04:45:15 +00:00
|
|
|
#endif
|
2015-10-27 15:20:15 +00:00
|
|
|
#ifdef QUAKEHUD
|
2019-09-04 07:59:40 +00:00
|
|
|
static int QDECL Plug_GetWeaponStats(int self, struct wstats_s *result, size_t maxresults)
|
2015-10-27 15:20:15 +00:00
|
|
|
{
|
|
|
|
//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;
|
|
|
|
|
2016-08-25 00:12:14 +00:00
|
|
|
if (maxresults > countof(cl.players[self].weaponstats))
|
|
|
|
maxresults = countof(cl.players[self].weaponstats);
|
2015-10-27 15:20:15 +00:00
|
|
|
memcpy(result, cl.players[self].weaponstats, sizeof(*result) * maxresults);
|
2019-09-04 07:59:40 +00:00
|
|
|
return maxresults;
|
2015-10-27 15:20:15 +00:00
|
|
|
}
|
|
|
|
#endif
|
2015-06-29 23:46:31 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static qboolean QDECL Plug_Con_SubPrint(const char *name, const char *text)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
|
|
|
console_t *con;
|
2013-06-23 02:17:02 +00:00
|
|
|
if (!name)
|
|
|
|
name = "";
|
2006-01-02 23:01:54 +00:00
|
|
|
|
2010-02-06 01:25:04 +00:00
|
|
|
if (qrenderer == QR_NONE)
|
2013-07-13 12:14:32 +00:00
|
|
|
{
|
|
|
|
if (!*name)
|
|
|
|
{
|
|
|
|
Con_Printf("%s", text);
|
2019-09-04 07:59:40 +00:00
|
|
|
return true;
|
2013-07-13 12:14:32 +00:00
|
|
|
}
|
2006-01-02 23:01:54 +00:00
|
|
|
return false;
|
2013-07-13 12:14:32 +00:00
|
|
|
}
|
2006-01-02 23:01:54 +00:00
|
|
|
|
2005-12-15 19:41:11 +00:00
|
|
|
con = Con_FindConsole(name);
|
|
|
|
if (!con)
|
|
|
|
{
|
2011-06-16 02:03:57 +00:00
|
|
|
con = Con_Create(name, 0);
|
2005-12-20 23:34:06 +00:00
|
|
|
Con_SetActive(con);
|
2005-12-15 19:41:11 +00:00
|
|
|
|
|
|
|
if (currentplug->conexecutecommand)
|
|
|
|
{
|
2013-06-29 21:08:09 +00:00
|
|
|
con->notif_x = 0;
|
|
|
|
con->notif_y = 8*4;
|
|
|
|
con->notif_w = vid.width;
|
|
|
|
con->notif_t = 8;
|
|
|
|
con->notif_l = 4;
|
|
|
|
con->flags |= CONF_NOTIFY;
|
2005-12-15 19:41:11 +00:00
|
|
|
con->userdata = currentplug;
|
|
|
|
con->linebuffered = Plug_SubConsoleCommand;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-05 20:04:11 +00:00
|
|
|
Con_PrintCon(con, text, con->parseflags);
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
return true;
|
2005-12-15 19:41:11 +00:00
|
|
|
}
|
2019-09-04 07:59:40 +00:00
|
|
|
static qboolean QDECL Plug_Con_RenameSub(const char *oldname, const char *newname)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
|
|
|
console_t *con;
|
2010-02-06 01:25:04 +00:00
|
|
|
if (qrenderer == QR_NONE)
|
2006-01-02 23:01:54 +00:00
|
|
|
return false;
|
2019-09-04 07:59:40 +00:00
|
|
|
con = Con_FindConsole(oldname);
|
2005-12-15 19:41:11 +00:00
|
|
|
if (!con)
|
2019-09-04 07:59:40 +00:00
|
|
|
return false;
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
Q_strncpyz(con->name, newname, sizeof(con->name));
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
return true;
|
2005-12-15 19:41:11 +00:00
|
|
|
}
|
2019-09-04 07:59:40 +00:00
|
|
|
static qboolean QDECL Plug_Con_IsActive(const char *conname)
|
2005-12-20 23:34:06 +00:00
|
|
|
{
|
|
|
|
console_t *con;
|
2010-02-06 01:25:04 +00:00
|
|
|
if (qrenderer == QR_NONE)
|
2006-01-02 23:01:54 +00:00
|
|
|
return false;
|
2019-09-04 07:59:40 +00:00
|
|
|
con = Con_FindConsole(conname);
|
2005-12-20 23:34:06 +00:00
|
|
|
if (!con)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return Con_IsActive(con);
|
|
|
|
}
|
2019-09-04 07:59:40 +00:00
|
|
|
static qboolean QDECL Plug_Con_SetActive(const char *conname)
|
2005-12-20 23:34:06 +00:00
|
|
|
{
|
|
|
|
console_t *con;
|
2010-02-06 01:25:04 +00:00
|
|
|
if (qrenderer == QR_NONE)
|
2006-01-02 23:01:54 +00:00
|
|
|
return false;
|
2019-09-04 07:59:40 +00:00
|
|
|
con = Con_FindConsole(conname);
|
2005-12-20 23:34:06 +00:00
|
|
|
if (!con)
|
2019-09-04 07:59:40 +00:00
|
|
|
con = Con_Create(conname, 0);
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2005-12-20 23:34:06 +00:00
|
|
|
Con_SetActive(con);
|
|
|
|
return true;
|
|
|
|
}
|
2019-09-04 07:59:40 +00:00
|
|
|
static qboolean QDECL Plug_Con_Destroy(const char *conname)
|
2005-12-20 23:34:06 +00:00
|
|
|
{
|
|
|
|
console_t *con;
|
2010-02-06 01:25:04 +00:00
|
|
|
if (qrenderer == QR_NONE)
|
2006-01-02 23:01:54 +00:00
|
|
|
return false;
|
2019-09-04 07:59:40 +00:00
|
|
|
con = Con_FindConsole(conname);
|
2005-12-20 23:34:06 +00:00
|
|
|
if (!con)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Con_Destroy(con);
|
|
|
|
return true;
|
|
|
|
}
|
2019-09-04 07:59:40 +00:00
|
|
|
static qboolean QDECL Plug_Con_NameForNum(qintptr_t connum, char *outconname, size_t connamesize)
|
2005-12-20 23:34:06 +00:00
|
|
|
{
|
2010-02-06 01:25:04 +00:00
|
|
|
if (qrenderer == QR_NONE)
|
2006-01-02 23:01:54 +00:00
|
|
|
return false;
|
2005-12-20 23:34:06 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
return Con_NameForNum(connum, outconname, connamesize);
|
2005-12-20 23:34:06 +00:00
|
|
|
}
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static float QDECL Plug_Con_GetConsoleFloat(const char *conname, const char *attrib)
|
2015-04-14 23:12:17 +00:00
|
|
|
{
|
|
|
|
float ret;
|
|
|
|
console_t *con = Con_FindConsole(conname);
|
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
if (!con)
|
|
|
|
ret = -1;
|
|
|
|
else if (!strcmp(attrib, "unseen"))
|
|
|
|
ret = con->unseentext;
|
|
|
|
else if (!strcmp(attrib, "markup"))
|
|
|
|
{
|
|
|
|
if (con->parseflags & PFS_NOMARKUP)
|
|
|
|
ret = 0;
|
|
|
|
else if (con->parseflags & PFS_KEEPMARKUP)
|
|
|
|
ret = 2;
|
|
|
|
else
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
else if (!strcmp(attrib, "forceutf8"))
|
|
|
|
ret = (con->parseflags&PFS_FORCEUTF8)?true:false;
|
|
|
|
else if (!strcmp(attrib, "hidden"))
|
|
|
|
ret = (con->flags & CONF_HIDDEN)?true:false;
|
|
|
|
else if (!strcmp(attrib, "iswindow"))
|
|
|
|
ret = (con->flags & CONF_ISWINDOW)?true:false;
|
2016-07-12 00:40:13 +00:00
|
|
|
else if (!strcmp(attrib, "maxlines"))
|
|
|
|
ret = con->maxlines;
|
2015-04-14 23:12:17 +00:00
|
|
|
else if (!strcmp(attrib, "wnd_x"))
|
|
|
|
ret = con->wnd_x;
|
|
|
|
else if (!strcmp(attrib, "wnd_y"))
|
|
|
|
ret = con->wnd_y;
|
|
|
|
else if (!strcmp(attrib, "wnd_w"))
|
|
|
|
ret = con->wnd_w;
|
|
|
|
else if (!strcmp(attrib, "wnd_h"))
|
|
|
|
ret = con->wnd_h;
|
|
|
|
else if (!strcmp(attrib, "linecount"))
|
|
|
|
ret = con->linecount;
|
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
return ret;
|
2015-04-14 23:12:17 +00:00
|
|
|
}
|
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static qboolean QDECL Plug_Con_SetConsoleFloat(const char *conname, const char *attrib, float val)
|
2015-04-14 23:12:17 +00:00
|
|
|
{
|
|
|
|
console_t *con = Con_FindConsole(conname);
|
|
|
|
|
|
|
|
if (!con)
|
|
|
|
{
|
|
|
|
con = Con_Create(conname, 0);
|
|
|
|
if (!con)
|
2019-09-04 07:59:40 +00:00
|
|
|
return false;
|
2015-04-14 23:12:17 +00:00
|
|
|
con->userdata = currentplug;
|
|
|
|
con->linebuffered = Plug_SubConsoleCommand;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(attrib, "unseen"))
|
|
|
|
con->unseentext = !!val;
|
|
|
|
else if (!strcmp(attrib, "markup"))
|
|
|
|
{
|
|
|
|
int cur = val;
|
|
|
|
con->parseflags &= ~(PFS_NOMARKUP|PFS_KEEPMARKUP);
|
|
|
|
if (cur == 0)
|
|
|
|
con->parseflags |= PFS_NOMARKUP;
|
|
|
|
else if (cur == 2)
|
|
|
|
con->parseflags |= PFS_KEEPMARKUP;
|
|
|
|
}
|
|
|
|
else if (!strcmp(attrib, "forceutf8"))
|
|
|
|
con->parseflags = (con->parseflags & ~PFS_FORCEUTF8) | (val?PFS_FORCEUTF8:0);
|
|
|
|
else if (!strcmp(attrib, "hidden"))
|
|
|
|
con->flags = (con->flags & ~CONF_HIDDEN) | (val?CONF_HIDDEN:0);
|
|
|
|
else if (!strcmp(attrib, "iswindow"))
|
|
|
|
{
|
|
|
|
con->flags = (con->flags & ~CONF_ISWINDOW) | (val?CONF_ISWINDOW:0);
|
2016-07-12 00:40:13 +00:00
|
|
|
con->flags = (con->flags & ~CONF_NOTIFY) | (val>1?CONF_NOTIFY:0);
|
2015-04-14 23:12:17 +00:00
|
|
|
if (con_curwindow == con && !(con->flags & CONF_ISWINDOW))
|
|
|
|
con_curwindow = NULL;
|
|
|
|
else if (!con_curwindow && (con->flags & CONF_ISWINDOW))
|
|
|
|
con_curwindow = con;
|
|
|
|
}
|
2016-07-12 00:40:13 +00:00
|
|
|
else if (!strcmp(attrib, "maxlines"))
|
|
|
|
con->maxlines = val;
|
2015-04-14 23:12:17 +00:00
|
|
|
else if (!strcmp(attrib, "wnd_x"))
|
|
|
|
con->wnd_x = val;
|
|
|
|
else if (!strcmp(attrib, "wnd_y"))
|
|
|
|
con->wnd_y = val;
|
|
|
|
else if (!strcmp(attrib, "wnd_w"))
|
|
|
|
con->wnd_w = val;
|
|
|
|
else if (!strcmp(attrib, "wnd_h"))
|
|
|
|
con->wnd_h = val;
|
|
|
|
else if (!strcmp(attrib, "linebuffered"))
|
|
|
|
{
|
|
|
|
con->userdata = currentplug;
|
2016-07-12 00:40:13 +00:00
|
|
|
if (val == 2)
|
|
|
|
con->linebuffered = NULL;//Con_Navigate;
|
|
|
|
else if (val == 1)
|
|
|
|
con->linebuffered = Plug_SubConsoleCommand;
|
|
|
|
else
|
|
|
|
con->linebuffered = NULL;
|
2015-04-14 23:12:17 +00:00
|
|
|
}
|
|
|
|
else if (!strcmp(attrib, "linecount"))
|
|
|
|
{
|
|
|
|
if (val == 0)
|
2016-07-12 00:40:13 +00:00
|
|
|
{
|
|
|
|
int pfl = con->parseflags;
|
2015-04-14 23:12:17 +00:00
|
|
|
Con_ClearCon(con);
|
2016-07-12 00:40:13 +00:00
|
|
|
con->parseflags = pfl;
|
|
|
|
}
|
2015-04-14 23:12:17 +00:00
|
|
|
else
|
2019-09-04 07:59:40 +00:00
|
|
|
return false;
|
2015-04-14 23:12:17 +00:00
|
|
|
}
|
|
|
|
else
|
2019-09-04 07:59:40 +00:00
|
|
|
return false;
|
2015-04-14 23:12:17 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static qboolean QDECL Plug_Con_GetConsoleString(const char *conname, const char *attrib, char *value, size_t size)
|
2015-04-14 23:12:17 +00:00
|
|
|
{
|
|
|
|
console_t *con = Con_FindConsole(conname);
|
|
|
|
|
|
|
|
if (!con)
|
2019-09-04 07:59:40 +00:00
|
|
|
return false;
|
2015-04-14 23:12:17 +00:00
|
|
|
else if (!strcmp(attrib, "footer"))
|
|
|
|
;
|
2015-08-22 02:59:01 +00:00
|
|
|
else if (!strcmp(attrib, "title"))
|
|
|
|
{
|
|
|
|
Q_strncpyz(value, con->title, size);
|
|
|
|
}
|
2017-09-20 11:27:13 +00:00
|
|
|
else if (!strcmp(attrib, "icon"))
|
|
|
|
{
|
|
|
|
Q_strncpyz(value, con->icon, size);
|
|
|
|
}
|
2016-07-12 00:40:13 +00:00
|
|
|
else if (!strcmp(attrib, "prompt"))
|
|
|
|
{
|
|
|
|
Q_strncpyz(value, con->prompt, size);
|
|
|
|
}
|
2015-08-22 02:59:01 +00:00
|
|
|
else if (!strcmp(attrib, "backimage"))
|
|
|
|
{
|
|
|
|
if (con->backshader)
|
|
|
|
Q_strncpyz(value, con->backshader->name, size);
|
|
|
|
else
|
|
|
|
Q_strncpyz(value, con->backimage, size);
|
|
|
|
}
|
2019-09-04 07:59:40 +00:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
return true;
|
2015-04-14 23:12:17 +00:00
|
|
|
}
|
2019-09-04 07:59:40 +00:00
|
|
|
static qboolean QDECL Plug_Con_SetConsoleString(const char *conname, const char *attrib, const char *value)
|
2015-04-14 23:12:17 +00:00
|
|
|
{
|
|
|
|
console_t *con = Con_FindConsole(conname);
|
|
|
|
|
|
|
|
if (!con)
|
|
|
|
{
|
|
|
|
con = Con_Create(conname, 0);
|
|
|
|
if (!con)
|
2019-09-04 07:59:40 +00:00
|
|
|
return false;
|
2015-04-14 23:12:17 +00:00
|
|
|
con->userdata = currentplug;
|
|
|
|
con->linebuffered = Plug_SubConsoleCommand;
|
|
|
|
}
|
|
|
|
if (!con)
|
2019-09-04 07:59:40 +00:00
|
|
|
return false;
|
2015-04-14 23:12:17 +00:00
|
|
|
else if (!strcmp(attrib, "footer"))
|
|
|
|
Con_Footerf(con, false, "%s", value);
|
|
|
|
else if (!strcmp(attrib, "title"))
|
|
|
|
Q_strncpyz(con->title, value, sizeof(con->title));
|
2017-09-20 11:27:13 +00:00
|
|
|
else if (!strcmp(attrib, "icon"))
|
|
|
|
Q_strncpyz(con->icon, value, sizeof(con->icon));
|
2016-07-12 00:40:13 +00:00
|
|
|
else if (!strcmp(attrib, "prompt"))
|
|
|
|
Q_strncpyz(con->prompt, value, sizeof(con->prompt));
|
2015-08-22 02:59:01 +00:00
|
|
|
else if (!strcmp(attrib, "backimage"))
|
|
|
|
{
|
|
|
|
Q_strncpyz(con->backimage, value, sizeof(con->backimage));
|
|
|
|
if (con->backshader)
|
|
|
|
R_UnloadShader(con->backshader);
|
|
|
|
}
|
|
|
|
else if (!strcmp(attrib, "backvideomap"))
|
|
|
|
{
|
|
|
|
Q_strncpyz(con->backimage, "", sizeof(con->backimage));
|
|
|
|
if (con->backshader)
|
|
|
|
R_UnloadShader(con->backshader);
|
2016-07-12 00:40:13 +00:00
|
|
|
if (qrenderer != QR_NONE)
|
2021-06-22 14:40:53 +00:00
|
|
|
con->backshader = R_RegisterCustom(NULL, va("consolevid_%s", con->name), SUF_NONE, Shader_DefaultCinematic, value);
|
2016-07-12 00:40:13 +00:00
|
|
|
else
|
|
|
|
con->backshader = NULL;
|
2015-08-22 02:59:01 +00:00
|
|
|
}
|
2015-04-14 23:12:17 +00:00
|
|
|
else
|
2013-05-03 04:28:08 +00:00
|
|
|
return false;
|
2019-09-04 07:59:40 +00:00
|
|
|
return true;
|
2014-03-30 08:55:06 +00:00
|
|
|
}
|
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
static void QDECL Plug_S_RawAudio(int sourceid, void *data, int speed, int samples, int channels, int width, float volume)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
S_RawAudio(sourceid, data, speed, samples, channels, width, volume);
|
2005-12-15 19:41:11 +00:00
|
|
|
}
|
2022-03-08 05:31:34 +00:00
|
|
|
static void QDECL S_Spacialize(unsigned int seat, int entnum, vec3_t origin, vec3_t axis[3], int reverb, vec3_t velocity)
|
|
|
|
{
|
|
|
|
if (seat >= countof(cl.playerview))
|
|
|
|
return;
|
|
|
|
cl.playerview[seat].audio.defaulted = false;
|
|
|
|
cl.playerview[seat].audio.entnum = entnum;
|
|
|
|
VectorCopy(origin, cl.playerview[seat].audio.origin);
|
|
|
|
VectorCopy(axis[0], cl.playerview[seat].audio.forward);
|
|
|
|
VectorCopy(axis[1], cl.playerview[seat].audio.right);
|
|
|
|
VectorCopy(axis[2], cl.playerview[seat].audio.up);
|
|
|
|
cl.playerview[seat].audio.reverbtype = reverb;
|
|
|
|
VectorCopy(velocity, cl.playerview[seat].audio.velocity);
|
|
|
|
}
|
|
|
|
static sfx_t *QDECL Plug_S_PrecacheSound(const char *sndname)
|
|
|
|
{
|
|
|
|
return S_PrecacheSound(sndname);
|
|
|
|
}
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2018-10-11 10:31:23 +00:00
|
|
|
static void Plug_Client_Close(plugin_t *plug)
|
2005-12-15 19:41:11 +00:00
|
|
|
{
|
2019-09-04 07:59:40 +00:00
|
|
|
menu_t *m = Menu_FindContext(currentplug);
|
2005-12-15 19:41:11 +00:00
|
|
|
|
2019-09-04 07:59:40 +00:00
|
|
|
if (m)
|
2021-07-01 21:05:45 +00:00
|
|
|
Menu_Unlink(m, true);
|
2005-12-15 19:41:11 +00:00
|
|
|
if (protocolclientplugin == plug)
|
|
|
|
{
|
|
|
|
protocolclientplugin = NULL;
|
|
|
|
if (cls.protocol == CP_PLUGIN)
|
|
|
|
cls.protocol = CP_UNKNOWN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|