diff --git a/progs/fte-menu.src b/progs/fte-menu.src new file mode 100644 index 0000000..dd04419 --- /dev/null +++ b/progs/fte-menu.src @@ -0,0 +1,7 @@ +../../build/pc/menu.dat + +../source/menu/defs/fte.qc +../source/menu/defs/custom.qc +../source/shared/sui_sys.qc +../source/menu/menu.qc +../source/menu/main.qc \ No newline at end of file diff --git a/source/client/main.qc b/source/client/main.qc index 9ad56e8..61bd2d2 100644 --- a/source/client/main.qc +++ b/source/client/main.qc @@ -581,20 +581,16 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = //does what you think it does renderscene(); - if(in_menu) - { - //in menu.qc - Draw_Menu(); - } - else + if (!menushown) { HUD_Draw(g_width, g_height); } - if(serverkey("constate") != "active" && serverkey("disconnected")) + + /*if(serverkey("constate") != "active" && serverkey("disconnected")) { drawfill('0 0 0', [width, height, 0], '0.2 0.4 0.7', 1, 0); drawstring([width/2 - 60, height/2, 0], "Loading...", [16,16,0],[1,1,1],1,0); - } + }*/ }; noref float(string cmd) CSQC_ConsoleCommand = diff --git a/source/menu/defs/custom.qc b/source/menu/defs/custom.qc new file mode 100644 index 0000000..e69de29 diff --git a/source/menu/defs/fte.qc b/source/menu/defs/fte.qc new file mode 100644 index 0000000..dccfc39 --- /dev/null +++ b/source/menu/defs/fte.qc @@ -0,0 +1,1049 @@ +/* +This file was automatically generated by FTE Quake v1.06 +This file can be regenerated by issuing the following command: +pr_dumpplatform -Ffte -Tmenu -O menudefs +Available options: +-Ffte - target only FTE (optimations and additional extensions) +-Tnq - dump specifically NQ fields +-Tqw - dump specifically QW fields +-Tcs - dump specifically CSQC fields +-Tmenu - dump specifically menuqc fields +-Fdefines - generate #defines instead of constants +-Faccessors - use accessors instead of basic types via defines +-O - write to a different qc file +*/ +#pragma noref 1 +//#pragma flag enable logicops +#pragma warning error Q101 /*too many parms*/ +#pragma warning error Q105 /*too few parms*/ +#pragma warning error Q106 /*assignment to constant/lvalue*/ +#pragma warning error Q208 /*system crc unknown*/ +#pragma warning disable F211 /*system crc outdated (eg: dp's csqc)*/ +#pragma warning enable F301 /*non-utf-8 strings*/ +#pragma warning enable F302 /*uninitialised locals*/ +#pragma target FTE +#ifndef MENU +#define MENU +#endif +#define FTE_PEXT_SETVIEW /* NQ's svc_setview works correctly even in quakeworld */ +#define DP_ENT_SCALE +#define FTE_PEXT_LIGHTSTYLECOL +#define DP_ENT_ALPHA +#define FTE_PEXT_VIEW2 +#define FTE_PEXT_ACURATETIMINGS +#define FTE_PEXT_SOUNDDBL +#define FTE_PEXT_FATNESS +#define DP_HALFLIFE_MAP +#define FTE_PEXT_TE_BULLET +#define FTE_PEXT_HULLSIZE +#define FTE_PEXT_MODELDBL +#define FTE_PEXT_ENTITYDBL +#define FTE_PEXT_ENTITYDBL2 +#define FTE_PEXT_FLOATCOORDS +#define FTE_PEXT_VWEAP +#define FTE_PEXT_Q2BSP +#define FTE_PEXT_Q3BSP +#define DP_ENT_COLORMOD +#define FTE_HEXEN2 +#define FTE_PEXT_SPAWNSTATIC +#define FTE_PEXT_CUSTOMTENTS +#define FTE_PEXT_256PACKETENTITIES +#define TEI_SHOWLMP2 +#define DP_GFX_QUAKE3MODELTAGS +#define FTE_PK3DOWNLOADS +#define PEXT_CHUNKEDDOWNLOADS +#define EXT_CSQC_SHARED +#define PEXT_DPFLAGS +#define EXT_CSQC +#define BX_COLOREDTEXT +#define DP_CON_SET /* The 'set' console command exists, and can be used to create/set cvars. */ +#define DP_CON_SETA /* The 'seta' console command exists, like the 'set' command, but also marks the cvar for archiving, allowing it to be written into the user's config. Use this command in your default.cfg file. */ +#define DP_EF_ADDITIVE +#define DP_EF_BLUE +#define DP_EF_FULLBRIGHT +#define DP_EF_NODEPTHTEST +#define DP_EF_NODRAW +#define DP_EF_NOGUNBOB +#define DP_EF_NOSHADOW +#define DP_EF_RED +#define DP_ENT_CUSTOMCOLORMAP +#define DP_ENT_EXTERIORMODELTOCLIENT +#define DP_ENT_TRAILEFFECTNUM /* self.traileffectnum=particleeffectnum("myeffectname"); can be used to attach a particle trail to the given server entity. This is equivelent to calling trailparticles each frame. */ +#define DP_ENT_VIEWMODEL +#define DP_GECKO_SUPPORT +#define DP_GFX_FONTS +#define DP_GFX_SKINFILES +#define DP_GFX_SKYBOX +#define DP_HALFLIFE_MAP_CVAR +#define DP_INPUTBUTTONS +#define DP_LIGHTSTYLE_STATICVALUE +#define DP_LITSUPPORT +#define DP_MONSTERWALK /* MOVETYPE_WALK is valid on non-player entities. Note that only players receive acceleration etc in line with none/bounce/fly/noclip movetypes on the player, thus you will have to provide your own accelerations (incluing gravity) yourself. */ +#define DP_MOVETYPEBOUNCEMISSILE +#define DP_MOVETYPEFOLLOW +#define DP_QC_ASINACOSATANATAN2TAN +#define DP_QC_CHANGEPITCH +#define DP_QC_COPYENTITY +#define DP_QC_CRC16 +#define DP_QC_CVAR_DEFSTRING +#define DP_QC_CVAR_STRING +#define DP_QC_CVAR_TYPE +#define DP_QC_EDICT_NUM +#define DP_QC_ENTITYDATA +#define DP_QC_ETOS +#define DP_QC_FINDCHAIN +#define DP_QC_FINDCHAINFLOAT +#define DP_QC_FINDFLAGS +#define DP_QC_FINDCHAINFLAGS +#define DP_QC_FINDFLOAT +#define DP_QC_FS_SEARCH +#define DP_QC_GETSURFACE +#define DP_QC_GETSURFACEPOINTATTRIBUTE +#define DP_QC_GETTAGINFO +#define DP_QC_MINMAXBOUND +#define DP_QC_MULTIPLETEMPSTRINGS /* Superseded by DP_QC_UNLIMITEDTEMPSTRINGS. Functions that return a temporary string will not overwrite/destroy previous temporary strings until at least 16 strings are returned (or control returns to the engine). */ +#define DP_QC_RANDOMVEC +#define DP_QC_RENDER_SCENE /* clearscene+addentity+setviewprop+renderscene+setmodel are available to menuqc. WARNING: DP advertises this extension without actually supporting it, FTE does actually support it. */ +#define DP_QC_SINCOSSQRTPOW +#define DP_QC_SPRINTF /* Provides the sprintf builtin, which allows for rich formatting along the lines of C's function with the same name. Not to be confused with QC's sprint builtin. */ +#define DP_QC_STRFTIME +#define DP_QC_STRING_CASE_FUNCTIONS +#define DP_QC_STRINGBUFFERS +#define DP_QC_STRINGCOLORFUNCTIONS +#define DP_QC_STRREPLACE +#define DP_QC_TOKENIZEBYSEPARATOR +#define DP_QC_TRACEBOX +#define DP_QC_TRACETOSS +#define DP_QC_TRACE_MOVETYPE_HITMODEL +#define DP_QC_TRACE_MOVETYPE_WORLDONLY +#define DP_QC_TRACE_MOVETYPES +#define DP_QC_UNLIMITEDTEMPSTRINGS /* Supersedes DP_QC_MULTIPLETEMPSTRINGS, superseded by FTE_QC_PERSISTENTTEMPSTRINGS. Specifies that all temp strings will be valid at least until the QCVM returns. */ +#define DP_QC_URI_ESCAPE +#define DP_QC_URI_GET +#define DP_QC_URI_POST +#define DP_QC_VECTOANGLES_WITH_ROLL +#define DP_QC_VECTORVECTORS +#define DP_QC_WHICHPACK +#define DP_QUAKE2_MODEL +#define DP_QUAKE2_SPRITE +#define DP_QUAKE3_MODEL +#define DP_REGISTERCVAR +#define DP_SND_SOUND7_WIP2 +#define DP_SND_STEREOWAV +#define DP_SND_OGGVORBIS +#define DP_SOLIDCORPSE +#define DP_SPRITE32 +#define DP_SV_BOTCLIENT +#define DP_SV_CLIENTCOLORS /* Provided only for compatibility with DP. */ +#define DP_SV_CLIENTNAME /* Provided only for compatibility with DP. */ +#define DP_SV_DRAWONLYTOCLIENT +#define DP_SV_DROPCLIENT /* Equivelent to quakeworld's stuffcmd(self,"disconnect\n"); hack */ +#define DP_SV_EFFECT +#define DP_SV_EXTERIORMODELFORCLIENT +#define DP_SV_NODRAWTOCLIENT +#define DP_SV_PLAYERPHYSICS /* Allows reworking parts of NQ player physics. USE AT OWN RISK - this necessitates NQ physics and is thus guarenteed to break prediction. */ +#define DP_SV_POINTSOUND +#define DP_SV_PRECACHEANYTIME /* Specifies that the various precache builtins can be called at any time. WARNING: precaches are sent reliably while sound events, modelindexes, and particle events are not. This can mean sounds and particles might not work the first time around, or models may take a while to appear (after the reliables are received and the model is loaded from disk). Always attempt to precache a little in advance in order to reduce these issues (preferably at the start of the map...) */ +#define DP_SV_PRINT /* Says that the print builtin can be used from nqssqc (as well as just csqc), bypassing the developer cvar issues. */ +#define DP_SV_SETCOLOR +#define DP_SV_SPAWNFUNC_PREFIX +#define DP_SV_WRITEPICTURE +#define DP_SV_WRITEUNTERMINATEDSTRING +#define DP_TE_BLOOD +#define DP_TE_CUSTOMFLASH +#define DP_TE_EXPLOSIONRGB +#define DP_TE_PARTICLECUBE +#define DP_TE_PARTICLERAIN +#define DP_TE_PARTICLESNOW +#define DP_TE_SMALLFLASH +#define DP_TE_SPARK +#define DP_TE_STANDARDEFFECTBUILTINS +#define DP_VIEWZOOM +#define EXT_BITSHIFT +#define EXT_DIMENSION_VISIBILITY +#define EXT_DIMENSION_PHYSICS +#define EXT_DIMENSION_GHOST +#define FRIK_FILE +#define FTE_CALLTIMEOFDAY /* Replication of mvdsv functionality (call calltimeofday to cause 'timeofday' to be called, with arguments that can be saved off to a global). Generally strftime is simpler to use. */ +#define FTE_CSQC_ALTCONSOLES /* The engine tracks multiple consoles. These may or may not be directly visible to the user. */ +#define FTE_CSQC_BASEFRAME /* Specifies that .basebone, .baseframe2, .baselerpfrac, baseframe1time, etc exist in csqc. These fields affect all bones in the entity's model with a lower index than the .basebone field, allowing you to give separate control to the legs of a skeletal model, without affecting the torso animations. */ +#define FTE_CSQC_HALFLIFE_MODELS +#define FTE_CSQC_SERVERBROWSER /* Provides builtins to query the engine's serverbrowser servers list from ssqc. Note that these builtins are always available in menuqc. */ +#define FTE_CSQC_SKELETONOBJECTS /* Provides container objects for skeletal bone data, which can be modified on a per bone basis if needed. This allows you to dynamically generate animations (or just blend them with greater customisation) instead of being limited to a single animation or two. */ +#define FTE_CSQC_RAWIMAGES /* Provides raw rgba image access to csqc. With this, the csprogs can read textures into qc-accessible memory, modify it, and then upload it to the renderer. */ +#define FTE_CSQC_RENDERTARGETS /* VF_RT_DESTCOLOUR exists and can be used to redirect any rendering to a texture instead of the screen. */ +#define FTE_CSQC_REVERB /* Specifies that the mod can create custom reverb effects. Whether they will actually be used or not depends upon the sound driver. */ +#define FTE_CSQC_WINDOWCAPTION /* Provides csqc with the ability to change the window caption as displayed when running windowed or in the task bar when switched out. */ +#define FTE_ENT_SKIN_CONTENTS /* self.skin = CONTENTS_WATER; makes a brush entity into water. use -16 for a ladder. */ +#define FTE_ENT_UNIQUESPAWNID +#define FTE_EXTENDEDTEXTCODES +#define FTE_FORCESHADER /* Allows csqc to override shaders on models with an explicitly named replacement. Also allows you to define shaders with a fallback if it does not exist on disk. */ +#define FTE_FORCEINFOKEY /* Provides an easy way to change a user's userinfo from the server. */ +#define FTE_GFX_QUAKE3SHADERS /* specifies that the engine has full support for vanilla quake3 shaders */ +#define FTE_GFX_REMAPSHADER /* With the raw power of stuffcmds, the r_remapshader console command is exposed! This mystical command can be used to remap any shader to another. Remapped shaders that specify $diffuse etc in some form will inherit the textures implied by the surface. */ +#define FTE_GFX_MODELEVENTS /* Provides a query for per-animation events in model files, including from progs/foo.mdl.events files. */ +#define FTE_ISBACKBUFFERED /* Allows you to check if a client has too many reliable messages pending. */ +#define FTE_MEMALLOC /* Allows dynamically allocating memory. Use pointers to access this memory. Memory will not be saved into saved games. */ +#define FTE_MEDIA_AVI /* playfilm command supports avi files. */ +#define FTE_MEDIA_CIN /* playfilm command supports q2 cin files. */ +#define FTE_MEDIA_ROQ /* playfilm command supports q3 roq files. */ +#define FTE_MULTIPROGS /* Multiple progs.dat files can be loaded inside the same qcvm. Insert new ones with addprogs inside the 'init' function, and use externvalue+externset to rewrite globals (and hook functions) to link them together. Note that the result is generally not very clean unless you carefully design for it beforehand. */ +#define FTE_MULTITHREADED /* Faux multithreading, allowing multiple contexts to run in sequence. */ +#define FTE_MVD_PLAYERSTATS /* In csqc, getplayerstat can be used to query any player's stats when playing back MVDs. isdemo will return 2 in this case. */ +#define FTE_PART_SCRIPT /* Specifies that the r_particledesc cvar can be used to select a list of particle effects to load from particles/*.cfg, the format of which is documented elsewhere. */ +#define FTE_PART_NAMESPACES /* Specifies that the engine can use foo.bar to load effect foo from particle description bar. When used via ssqc, this should cause the client to download whatever effects as needed. */ +#define FTE_PART_NAMESPACE_EFFECTINFO /* Specifies that effectinfo.bar can load effects from effectinfo.txt for DP compatibility. */ +#define FTE_QC_BASEFRAME /* Specifies that .basebone and .baseframe exist in ssqc. These fields affect all bones in the entity's model with a lower index than the .basebone field, allowing you to give separate control to the legs of a skeletal model, without affecting the torso animations, from ssqc. */ +#define FTE_QC_FILE_BINARY /* Extends FRIK_FILE with binary read+write, as well as allowing seeking. Requires pointers. */ +#define FTE_QC_CHANGELEVEL_HUB /* Adds an extra argument to changelevel which is carried over to the next map in the 'spawnspot' global. Maps will be saved+reloaded until the extra argument is omitted again, purging all saved maps. Saved games will contain a copy of each preserved map. parm1-parm64 globals can be used, giving more space to transfer more player data. */ +#define FTE_QC_CHECKCOMMAND /* Provides a way to test if a console command exists, and whether its a command/alias/cvar. Does not say anything about the expected meanings of any arguments or values. */ +#define FTE_QC_CHECKPVS +#define FTE_QC_CROSSPRODUCT +#define FTE_QC_CUSTOMSKINS /* The engine supports the use of q3 skins, as well as the use of such skin 'files' to specify rich top+bottom colours, qw skins, geomsets, or texture composition even on non-players.. */ +#define FTE_QC_FS_SEARCH_SIZEMTIME +#define FTE_QC_HARDWARECURSORS /* setcursormode exists in both csqc+menuqc, and accepts additional arguments to specify a cursor image to use when this module has focus. If the image exceeds hardware limits (or hardware cursors are unsupported), it will be emulated using regular draws - this at least still avoids conflicting cursors as only one will ever be used, even if console+menu+csqc are all overlayed. */ +#define FTE_QC_HASHTABLES /* Provides efficient string-based lookups. */ +#define FTE_QC_INFOKEY /* QuakeWorld's infokey builtin works, and reports at least name+topcolor+bottomcolor+ping(in ms)+ip(unmasked, but not always ipv4)+team(aka bottomcolor in nq). Does not require actual localinfo/serverinfo/userinfo, but they're _highly_ recommended to any engines with csqc */ +#define FTE_QC_INTCONV /* Provides string<>int conversions, including hex representations. */ +#define FTE_QC_MATCHCLIENTNAME +#define FTE_QC_MULTICAST /* QuakeWorld's multicast builtin works along with MSG_MULTICAST, but also with unicast support. */ +#define FTE_QC_PAUSED +#define FTE_QC_PERSISTENTTEMPSTRINGS /* Supersedes DP_QC_MULTIPLETEMPSTRINGS. Temp strings are garbage collected automatically, and do not expire while they're still in use. This makes strzone redundant. */ +#define FTE_QC_RAGDOLL_WIP +#define FTE_QC_SENDPACKET /* Allows the use of out-of-band udp packets to/from other hosts. Includes the SV_ParseConnectionlessPacket event. */ +#define FTE_QC_STUFFCMDFLAGS /* Variation on regular stuffcmd that gives control over how spectators/mvds should be treated. */ +#define FTE_QC_TRACETRIGGER +#define FTE_QUAKE2_CLIENT /* This engine is able to act as a quake2 client */ +#define FTE_QUAKE2_SERVER /* This engine is able to act as a quake2 server */ +#define FTE_QUAKE3_CLIENT /* This engine is able to act as a quake3 client */ +#define FTE_QUAKE3_SERVER /* This engine is able to act as a quake3 server */ +#define FTE_SOLID_LADDER /* Allows a simple trigger to remove effects of gravity (solid 20). obsolete. will prolly be removed at some point as it is not networked properly. Use FTE_ENT_SKIN_CONTENTS */ +#define FTE_SPLITSCREEN /* Client supports splitscreen, controlled via cl_splitscreen. Servers require allow_splitscreen 1 if splitscreen is to be used over the internet. Mods that use csqc will need to be aware for this to work properly. per-client networking may be problematic. */ +#define FTE_SQL /* Provides sql* builtins which can be used for sql database access */ +#define FTE_SQL_SQLITE /* SQL functionality is able to utilise sqlite databases */ +#define FTE_STRINGS /* Extra builtins (and additional behaviour) to make string manipulation easier */ +#define FTE_SV_POINTPARTICLES /* Specifies that particleeffectnum, pointparticles, and trailparticles exist in ssqc as well as csqc. particleeffectnum acts as a precache, allowing ssqc values to be networked up with csqc for use. Use in combination with FTE_PART_SCRIPT+FTE_PART_NAMESPACES to use custom effects. This extension is functionally identical to the DP version, but avoids any misplaced assumptions about the format of the client's particle descriptions. */ +#define FTE_SV_REENTER +#define FTE_TE_STANDARDEFFECTBUILTINS /* Provides builtins to replace writebytes, with a QW compatible twist. */ +#define FTE_TERRAIN_MAP /* This engine supports .hmp files, as well as terrain embedded within bsp files. */ +#define FTE_RAW_MAP /* This engine supports directly loading .map files, as well as realtime editing of the various brushes. */ +#define KRIMZON_SV_PARSECLIENTCOMMAND /* SSQC's SV_ParseClientCommand function is able to handle client 'cmd' commands. The tokenizing parts also work in csqc. */ +#define NEH_CMD_PLAY2 +#define NEH_RESTOREGAME +#define QSG_CVARSTRING +#define QW_ENGINE +#define QWE_MVD_RECORD /* You can use the easyrecord command to record MVD demos serverside. */ +#define TEI_MD3_MODEL +#define TENEBRAE_GFX_DLIGHTS /* Allows ssqc to attach rtlights to entities with various special properties. */ +#define ZQ_MOVETYPE_FLY /* MOVETYPE_FLY works on players. */ +#define ZQ_MOVETYPE_NOCLIP /* MOVETYPE_NOCLIP works on players. */ +#define ZQ_MOVETYPE_NONE /* MOVETYPE_NONE works on players. */ +#define ZQ_VWEP +#define ZQ_QC_STRINGS /* The strings-only subset of FRIK_FILE is supported. */ + +#ifdef _ACCESSORS +accessor strbuf : float; +accessor searchhandle : float; +accessor hashtable : float; +accessor infostring : string; +accessor filestream : float; +accessor filestream : float; +#else +#define strbuf float +#define searchhandle float +#define hashtable float +#define infostring string +#define filestream float +#endif + +entity self; /* The magic me */ +void end_sys_globals; +void end_sys_fields; +float time; /* The current local time. Increases while paused. */ +void(float reqid, float responsecode, string resourcebody) URI_Get_Callback; /* Called as an eventual result of the uri_get builtin. */ +void(string cmdtext) GameCommand; +string(string uri, string method, string postdata, __in string requestheaders, __inout string responseheaders) Cef_GeneratePage; /* Provides an entrypoint to generate pages for the CEF plugin from within QC. Headers are +-separated key/value pairs (use tokenizebyseparator). */ +void() m_init; +void() m_shutdown; +void(vector screensize) m_draw; /* Provides the menuqc with a chance to draw. Will be called even if the menu does not have focus, so be sure to avoid that. COMPAT: screensize is not provided in DP. */ +void(vector screensize, float opaque) m_drawloading; /* Additional drawing function to draw loading screens. If opaque is set, then this function must ensure that the entire screen is overdrawn (even if just by a black drawfill). */ +float(float evtype, float scanx, float chary, float devid) Menu_InputEvent; /* If present, this is called instead of m_keydown and m_keyup +Called whenever a key is pressed, the mouse is moved, etc. evtype will be one of the IE_* constants. The other arguments vary depending on the evtype. Key presses are not guarenteed to have both scan and unichar values set at the same time. */ +void(float scan, float chr) m_keydown; +void(float scan, float chr) m_keyup; +void(float wantmode) m_toggle; +float(string cmd) m_consolecommand; +var vector drawfontscale = '1 1 0'; /* Specifies a scaler for all text rendering. There are other ways to implement this. */ +float drawfont; /* Allows you to choose exactly which font is to be used to draw text. Fonts can be registered/allocated with the loadfont builtin. */ +const float FONT_DEFAULT = 0; +const float TRUE = 1; +const float FALSE = 0; /* File not found... */ +const float M_PI = 3.14159; +const float RESTYPE_MODEL = 0; /* RESTYPE_* constants are used as arguments with the resourcestatus builtin. */ +const float RESTYPE_SOUND = 1; /* precache_sound */ +const float RESTYPE_PARTICLE = 2; /* particleeffectnum */ +const float RESTYPE_PIC = 3; /* precache_pic. Status results are an amalgomation of the textures used by the named shader. */ +const float RESTYPE_SKIN = 4; /* setcustomskin */ +const float RESTYPE_TEXTURE = 5; /* Individual textures within shaders. These are not directly usable, but may be named as part of a skin file, or a shader. */ +const float RESSTATE_NOTKNOWN = 0; /* RESSTATE_* constants are return values from the resourcestatus builtin. The engine doesn't know about the resource if it is in this state. This means you will need to precache it. Attempting to use it anyway may result in warnings, errors, or silently succeed, depending on engine version and resource type. */ +const float RESSTATE_NOTLOADED = 1; /* The resource was precached, but has been flushed and there has not been an attempt to reload it. If you use the resource normally, chances are it'll be loaded but at the cost of a stall. */ +const float RESSTATE_LOADING = 2; /* Resources in this this state are queued for loading, and will be loaded at the engine's convienience. If you attempt to query the resource now, the engine will stall until the result is available. sounds in this state may be delayed, while models/pics/shaders may be invisible. */ +const float RESSTATE_FAILED = 3; /* Resources in this state are unusable/could not be loaded. You will get placeholders or dummy results. Queries will not stall the engine. The engine may display placeholder content. */ +const float RESSTATE_LOADED = 4; /* Resources in this state are finally usable, everything will work okay. Hurrah. Queries will not stall the engine. */ +hashtable gamestate; /* Special hash table index for hash_add and hash_get. Entries in this table will persist over map changes (and doesn't need to be created/deleted). */ +const float HASH_REPLACE = 256; /* Used with hash_add. Attempts to remove the old value instead of adding two values for a single key. */ +const float HASH_ADD = 512; /* Used with hash_add. The new entry will be inserted in addition to the existing entry. */ +const float VF_MIN = 1; /* The top-left of the 3d viewport in screenspace. The VF_ values are used via the setviewprop/getviewprop builtins. */ +const float VF_MIN_X = 2; +const float VF_MIN_Y = 3; +const float VF_SIZE = 4; /* The width+height of the 3d viewport in screenspace. */ +const float VF_SIZE_X = 5; +const float VF_SIZE_Y = 6; +const float VF_VIEWPORT = 7; /* vector+vector. Two argument shortcut for VF_MIN and VF_SIZE */ +const float VF_FOV = 8; /* sets both fovx and fovy. consider using afov instead. */ +const float VF_FOVX = 9; /* horizontal field of view. does not consider aspect at all. */ +const float VF_FOVY = 10; /* vertical field of view. does not consider aspect at all. */ +const float VF_ORIGIN = 11; /* The origin of the view. Not of the player. */ +const float VF_ORIGIN_X = 12; +const float VF_ORIGIN_Y = 13; +const float VF_ORIGIN_Z = 14; +const float VF_ANGLES = 15; /* The angles the view will be drawn at. Not the angle the client reports to the server. */ +const float VF_ANGLES_X = 16; +const float VF_ANGLES_Y = 17; +const float VF_ANGLES_Z = 18; +const float VF_MINDIST = 23; /* The distance of the near clip plane from the view position. Should generally not be <=0, as this would introduce NANs. */ +const float VF_MAXDIST = 24; /* The distance of the far clip plane from the view position. If 0, will be considered infinite. */ +const float VF_PERSPECTIVE = 200; /* 1: regular rendering. Fov specifies the angle. 0: isometric-style. Fov specifies the number of Quake Units each side of the viewport, and mindist restrictions are removed, pvs culling should be disabled. */ +const float VF_AFOV = 203; /* Aproximate fov. Matches the 'fov' cvar. The engine handles the aspect ratio for you. */ +const float VF_SCREENVSIZE = 204; /* Provides a reliable way to retrieve the current virtual screen size (even if the screen is automatically scaled to retain aspect). */ +const float VF_SCREENPSIZE = 205; /* Provides a reliable way to retrieve the current physical screen size (cvars need vid_restart for them to take effect). */ +const float VF_RT_DESTCOLOUR = 212; /* The texture name to write colour info into, this includes both 3d and 2d drawing. +Additional arguments are: format (rgba8=1,rgba16f=2,rgba32f=3), sizexy. +Written to by both 3d and 2d rendering. +Note that any rendertarget textures may be destroyed on video mode changes or so. Shaders can name render targets by prefixing texture names with '$rt:', or $sourcecolour. */ +const float VF_RT_SOURCECOLOUR = 209; /* The texture name to use with shaders that specify a $sourcecolour map. */ +const float VF_RT_DEPTH = 210; /* The texture name to use as a depth buffer. Also used for shaders that specify $sourcedepth. 1-based. Additional arguments are: format (16bit=4,24bit=5,32bit=6), sizexy. */ +const float VF_RT_RIPPLE = 211; /* The texture name to use as a ripplemap (target for shaders with 'sort ripple'). Also used for shaders that specify $ripplemap. 1-based. Additional arguments are: format, sizexy. */ +const float VF_ENVMAP = 220; /* The cubemap name to use as a fallback for $reflectcube, if a shader was unable to load one. Note that this doesn't automatically change shader permutations or anything. */ +const float VF_USERDATA = 221; /* Pointer (and byte size) to an array of vec4s. This data is then globally visible to all glsl via the w_user uniform. */ +const float RF_DEPTHHACK = 4; /* Hacks the depth values such that the entity uses depth values as if it were closer to the screen. This is useful when combined with viewmodels to avoid weapons poking in to walls. */ +const float RF_ADDITIVE = 8; /* Shaders from this entity will temporarily be hacked to use an additive blend mode instead of their normal blend mode. */ +const float FILE_READ = 0; /* The file may be read via fgets to read a single line at a time. */ +const float FILE_APPEND = 1; /* Like FILE_WRITE, but writing starts at the end of the file. */ +const float FILE_WRITE = 2; /* fputs will be used to write to the file. */ +const float SLIST_HOSTCACHEVIEWCOUNT = 0; +const float SLIST_HOSTCACHETOTALCOUNT = 1; +const float SLIST_MASTERQUERYCOUNT = 2; +const float SLIST_MASTERREPLYCOUNT = 3; +const float SLIST_SERVERQUERYCOUNT = 4; +const float SLIST_SERVERREPLYCOUNT = 5; +const float SLIST_SORTFIELD = 6; +const float SLIST_SORTDESCENDING = 7; +const float SLIST_TEST_CONTAINS = 0; +const float SLIST_TEST_NOTCONTAIN = 1; +const float SLIST_TEST_LESSEQUAL = 2; +const float SLIST_TEST_LESS = 3; +const float SLIST_TEST_EQUAL = 4; +const float SLIST_TEST_GREATER = 5; +const float SLIST_TEST_GREATEREQUAL = 6; +const float SLIST_TEST_NOTEQUAL = 7; +const float SLIST_TEST_STARTSWITH = 8; +const float SLIST_TEST_NOTSTARTSWITH = 9; +float(string ext) checkextension = #1; /* + Checks if the named extension is supported by the running engine. */ + +void(string err,...) error = #2; +void(string err,...) objerror = #3; +void(string text,...) print = #4; /* Part of DP_SV_PRINT*/ +void(string text,...) bprint = #5; +void(float clientnum, string text,...) msprint = #6; +void(string text,...) cprint = #7; +vector(vector) normalize = #8; +float(vector) vlen = #9; +float(vector) vectoyaw = #10; +vector(vector) vectoangles = #11; +float() random = #12; +void(string,...) localcmd = #13; +float(string name) cvar = #14; +void(string name, string value) cvar_set = #15; +void(string text) dprint = #16; +string(float) ftos = #17; +float(float) fabs = #18; +string(vector) vtos = #19; +string(entity) etos = #20; /* Part of DP_QC_ETOS*/ +float(string) stof = #21; /* Part of FRIK_FILE, FTE_QC_INFOKEY, FTE_STRINGS, QW_ENGINE, ZQ_QC_STRINGS*/ +entity() spawn = #22; +void(entity) remove = #23; +entity(entity start, .string field, string match) find = #24; +entity(entity start, .__variant field, __variant match) findfloat = #25; /* Part of DP_QC_FINDFLOAT*/ +entity(.string field, string match) findchain = #26; /* Part of DP_QC_FINDCHAIN*/ +entity(.__variant field, __variant match) findchainfloat = #27; /* Part of DP_QC_FINDCHAINFLOAT*/ +string(string file) precache_file = #28; +string(string sample) precache_sound = #29; +void() coredump = #30; +void() traceon = #31; +void() traceoff = #32; +void(entity) eprint = #33; +float(float) rint = #34; +float(float) floor = #35; +float(float) ceil = #36; +entity(entity) nextent = #37; +float(float) sin = #38; /* Part of DP_QC_SINCOSSQRTPOW*/ +float(float) cos = #39; /* Part of DP_QC_SINCOSSQRTPOW*/ +float(float) sqrt = #40; /* Part of DP_QC_SINCOSSQRTPOW*/ +vector() randomvector = #41; +float(string name, string value, float flags) registercvar = #42; /* Part of DP_REGISTERCVAR*/ +float(float,...) min = #43; /* Part of DP_QC_MINMAXBOUND*/ +float(float,...) max = #44; /* Part of DP_QC_MINMAXBOUND*/ +float(float min,float value,float max) bound = #45; /* Part of DP_QC_MINMAXBOUND*/ +float(float,float) pow = #46; /* Part of DP_QC_SINCOSSQRTPOW*/ +void(entity src, entity dst) copyentity = #47; /* Part of DP_QC_COPYENTITY*/ +filestream(string filename, float mode) fopen = #48; /* Part of FRIK_FILE*/ +void(filestream fhandle) fclose = #49; /* Part of FRIK_FILE*/ +string(filestream fhandle) fgets = #50; /* Part of FRIK_FILE*/ +void(filestream fhandle, string s) fputs = #51; /* Part of FRIK_FILE*/ +float(string) strlen = #52; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +string(string, optional string, optional string, optional string, optional string, optional string, optional string, optional string) strcat = #53; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +string(string s, float start, float length) substring = #54; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +vector(string) stov = #55; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +string(string) strzone = #56; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +void(string) strunzone = #57; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/ +float(string) tokenize = #58; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ +string(float) argv = #59; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ +float() isserver = #60; +float() clientcount = #61; +float() clientstate = #62; +void(string map) changelevel = #64; +void(string sample, optional float channel, optional float volume) localsound = #65; +vector() getmousepos = #66; +float(optional float timetype) gettime = #67; +void(string data) loadfromdata = #68; +void(string data) loadfromfile = #69; +float(float val, float m) mod = #70; +string(string name) cvar_string = #71; /* Part of DP_QC_CVAR_STRING*/ +void() crash = #72; +void() stackdump = #73; +searchhandle(string pattern, float caseinsensitive, float quiet) search_begin = #74; /* Part of DP_QC_FS_SEARCH*/ +void(searchhandle handle) search_end = #75; /* Part of DP_QC_FS_SEARCH*/ +float(searchhandle handle) search_getsize = #76; /* Part of DP_QC_FS_SEARCH*/ +string(searchhandle handle, float num) search_getfilename = #77; /* Part of DP_QC_FS_SEARCH*/ +float(entity) etof = #79; +entity(float) ftoe = #80; +float(string) validstring = #81; +float(string str) altstr_count = #82; +string(string str) altstr_prepare = #83; +string(string str, float num) altstr_get = #84; +string(string str, float num, string set) altstr_set = #85; +entity(entity start, .float field, float match) findflags = #87; /* Part of DP_QC_FINDFLAGS*/ +entity(.float field, float match) findchainflags = #88; /* Part of DP_QC_FINDCHAINFLAGS*/ +void(entity ent, string mname) setmodel = #90; /* + Menuqc-specific version. */ + +void(string mname) precache_model = #91; /* + Menuqc-specific version. */ + +void(entity ent, vector neworg) setorigin = #92; /* + Menuqc-specific version. */ + +float(float v, optional float base) logarithm = #0:logarithm; /* + Determines the logarithm of the input value according to the specified base. This can be used to calculate how much something was shifted by. */ + +float(__variant funcref) checkbuiltin = #0:checkbuiltin; /* + Checks to see if the specified builtin is supported/mapped. This is intended as a way to check for #0 functions, allowing for simple single-builtin functions. Warning, if two different engines map different builtins to the same number, then this function will not tell you which will be called, only that it won't crash (the exception being #0, which are remapped as available). */ + +int(filestream fhandle, void *ptr, int size) fread = #0:fread; /* Part of FTE_QC_FILE_BINARY + Reads binary data out of the file. Returns truncated lengths if the read exceeds the length of the file. */ + +int(filestream fhandle, void *ptr, int size) fwrite = #0:fwrite; /* Part of FTE_QC_FILE_BINARY + Writes binary data out of the file. */ + +#define ftell fseek //c compat +int(filestream fhandle, optional int newoffset) fseek = #0:fseek; /* Part of FTE_QC_FILE_BINARY + Changes the current position of the file, if specified. Returns prior position, in bytes. */ + +int(filestream fhandle, optional int newsize) fsize = #0:fsize; /* Part of FTE_QC_FILE_BINARY + Reports the total size of the file, in bytes. Can also be used to truncate/extend the file */ + +void(optional __variant ret) abort = #211; /* Part of FTE_MULTITHREADED + QC execution is aborted. Parent QC functions on the stack will be skipped, effectively this forces all QC functions to 'return ret' until execution returns to the engine. If ret is ommited, it is assumed to be 0. */ + +float(string s1, string sub, optional float startidx) strstrofs = #221; /* Part of FTE_STRINGS + Returns the 0-based offset of sub within the s1 string, or -1 if sub is not in s1. + If startidx is set, this builtin will ignore matches before that 0-based offset. */ + +float(string str, float index) str2chr = #222; /* Part of FTE_STRINGS + Retrieves the character value at offset 'index'. */ + +string(float chr, ...) chr2str = #223; /* Part of FTE_STRINGS + The input floats are considered character values, and are concatenated. */ + +string(float ccase, float redalpha, float redchars, string str, ...) strconv = #224; /* Part of FTE_STRINGS + Converts quake chars in the input string amongst different representations. + ccase specifies the new case for letters. + 0: not changed. + 1: forced to lower case. + 2: forced to upper case. + redalpha and redchars switch between colour ranges. + 0: no change. + 1: Forced white. + 2: Forced red. + 3: Forced gold(low) (numbers only). + 4: Forced gold (high) (numbers only). + 5+6: Forced to white and red alternately. + You should not use this builtin in combination with UTF-8. */ + +string(float pad, string str1, ...) strpad = #225; /* Part of FTE_STRINGS + Pads the string with spaces, to ensure its a specific length (so long as a fixed-width font is used, anyway). If pad is negative, the spaces are added on the left. If positive the padding is on the right. */ + +string(infostring old, string key, string value) infoadd = #226; /* Part of FTE_STRINGS + Returns a new tempstring infostring with the named value changed (or added if it was previously unspecified). Key and value may not contain the \ character. */ + +string(infostring info, string key) infoget = #227; /* Part of FTE_STRINGS + Reads a named value from an infostring. The returned value is a tempstring */ + +#define strcmp strncmp +float(string s1, string s2, optional float len, optional float s1ofs, optional float s2ofs) strncmp = #228; /* Part of FTE_STRINGS + Compares up to 'len' chars in the two strings. s1ofs allows you to treat s2 as a substring to compare against, or should be 0. + Returns 0 if the two strings are equal, a negative value if s1 appears numerically lower, and positive if s1 appears numerically higher. */ + +float(string s1, string s2) strcasecmp = #229; /* Part of FTE_STRINGS + Compares the two strings without case sensitivity. + Returns 0 if they are equal. The sign of the return value may be significant, but should not be depended upon. */ + +float(string s1, string s2, float len, optional float s1ofs, optional float s2ofs) strncasecmp = #230; /* Part of FTE_STRINGS + Compares up to 'len' chars in the two strings without case sensitivity. s1ofs allows you to treat s2 as a substring to compare against, or should be 0. + Returns 0 if they are equal. The sign of the return value may be significant, but should not be depended upon. */ + +string(string s) strtrim = #0:strtrim; /* + Trims the whitespace from the start+end of the string. */ + +float(string shadername, optional string defaultshader, ...) shaderforname = #238; /* Part of FTE_FORCESHADER + Caches the named shader and returns a handle to it. + If the shader could not be loaded from disk (missing file or ruleset_allow_shaders 0), it will be created from the 'defaultshader' string if specified, or a 'skin shader' default will be used. + defaultshader if not empty should include the outer {} that you would ordinarily find in a shader. */ + +void(string destaddress, string content) sendpacket = #242; /* Part of FTE_QC_SENDPACKET + Sends a UDP packet to the specified destination. Note that the payload will be prefixed with four 255 bytes as a sort of security feature. */ + +int(float) ftoi = #0:ftoi; /* Part of FTE_QC_INTCONV + Converts the given float into a true integer without depending on extended qcvm instructions. */ + +float(int) itof = #0:itof; /* Part of FTE_QC_INTCONV + Converts the given true integer into a float without depending on extended qcvm instructions. */ + +#define dotproduct(v1,v2) ((vector)(v1)*(vector)(v2)) +vector(vector v1, vector v2) crossproduct = #0:crossproduct; /* Part of FTE_QC_CROSSPRODUCT + Small helper function to calculate the crossproduct of two vectors. */ + +hashtable(float tabsize, optional float defaulttype) hash_createtab = #287; /* Part of FTE_QC_HASHTABLES + Creates a hash table object with at least 'tabsize' slots. hash table with index 0 is a game-persistant table and will NEVER be returned by this builtin (except as an error return). */ + +void(hashtable table) hash_destroytab = #288; /* Part of FTE_QC_HASHTABLES + Destroys a hash table object. */ + +void(hashtable table, string name, __variant value, optional float typeandflags) hash_add = #289; /* Part of FTE_QC_HASHTABLES + Adds the given key with the given value to the table. + If flags&HASH_REPLACE, the old value will be removed, if not set then multiple values may be added for a single key, they won't overwrite. + The type argument describes how the value should be stored and saved to files. While you can claim that all variables are just vectors, being more precise can result in less issues with tempstrings or saved games. */ + +__variant(hashtable table, string name, optional __variant deflt, optional float requiretype, optional float index) hash_get = #290; /* Part of FTE_QC_HASHTABLES + looks up the specified key name in the hash table. returns deflt if key was not found. If stringsonly=1, the return value will be in the form of a tempstring, otherwise it'll be the original value argument exactly as it was. If requiretype is specified, then values not of the specified type will be ignored. Hurrah for multiple types with the same name. */ + +__variant(hashtable table, string name) hash_delete = #291; /* Part of FTE_QC_HASHTABLES + removes the named key. returns the value of the object that was destroyed, or 0 on error. */ + +string(hashtable table, float idx) hash_getkey = #292; /* Part of FTE_QC_HASHTABLES + gets some random key name. add+delete can change return values of this, so don't blindly increment the key index if you're removing all. */ + +float(string name) checkcommand = #294; /* Part of FTE_QC_CHECKCOMMAND + Checks to see if the supplied name is a valid command, cvar, or alias. Returns 0 if it does not exist. */ + +string(string s) argescape = #295; /* + Marks up a string so that it can be reliably tokenized as a single argument later. */ + +void() clearscene = #300; /* + Forgets all rentities, polygons, and temporary dlights. Resets all view properties to their default values. */ + +void(entity ent) addentity = #302; /* + Copies the entity fields into a new rentity for later rendering via addscene. */ + +#define setviewprop setproperty +float(float property, ...) setproperty = #303; /* + Allows you to override default view properties like viewport, fov, and whether the engine hud will be drawn. Different VF_ values have slightly different arguments, some are vectors, some floats. */ + +void() renderscene = #304; /* + Draws all entities, polygons, and particles on the rentity list (which were added via addentities or addentity), using the various view properties set via setproperty. There is no ordering dependancy. + The scene must generally be cleared again before more entities are added, as entities will persist even over to the next frame. + You may call this builtin multiple times per frame, but should only be called from CSQC_UpdateView. */ + +void(string texturename, optional float flags, optional float is2d) R_BeginPolygon = #306; /* + Specifies the shader to use for the following polygons, along with optional flags. + If is2d, the polygon will be drawn as soon as the EndPolygon call is made, rather than waiting for renderscene. This allows complex 2d effects. */ + +void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex = #307; /* + Specifies a polygon vertex with its various properties. */ + +void() R_EndPolygon = #308; /* + Ends the current polygon. At least 3 verticies must have been specified. You do not need to call beginpolygon if you wish to draw another polygon with the same shader. */ + +#define getviewprop getproperty +__variant(float property) getproperty = #309; /* + Retrieve a currently-set (typically view) property, allowing you to read the current viewport or other things. Due to cheat protection, certain values may be unretrievable. */ + +void(vector pos, vector size, float alignflags, string text) drawtextfield = #0:drawtextfield; /* + Draws a multi-line block of text, including word wrapping and alignment. alignflags bits are RTLB, typically 3. */ + +void(string imagename, int width, int height, void *pixeldata, optional int datasize, optional int format) r_uploadimage = #0:r_uploadimage; /* Part of FTE_CSQC_RAWIMAGES + Updates a texture with the specified rgba data. Will be created if needed. If blobsize is specified then the image is decoded (eg .ktx or .dds data) instead of being raw R8G8B8A data. You'll typically want shaderforname to also generate a shader to use the texture. */ + +int*(string filename, __out int width, __out int height) r_readimage = #0:r_readimage; /* Part of FTE_CSQC_RAWIMAGES + Reads and decodes an image from disk, providing raw R8G8B8A pixel data. Should not be used for dds or ktx etc formats. Returns __NULL__ if the image could not be read for any reason. Use memfree to free the data once you're done with it. */ + +void(vector pivot, vector mins, vector maxs, string pic, vector rgb, float alpha, float angle) drawrotpic = #0:drawrotpic; /* + Draws an image rotating at the pivot. To rotate in the center, use mins+maxs of half the size with mins negated. Angle is in degrees. */ + +void(vector pivot, vector mins, vector maxs, string pic, vector txmin, vector txsize, vector rgb, vector alphaandangles) drawrotsubpic = #0:drawrotsubpic; /* + Overcomplicated draw function for over complicated people. Positions follow drawrotpic, while texture coords follow drawsubpic. Due to argument count limitations in builtins, the alpha value and angles are combined into separate fields of a vector (tip: use fteqcc's [alpha, angle] feature. */ + +string(float keynum) keynumtostring_csqc = #340; /* + Returns a hunam-readable name for the given keycode, as a tempstring. */ + +float(string keyname) stringtokeynum_csqc = #341; /* + Looks up the key name in the same way that the bind command would, returning the keycode for that key. */ + +string(float keynum) getkeybind = #342; /* + Returns the current binding for the given key (returning only the command executed when no modifiers are pressed). */ + +void(float usecursor, optional string cursorimage, optional vector hotspot, optional float scale) setcursormode = #343; /* + Pass TRUE if you want the engine to release the mouse cursor (absolute input events + touchscreen mode). Pass FALSE if you want the engine to grab the cursor (relative input events + standard looking). If the image name is specified, the engine will use that image for a cursor (use an empty string to clear it again), in a way that will not conflict with the console. Images specified this way will be hardware accelerated, if supported by the platform/port. */ + +float(float effective) getcursormode = #0:getcursormode; /* + Reports the cursor mode this module previously attempted to use. If 'effective' is true, reports the cursor mode currently active (if was overriden by a different module which has precidence, for instance, or if there is only a touchscreen and no mouse). */ + +float() isdemo = #349; /* + Returns if the client is currently playing a demo or not. Returns 2 when playing an mvd (where other player's stats can be queried, or the pov can be changed freely). */ + +void(string cmdname) registercommand = #352; /* + Register the given console command, for easy console use. + Console commands that are later used will invoke CSQC_ConsoleCommand. */ + +float(string s) findfont = #356; /* Part of DP_GFX_FONTS + Looks up a named font slot. Matches the actual font name as a last resort. */ + +float(string fontname, string fontmaps, string sizes, float slot, optional float fix_scale, optional float fix_voffset) loadfont = #357; /* Part of DP_GFX_FONTS + too convoluted for me to even try to explain correct usage. Try drawfont = loadfont("", "cour", "16", -1, 0, 0); to switch to the courier font (optimised for 16 virtual pixels high), if you have the freetype2 library in windows.. */ + +void(entity e, string skinfilename, optional string skindata) setcustomskin = #376; /* Part of FTE_QC_CUSTOMSKINS + Sets an entity's skin overrides to a new skin object. Releases the entities old skin (refcounted). */ + +__variant*(int size) memalloc = #384; /* Part of FTE_MEMALLOC + Allocate an arbitary block of memory */ + +void(__variant *ptr) memfree = #385; /* Part of FTE_MEMALLOC + Frees a block of memory that was allocated with memfree */ + +void(__variant *dst, __variant *src, int size) memcpy = #386; /* Part of FTE_MEMALLOC + Copys memory from one location to another */ + +void(__variant *dst, int val, int size) memfill8 = #387; /* Part of FTE_MEMALLOC + Sets an entire block of memory to a specified value. Pretty much always 0. */ + +__variant(__variant *dst, float ofs) memgetval = #388; /* + Looks up the 32bit value stored at a pointer-with-offset. */ + +void(__variant *dst, float ofs, __variant val) memsetval = #389; /* + Changes the 32bit value stored at the specified pointer-with-offset. */ + +__variant*(__variant *base, float ofs) memptradd = #390; /* + Perform some pointer maths. Woo. */ + +float(string s) memstrsize = #0:memstrsize; /* + strlen, except ignores utf-8 */ + +string(string conname, string field, optional string newvalue) con_getset = #391; /* Part of FTE_CSQC_ALTCONSOLES + Reads or sets a property from a console object. The old value is returned. Iterrate through consoles with the 'next' field. Valid properties: title, name, next, unseen, markup, forceutf8, close, clear, hidden, linecount */ + +void(string conname, string messagefmt, ...) con_printf = #392; /* Part of FTE_CSQC_ALTCONSOLES + Prints onto a named console. */ + +void(string conname, vector pos, vector size, float fontsize) con_draw = #393; /* Part of FTE_CSQC_ALTCONSOLES + Draws the named console. */ + +float(string conname, float inevtype, float parama, float paramb, float paramc) con_input = #394; /* Part of FTE_CSQC_ALTCONSOLES + Forwards input events to the named console. Mouse updates should be absolute only. */ + +float() cvars_haveunsaved = #0:cvars_haveunsaved; /* + Returns true if any archived cvar has an unsaved value. */ + +float(entity e, float nowreadonly) entityprotection = #0:entityprotection; /* + Changes the protection on the specified entity to protect it from further edits from QC. The return value is the previous setting. Note that this can be used to unprotect the world, but doing so long term is not advised as you will no longer be able to detect invalid entity references. Also, world is not networked, so results might not be seen by clients (or in other words, world.avelocity_y=64 is a bad idea). */ + +strbuf() buf_create = #440; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle) buf_del = #441; /* Part of DP_QC_STRINGBUFFERS*/ +float(strbuf bufhandle) buf_getsize = #442; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle_from, float bufhandle_to) buf_copy = #443; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle, float sortprefixlen, float backward) buf_sort = #444; /* Part of DP_QC_STRINGBUFFERS*/ +string(strbuf bufhandle, string glue) buf_implode = #445; /* Part of DP_QC_STRINGBUFFERS*/ +string(strbuf bufhandle, float string_index) bufstr_get = #446; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle, float string_index, string str) bufstr_set = #447; /* Part of DP_QC_STRINGBUFFERS*/ +float(strbuf bufhandle, string str, float ordered) bufstr_add = #448; /* Part of DP_QC_STRINGBUFFERS*/ +void(strbuf bufhandle, float string_index) bufstr_free = #449; /* Part of DP_QC_STRINGBUFFERS*/ +float(string name) iscachedpic = #451; +string(string name, optional float trywad) precache_pic = #452; +float(vector position, float character, vector scale, vector rgb, float alpha, optional float flag) drawcharacter = #454; +float(vector position, string text, vector scale, vector rgb, float alpha, optional float flag) drawrawstring = #455; +float(vector position, string pic, vector size, vector rgb, float alpha, optional float flag) drawpic = #456; +float(vector position, vector size, vector rgb, float alpha, optional float flag) drawfill = #457; +void(float x, float y, float width, float height) drawsetcliparea = #458; +void(void) drawresetcliparea = #459; +vector(string picname) drawgetimagesize = #460; +float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring = #467; +float(string text, float usecolours, optional vector fontsize) stringwidth = #468; +void(vector pos, vector sz, string pic, vector srcpos, vector srcsz, vector rgb, float alpha, float flag) drawsubpic = #469; +float(searchhandle handle, float num) search_getfilesize = #0:search_getfilesize; /* Part of FTE_QC_FS_SEARCH_SIZEMTIME + Retrieves the size of one of the files that was found by the initial search. */ + +string(searchhandle handle, float num) search_getfilemtime = #0:search_getfilemtime; /* Part of FTE_QC_FS_SEARCH_SIZEMTIME + Retrieves modification time of one of the files. */ + +float(float s) asin = #471; /* Part of DP_QC_ASINACOSATANATAN2TAN*/ +float(float c) acos = #472; /* Part of DP_QC_ASINACOSATANATAN2TAN*/ +float(float t) atan = #473; /* Part of DP_QC_ASINACOSATANATAN2TAN*/ +float(float c, float s) atan2 = #474; /* Part of DP_QC_ASINACOSATANATAN2TAN*/ +float(float a) tan = #475; /* Part of DP_QC_ASINACOSATANATAN2TAN + Forgive me father, for I have a sunbed and I'm not afraid to use it. */ + +float(string s) strlennocol = #476; /* Part of DP_QC_STRINGCOLORFUNCTIONS + Returns the number of characters in the string after any colour codes or other markup has been parsed. */ + +string(string s) strdecolorize = #477; /* Part of DP_QC_STRINGCOLORFUNCTIONS + Flattens any markup/colours, removing them from the string. */ + +string(float uselocaltime, string format, ...) strftime = #478; /* Part of DP_QC_STRFTIME*/ +float(string s, string separator1, ...) tokenizebyseparator = #479; /* Part of DP_QC_TOKENIZEBYSEPARATOR*/ +string(string s) strtolower = #480; /* Part of DP_QC_STRING_CASE_FUNCTIONS*/ +string(string s) strtoupper = #481; /* Part of DP_QC_STRING_CASE_FUNCTIONS*/ +string(string s) cvar_defstring = #482; /* Part of DP_QC_CVAR_DEFSTRING*/ +string(string search, string replace, string subject) strreplace = #484; /* Part of DP_QC_STRREPLACE*/ +string(string search, string replace, string subject) strireplace = #485; /* Part of DP_QC_STRREPLACE*/ +float(string name, optional string initialURI) gecko_create = #487; /* Part of DP_GECKO_SUPPORT + Create a new 'browser tab' shader with the specified name that can then be drawn via drawpic (shader should not already exist - including from map/model textures or disk). In order to function correctly, this builtin depends upon external plugins being available. Use gecko_navigate to navigate it to a page of your choosing. */ + +void(string name) gecko_destroy = #488; /* Part of DP_GECKO_SUPPORT + Destroy a shader. */ + +void(string name, string URI) gecko_navigate = #489; /* Part of DP_GECKO_SUPPORT + Sends a command to the media decoder attached to the specified shader. In the case of a browser decoder, this changes the url that the browser displays. 'cmd:[un]focus' will tell the decoder that it has focus. */ + +float(string name, float key, float eventtype, optional float charcode) gecko_keyevent = #490; /* Part of DP_GECKO_SUPPORT + Send a key event to a media decoder. This applies only to interactive decoders like browsers. */ + +void(string name, float x, float y) gecko_mousemove = #491; /* Part of DP_GECKO_SUPPORT + Sets a media decoder shader's mouse position. Values should be 0-1. */ + +void(string name, float w, float h) gecko_resize = #492; /* Part of DP_GECKO_SUPPORT + Request to resize a media decoder. */ + +vector(string name) gecko_get_texture_extent = #493; /* Part of DP_GECKO_SUPPORT + Retrieves a media decoder current image pixel sizes. */ + +string(string shadname, string propname) gecko_getproperty = #0:gecko_getproperty; /* + Queries the media decoder (especially browser ones) for decoder-specific properties. The cef plugin recognises url, title, status. */ + +float(float caseinsensitive, string s, ...) crc16 = #494; /* Part of DP_QC_CRC16*/ +float(string name) cvar_type = #495; /* Part of DP_QC_CVAR_TYPE*/ +float() numentityfields = #496; /* Part of DP_QC_ENTITYDATA + Gives the number of named entity fields. Note that this is not the size of an entity, but rather just the number of unique names (ie: vectors use 4 names rather than 3). */ + +float(string fieldname) findentityfield = #0:findentityfield; /* + Find a field index by name. */ + +typedef .__variant field_t; +field_t(float fieldnum) entityfieldref = #0:entityfieldref; /* + Returns a field value that can be directly used to read entity fields. Be sure to validate the type with entityfieldtype before using. */ + +string(float fieldnum) entityfieldname = #497; /* Part of DP_QC_ENTITYDATA + Retrieves the name of the given entity field. */ + +float(float fieldnum) entityfieldtype = #498; /* Part of DP_QC_ENTITYDATA + Provides information about the type of the field specified by the field num. Returns one of the EV_ values. */ + +string(float fieldnum, entity ent) getentityfieldstring = #499; /* Part of DP_QC_ENTITYDATA*/ +float(float fieldnum, entity ent, string s) putentityfieldstring = #500; /* Part of DP_QC_ENTITYDATA*/ +string(string filename, optional float makereferenced) whichpack = #503; /* Part of DP_QC_WHICHPACK + Returns the pak file name that contains the file specified. progs/player.mdl will generally return something like 'pak0.pak'. If makereferenced is true, clients will automatically be told that the returned package should be pre-downloaded and used, even if allow_download_refpackages is not set. */ + +string(string in) uri_escape = #510; /* Part of DP_QC_URI_ESCAPE*/ +string(string in) uri_unescape = #511; /* Part of DP_QC_URI_ESCAPE*/ +float(entity ent) num_for_edict = #512; +#define uri_post uri_get +float(string uril, float id, optional string postmimetype, optional string postdata) uri_get = #513; /* Part of DP_QC_URI_GET, DP_QC_URI_POST + uri_get() gets content from an URL and calls a callback "uri_get_callback" with it set as string; an unique ID of the transfer is returned + returns 1 on success, and then calls the callback with the ID, 0 or the HTTP status code, and the received data in a string + For a POST request, you will typically want the postmimetype set to application/x-www-form-urlencoded. + For a GET request, omit the mime+data entirely. + Consult your webserver/php/etc documentation for best-practise. */ + +float(string str) tokenize_console = #514; /* + Tokenize a string exactly as the console's tokenizer would do so. The regular tokenize builtin became bastardized for convienient string parsing, which resulted in a large disparity that can be exploited to bypass checks implemented in a naive SV_ParseClientCommand function, therefore you can use this builtin to make sure it exactly matches. */ + +float(float idx) argv_start_index = #515; /* + Returns the character index that the tokenized arg started at. */ + +float(float idx) argv_end_index = #516; /* + Returns the character index that the tokenized arg stopped at. */ + +void(strbuf strbuf, string pattern, string antipattern) buf_cvarlist = #517; +string(string cvarname) cvar_description = #518; /* + Retrieves the description of a cvar, which might be useful for tooltips or help files. This may still not be useful. */ + +float(float v, optional float base) log = #532; /* Part of ??MVDSV_BUILTINS + Determines the logarithm of the input value according to the specified base. This can be used to calculate how much something was shifted by. */ + +float(string sample) soundlength = #534; /* + Provides a way to query the duration of a sound sample, allowing you to set up a timer to chain samples. */ + +float(string filename, strbuf bufhandle) buf_loadfile = #535; /* + Appends the named file into a string buffer (which must have been created in advance). The return value merely says whether the file was readable. */ + +float(filestream filehandle, strbuf bufhandle, optional float startpos, optional float numstrings) buf_writefile = #536; /* + Writes the contents of a string buffer onto the end of the supplied filehandle (you must have already used fopen). Additional optional arguments permit you to constrain the writes to a subsection of the stringbuffer. */ + +void(float dest) setkeydest = #601; +float() getkeydest = #602; +void(float trg) setmousetarget = #603; +float() getmousetarget = #604; +void(.../*, string funcname*/) callfunction = #605; /* + Invokes the named function. The function name is always passed as the last parameter and must always be present. The others are passed to the named function as-is */ + +void(filestream fh, entity e) writetofile = #606; /* + Writes an entity's fields to the named frik_file file handle. */ + +float(string s) isfunction = #607; /* + Returns true if the named function exists and can be called with the callfunction builtin. */ + +vector(float vidmode, optional float forfullscreen) getresolution = #608; /* + Supposed to query the driver for supported video modes. FTE does not query drivers in this way, nor would it trust drivers anyway. */ + +string(float keynum) keynumtostring = #609; /* + Converts a qscancode key number into a mostly-human-readable name, matching the bind command. */ + +string(string command, optional float bindmap) findkeysforcommand = #610; +float(float type) gethostcachevalue = #611; /* Part of FTE_CSQC_SERVERBROWSER*/ +string(float type, float hostnr) gethostcachestring = #612; /* Part of FTE_CSQC_SERVERBROWSER*/ +float(entity e, string s, optional float offset) parseentitydata = #613; /* + Reads a single entity's fields into an already-spawned entity. s should contain field pairs like in a saved game: {"foo1" "bar" "foo2" "5"}. Returns <=0 on failure, otherwise returns the offset in the string that was read to. */ + +string(entity e) generateentitydata = #0:generateentitydata; /* + Dumps the entities fields into a string which can later be parsed with parseentitydata. */ + +float(string key) stringtokeynum = #614; /* + Returns the qscancode of a key from its name. Names are identical to the bind command. ctrl/shift/alt modifiers are ignored. */ + +void() resethostcachemasks = #615; /* Part of FTE_CSQC_SERVERBROWSER*/ +void(float mask, float fld, string str, float op) sethostcachemaskstring = #616; /* Part of FTE_CSQC_SERVERBROWSER*/ +void(float mask, float fld, float num, float op) sethostcachemasknumber = #617; /* Part of FTE_CSQC_SERVERBROWSER*/ +void() resorthostcache = #618; /* Part of FTE_CSQC_SERVERBROWSER*/ +void(float fld, float descending) sethostcachesort = #619; /* Part of FTE_CSQC_SERVERBROWSER*/ +void(optional float dopurge) refreshhostcache = #620; /* Part of FTE_CSQC_SERVERBROWSER*/ +float(float fld, float hostnr) gethostcachenumber = #621; /* Part of FTE_CSQC_SERVERBROWSER*/ +float(string key) gethostcacheindexforkey = #622; /* Part of FTE_CSQC_SERVERBROWSER*/ +void(string key) addwantedhostcachekey = #623; /* Part of FTE_CSQC_SERVERBROWSER*/ +string() getextresponse = #624; /* Part of FTE_CSQC_SERVERBROWSER*/ +string(string dnsname, optional float defport) netaddress_resolve = #625; +string(string fmt, ...) sprintf = #627; /* Part of DP_QC_SPRINTF + 'prints' to a formatted temp-string. Mostly acts as in C, however %d assumes floats (fteqcc has arg checking. Use it.). + type conversions: l=arg is an int, h=arg is a float, and will work as a prefix for any float or int representation. + float representations: d=decimal, e,E=exponent-notation, f,F=floating-point notation, g,G=terse float, c=char code, x,X=hex + other representations: i=int, s=string, S=quoted and marked-up string, v=vector, p=pointer + so %ld will accept an int arg, while %hi will expect a float arg. + entities, fields, and functions will generally need to be printed as ints with %i. */ + +vector() getbindmaps = #631; +float(vector bm) setbindmaps = #632; +string(string digest, string data, ...) digest_hex = #639; +string(string digest, void *data, int length) digest_ptr = #0:digest_ptr; /* + Calculates the digest of a single contiguous block of memory (including nulls) using the specified hash function. */ + +#if defined(CSQC) || defined(MENU) +#define K_TAB 9 +#define K_ENTER 13 +#define K_ESCAPE 27 +#define K_SPACE 32 +#define K_BACKSPACE 127 +#define K_UPARROW 128 +#define K_DOWNARROW 129 +#define K_LEFTARROW 130 +#define K_RIGHTARROW 131 +#define K_LALT 132 +#define K_RALT -245 +#define K_LCTRL 133 +#define K_RCTRL -246 +#define K_LSHIFT 134 +#define K_RSHIFT -247 +#define K_F1 135 +#define K_F2 136 +#define K_F3 137 +#define K_F4 138 +#define K_F5 139 +#define K_F6 140 +#define K_F7 141 +#define K_F8 142 +#define K_F9 143 +#define K_F10 144 +#define K_F11 145 +#define K_F12 146 +#define K_INS 147 +#define K_DEL 148 +#define K_PGDN 149 +#define K_PGUP 150 +#define K_HOME 151 +#define K_END 152 +#define K_KP_HOME 164 +#define K_KP_UPARROW 165 +#define K_KP_PGUP 166 +#define K_KP_LEFTARROW 161 +#define K_KP_5 162 +#define K_KP_RIGHTARROW 163 +#define K_KP_END 158 +#define K_KP_DOWNARROW 159 +#define K_KP_PGDN 160 +#define K_KP_ENTER 172 +#define K_KP_INS 157 +#define K_KP_DEL 167 +#define K_KP_SLASH 168 +#define K_KP_MINUS 170 +#define K_KP_PLUS 171 +#define K_KP_NUMLOCK 154 +#define K_KP_STAR 169 +#define K_KP_EQUALS 173 +#define K_MOUSE1 512 +#define K_MOUSE2 513 +#define K_MOUSE3 514 +#define K_MOUSE4 517 +#define K_MOUSE5 518 +#define K_MOUSE6 519 +#define K_MOUSE7 520 +#define K_MOUSE8 521 +#define K_MOUSE9 522 +#define K_MOUSE10 523 +#define K_MWHEELUP 515 +#define K_MWHEELDOWN 516 +#define K_LWIN -239 +#define K_RWIN -240 +#define K_APP -241 +#define K_SEARCH -242 +#define K_POWER -130 +#define K_VOLUP -243 +#define K_VOLDOWN -244 +#define K_JOY1 768 +#define K_JOY2 769 +#define K_JOY3 770 +#define K_JOY4 771 +#define K_AUX1 784 +#define K_AUX2 785 +#define K_AUX3 786 +#define K_AUX4 787 +#define K_AUX5 788 +#define K_AUX6 789 +#define K_AUX7 790 +#define K_AUX8 791 +#define K_AUX9 792 +#define K_AUX10 793 +#define K_AUX11 794 +#define K_AUX12 795 +#define K_AUX13 796 +#define K_AUX14 797 +#define K_AUX15 798 +#define K_AUX16 799 +#define K_AUX17 800 +#define K_AUX18 801 +#define K_AUX19 802 +#define K_AUX20 803 +#define K_AUX21 804 +#define K_AUX22 805 +#define K_AUX23 806 +#define K_AUX24 807 +#define K_AUX25 808 +#define K_AUX26 809 +#define K_AUX27 810 +#define K_AUX28 811 +#define K_AUX29 812 +#define K_AUX30 813 +#define K_AUX31 814 +#define K_AUX32 815 +#define K_PAUSE 153 +#define K_PRINTSCREEN 174 +#define K_CAPSLOCK 155 +#define K_SCROLLLOCK 156 +#define K_SEMICOLON 59 +#define K_PLUS 43 +#define K_MINUS 45 +#define K_TILDE 126 +#define K_BACKQUOTE 96 +#define K_BACKSLASH 92 +#define K_GP_A 826 +#define K_GP_B 827 +#define K_GP_X 828 +#define K_GP_Y 829 +#define K_GP_LSHOULDER 824 +#define K_GP_RSHOULDER 825 +#define K_GP_LTRIGGER 830 +#define K_GP_RTRIGGER 831 +#define K_GP_BACK 821 +#define K_GP_START 820 +#define K_GP_LTHUMB 822 +#define K_GP_RTHUMB 823 +#define K_GP_DPAD_UP 816 +#define K_GP_DPAD_DOWN 817 +#define K_GP_DPAD_LEFT 818 +#define K_GP_DPAD_RIGHT 819 +#define K_GP_GUIDE -202 +#define K_GP_UNKNOWN -255 +#define K_GP_LTHUMB_UP 832 +#define K_GP_LTHUMB_DOWN 833 +#define K_GP_LTHUMB_LEFT 834 +#define K_GP_LTHUMB_RIGHT 835 +#define K_GP_RTHUMB_UP 836 +#define K_GP_RTHUMB_DOWN 837 +#define K_GP_RTHUMB_LEFT 838 +#define K_GP_RTHUMB_RIGHT 839 +#endif +#ifdef _ACCESSORS +accessor strbuf : float +{ + inline get float asfloat[float idx] = {return stof(bufstr_get(this, idx));}; + inline set float asfloat[float idx] = {bufstr_set(this, idx, ftos(value));}; + get string[float] = bufstr_get; + set string[float] = bufstr_set; + get float length = buf_getsize; +}; +accessor searchhandle : float +{ + get string[float] = search_getfilename; + get float length = search_getsize; +}; +accessor hashtable : float +{ + inline get vector v[string key] = {return hash_get(this, key, '0 0 0', EV_VECTOR);}; + inline set vector v[string key] = {hash_add(this, key, value, HASH_REPLACE|EV_VECTOR);}; + inline get string s[string key] = {return hash_get(this, key, "", EV_STRING);}; + inline set string s[string key] = {hash_add(this, key, value, HASH_REPLACE|EV_STRING);}; + inline get float f[string key] = {return hash_get(this, key, 0.0, EV_FLOAT);}; + inline set float f[string key] = {hash_add(this, key, value, HASH_REPLACE|EV_FLOAT);}; + inline get __variant[string key] = {return hash_get(this, key, __NULL__);}; + inline set __variant[string key] = {hash_add(this, key, value, HASH_REPLACE);}; +}; +accessor infostring : string +{ + get string[string] = infoget; + inline seti& string[string fld] = {this = infoadd(this, fld, value);}; +}; +accessor filestream : float +{ + get string = fgets; + inline set string = {fputs(this,value);}; +}; +#endif +#pragma noref 0 diff --git a/source/menu/main.qc b/source/menu/main.qc new file mode 100644 index 0000000..43640e7 --- /dev/null +++ b/source/menu/main.qc @@ -0,0 +1,116 @@ +float menu_active; +float splash_time; +void() m_open; + +void() m_init = +{ + splash_time = time + 2.5; + registercommand("togglemenu2"); + // drawfont = loadfont("", "Courier Prime Code", "12,16,24,32,48,64,72,128,256,512", -1, 0, 0); + setcursormode(TRUE,"gfx/xhair", [16, 16], cvar("vid_conautoscale")); + current_menu = MENU_MAIN; + m_open(); +}; + +vector() randomofs = { return [random() - 0.5, random() - 0.5] * 2; }; + +void(vector screensize) m_draw = +{ +// clearscene(); + + + vector realsize = getproperty(VF_SCREENPSIZE); + float target_conauto = 2; + if (realsize_y < 600) target_conauto = 1; + else if (realsize_y < 1200) target_conauto = 2; + else target_conauto = 4; + + if (target_conauto != cvar("vid_conautoscale")) localcmd(sprintf("vid_conautoscale %f\n", target_conauto)); + + + sui_begin(screensize_x, screensize_y); + + if (menu_active) + root_menu(screensize); + else { + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_START]); + sui_text([0, 64], MENU_TEXT_LARGE, "NOT ACTIVE.", [1, 1, 1], 1, 0); + } + + + /*if (time < splash_time) + { + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); + float diff = splash_time - time; + float a; + if (diff > 2.5) + { + a = 1 - (diff - 2.5) * 2; + float xstretch = (diff - 2.5) * 4; + sui_fill([0, 0], screensize, '0 0 0', 1, 0); + sui_pic(randomofs() * 1, [screensize_y * (0.7 + xstretch), screensize_y * 0.7], "gfx/splash.tga", '1 1 1', a * 0.75, 1); + sui_pic(randomofs() * 1, [screensize_y * (0.7 + xstretch), screensize_y * 0.7], "gfx/splash.tga", '1 1 1', a * 0.75, 1); + } + else + { + a = diff * 0.6; + sui_fill([0, 0], screensize, '0 0 0', a * 2, 0); + sui_pic(randomofs() * a, [screensize_y * 0.7, screensize_y * 0.7], "gfx/splash.tga", '1 1 1', a, 1); + sui_pic(randomofs() * a, [screensize_y * (0.7 + random() * 0.05), screensize_y * 0.7], "gfx/splash.tga", '1 1 1', a * 0.5, 1); + } + }*/ + + sui_end(); +}; + +void() m_close = +{ + setkeydest(0); + menu_active = FALSE; +}; + +void() m_open = +{ + setkeydest(2); + menu_active = TRUE; +}; + +float(float evtype, float scanx, float chary, float devid) Menu_InputEvent = +{ + float used = sui_input_event(evtype, scanx, chary, devid); + + if (evtype == IE_KEYDOWN && !used) + { + string cmd = getkeybind(scanx); + switch (cmd) + { + case "togglemenu": + m_close(); + return TRUE; + break; + default: break; + } + } + return FALSE; +}; + +float(string cmd) m_consolecommand = +{ + tokenize(cmd); + switch (argv(0)) + { + default: break; + } + + return FALSE; +}; + +void(float wantmode) m_toggle = +{ + if (menu_active) m_close(); + else m_open(); +}; + +void() m_shutdown = +{ +}; \ No newline at end of file diff --git a/source/menu/menu.qc b/source/menu/menu.qc new file mode 100644 index 0000000..8b5045c --- /dev/null +++ b/source/menu/menu.qc @@ -0,0 +1,267 @@ +vector MENU_BG = '0.2 0.3 0.4'; +vector MENU_BG_DARK = '0.1 0.15 0.2'; +vector MENU_BORDER = '0.3 0.4 0.5'; +vector MENU_BUTTON = '0.3 0.4 0.5'; +vector MENU_BUTTON_BORDER = '0.35 0.45 0.55'; +vector MENU_TEXT_1 = '1 1 1'; +vector MENU_TEXT_2 = '0.7 0.75 0.75'; +vector MENU_HIGHLIGHT = '1 1 1'; +vector MENU_DARKEN = '1 1 1'; + +vector MENU_TEXT_SMALL = '8 8 0'; +vector MENU_TEXT_MEDIUM = '16 16 0'; +vector MENU_TEXT_LARGE = '24 24 0'; + +void() input_tester = +{ + float char = 0; + float scan = 0; + string printme = ""; + while (sui_get_input(char, scan)) + { + printme = strcat(printme, chr2str(char)); + } + if (printme != "") printf("INPUT: %s\n", printme); +}; + +void(string id, vector pos, vector size, float maxlen, __inout string text, __inout float cursor) text_input_control = +{ + vector textsize = [size_y - 4, size_y - 4]; + sui_push_frame(pos, size); + vector basecolor = sui_is_hovered(id) ? MENU_BG_DARK + MENU_HIGHLIGHT * 0.08 : MENU_BG_DARK; + sui_fill([0, 0], size, basecolor, 0.6, 0); + + sui_text_input(id, [0, 0], size, text, cursor); + + sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); + float focused = sui_is_last_clicked(id); + // Under focus + focused ? sui_border_box([0, 0], size, 1, MENU_BORDER, 0.6, 0) : 0; + + sui_push_frame([2, 0], [size_x - 4, size_y - 4]); + + float cursorx; + if (stringwidth(text, 1, textsize) > size_x - 4) + { + sui_clip_to_frame(); + cursorx = 0; + sui_set_align([SUI_ALIGN_END, SUI_ALIGN_CENTER]); + sui_text([0, 0], textsize, text, MENU_TEXT_1, 1, 0); + } + else + { + cursorx = stringwidth(substring(text, 0, cursor), 1, textsize); + sui_text([0, 0], textsize, text, MENU_TEXT_1, 1, 0); + } + if (focused) + { + sui_fill([cursorx, 0], [2, textsize_y], MENU_TEXT_1, fabs(sin(time * 4)), 0); + } + sui_reset_clip(); + sui_pop_frame(); + + sui_pop_frame(); +}; + +float(string id, vector pos, vector size, string text) my_button = +{ + sui_push_frame(pos, size); + vector basecolor = sui_is_hovered(id) ? MENU_BUTTON + MENU_HIGHLIGHT * 0.1 : MENU_BUTTON; + basecolor = sui_is_held(id) ? MENU_BUTTON - MENU_DARKEN * 0.1 : basecolor; + sui_fill([0, 0], size, basecolor, 0.6, 0); + sui_border_box([0, 0], size, 1, MENU_BUTTON_BORDER, 0.4, 0); + + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); + sui_text([0, 0], MENU_TEXT_SMALL, text, MENU_TEXT_1, 1, 0); + sui_action_element([0, 0], size, id, sui_noop); + sui_pop_frame(); + + return sui_is_clicked(id); +}; + + +void(string id, vector pos, vector size, vector minmaxsteps, __inout float value) my_slider = +{ + sui_push_frame(pos, size); + + value = sui_slidercontrol(id, [0, 0], size, minmaxsteps, value, sui_slider_noop); + float maxval = minmaxsteps[1]; + float sliderx = (value / maxval) * size_x; + sui_fill([0, size_y * 0.25], [size_x, size_y * 0.5], MENU_BG_DARK, 1.0, 0); + + float is_active = sui_is_held(id) || (sui_is_hovered(id) && !sui_click_held()); + vector slider_ctrl_color = is_active ? MENU_BUTTON + MENU_HIGHLIGHT * 0.1 : MENU_BUTTON; + sui_fill([sliderx - 2, 0], [4, size_y], slider_ctrl_color, 1.0, 0); + + sui_pop_frame(); +}; + +void(vector pos, vector size, vector minmaxsteps, string cvar_s, string name, string format) cvar_slider = +{ + float current = cvar(cvar_s); + float old = current; + sui_push_frame(pos, [size_x, size_y * 0.5 - 4]); + sui_text([0, 0], MENU_TEXT_SMALL, name, MENU_TEXT_1, 1, 0); + sui_set_align([SUI_ALIGN_END, SUI_ALIGN_START]); + sui_text([0, 0], MENU_TEXT_SMALL, sprintf(format, current), MENU_TEXT_1, 1, 0); + sui_pop_frame(); + my_slider(strcat(cvar_s, "sldr"), [pos_x, pos_y + size_y * 0.5], [size_x, size_y * 0.5], minmaxsteps, current); + if (current != old) cvar_set(cvar_s, ftos(current)); +}; + +struct name_command { + string name; + string command; +}; + +name_command bindlist[] = +{ + { "Forward", "+forward" }, + { "Back", "+back" }, + { "Left", "+moveleft" }, + { "Right", "+moveright" }, + { "Jump", "+jump" } +}; + +void(string id, vector pos, vector size, string name, string command) bind_button = +{ + sui_push_frame(pos, size); + sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]); + string key = sui_binder(id, [0, 0], size, name, command); + if (sui_is_hovered(id)) sui_fill([0, 0], size, MENU_HIGHLIGHT, 0.1, 0); + sui_text([6, 0], MENU_TEXT_SMALL, name, MENU_TEXT_1, 1, 0); + sui_set_align([SUI_ALIGN_END, SUI_ALIGN_CENTER]); + sui_text([-6, 0], MENU_TEXT_SMALL, key, MENU_TEXT_1, 1, 0); + + sui_pop_frame(); +}; + + +void(string id, vector pos, vector size, __inout vector scrollofs) bind_list = +{ + sui_fill(pos, size, MENU_BG_DARK, 0.75, 0); + sui_list_view_begin(strcat(id, "scrl"), pos, size, [size_x - 6, 24], bindlist.length, scrollofs, [0, 6]); + vector listitem_pos = '0 0 0'; + for (float index = sui_list_item(listitem_pos); index > -1; index = sui_list_item(listitem_pos)) + { + sui_push_frame(listitem_pos, [size_x - 6, 24]); + bind_button(strcat(id, ftos(index)), [0, 0], [size_x - 6, 24], bindlist[index].name, bindlist[index].command); + sui_pop_frame(); + } + sui_list_view_end(); +}; + + +float current_menu; +const float MENU_MAIN = 1; +const float MENU_SETTINGS = 2; +const float MENU_HELP = 3; + +vector binds_scroll; +void() settings_menu = +{ + vector pos = [0, 0]; + vector size = [360, 280]; + + sui_push_frame(pos, size); + + sui_fill([0, 0], size, MENU_BG, 0.75, 0); + sui_border_box([0, 0], size, 2, MENU_BORDER, 0.3, 0); + + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_START]); + sui_text([0, 4], MENU_TEXT_MEDIUM, "Settings", MENU_TEXT_1, 1, 0); + + + sui_set_align([SUI_ALIGN_START, SUI_ALIGN_START]); + + float xpos = 8; + float ypos = 32; + float width = size_x * 0.5 - 8 * 2; + sui_text([xpos, ypos], MENU_TEXT_SMALL, "Controls", MENU_TEXT_1, 1, 0); + ypos += 16; + bind_list("bindlist", [xpos, ypos], [width, 160], binds_scroll); + ypos += 160 + 8; + + cvar_slider([xpos, ypos], [width, 32], [0.1, 10], "sensitivity", "Sensitivity", "%.2f"); + ypos += 32; + + ypos = 32; + xpos = 8 + width + 8 + 8; + + cvar_slider([xpos, ypos], [width, 32], [0, 1], "volume", "Volume", "%.2f"); + ypos += 32 + 4; + cvar_slider([xpos, ypos], [width, 32], [0, 1], "musicvolume", "Music Volume", "%.2f"); + ypos += 32 + 4 + 8; + + sui_text([xpos, ypos], MENU_TEXT_SMALL, "Video", MENU_TEXT_1, 1, 0); + ypos += 16; + my_button("fs_btn", [xpos, ypos], [width, 20], "Fullscreen") ? localcmd("vid_fullscreen 2; vid_restart\n") : 0; + ypos += 24; + my_button("wn_btn", [xpos, ypos], [width, 20], "Windowed") ? localcmd("vid_fullscreen 0; vid_width 1024; vid_height 768; vid_restart\n") : 0; + ypos += 24; + sui_text([xpos, ypos], MENU_TEXT_SMALL, "Window can be resized.", MENU_TEXT_1, 0.8, 0); + ypos += 16; + sui_set_align([SUI_ALIGN_END, SUI_ALIGN_END]); + my_button("stg_back", [-8, -8], [80, 20], "Back") ? current_menu = MENU_MAIN : 0; + + sui_pop_frame(); +}; + +void() help_menu = +{ + vector pos = [0, 0]; + vector size = [360, 280]; + + sui_push_frame(pos, size); + + sui_fill([0, 0], size, MENU_BG, 0.75, 0); + sui_border_box([0, 0], size, 2, MENU_BORDER, 0.3, 0); + + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_START]); + sui_text([0, 4], MENU_TEXT_MEDIUM, "Help", MENU_TEXT_1, 1, 0); + + float xpos = 0; + float ypos = 32; + sui_text([xpos, ypos], MENU_TEXT_SMALL, "Bunch of Help and About", MENU_TEXT_1, 1, 0); + + sui_set_align([SUI_ALIGN_END, SUI_ALIGN_END]); + my_button("hlp_back", [-8, -8], [80, 20], "Back") ? current_menu = MENU_MAIN : 0; + + sui_pop_frame(); +}; + +void() main_menu = +{ + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_START]); + sui_text([0, 64], MENU_TEXT_LARGE, "Title Screen", [1, 1, 1], 1, 0); + + vector pos = [0, -24]; + vector size = [120, 140]; + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_END]); + sui_push_frame(pos, size); + + sui_fill([0, 0], size, MENU_BG, 0.3, 0); + sui_border_box([0, 0], size, 2, MENU_BORDER, 0.2, 0); + + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_START]); + + my_button("mm_start", [0, 8], [size_x - 16, 20], "Start Game") ? localcmd("map ndu\n") : 0; + my_button("mm_settings", [0, 8 + 24], [size_x - 16, 20], "Settings") ? current_menu = MENU_SETTINGS : 0; + my_button("mm_help", [0, 8 + 48], [size_x - 16, 20], "Help") ? current_menu = MENU_HELP : 0; + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_END]); + my_button("mm_quit", [0, -8], [size_x - 16, 20], "Quit") ? localcmd("quit\n") : 0; + sui_pop_frame(); +}; + +void(vector size) root_menu = +{ + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); + sui_fill([0, 0], size, '0 0 0', 0.5, 0); + switch (current_menu) + { + case MENU_MAIN: main_menu(); break; + case MENU_SETTINGS: settings_menu(); break; + case MENU_HELP: help_menu(); + default: break; + } +}; \ No newline at end of file diff --git a/source/shared/sui_sys.qc b/source/shared/sui_sys.qc new file mode 100644 index 0000000..ed291ff --- /dev/null +++ b/source/shared/sui_sys.qc @@ -0,0 +1,940 @@ +// Shpuld's Simple UI lib - sui +// Created 11/2018 +// +// sui is a simple QuakeC UI lib for drawing and handling game interfaces. +// The API is made simple and easy to build upon, but cuts have been made +// to keep complexity low. +// + + +#ifdef MENU +const float IE_KEYDOWN = 0; /* Specifies that a key was pressed. Second argument is the scan code. Third argument is the unicode (printable) char value. Fourth argument denotes which keyboard(or mouse, if its a mouse 'scan' key) the event came from. Note that some systems may completely separate scan codes and unicode values, with a 0 value for the unspecified argument. */ +const float IE_KEYUP = 1; /* Specifies that a key was released. Arguments are the same as IE_KEYDOWN. On some systems, this may be fired instantly after IE_KEYDOWN was fired. */ +const float IE_MOUSEDELTA = 2; /* Specifies that a mouse was moved (touch screens and tablets typically give IE_MOUSEABS events instead, use _windowed_mouse 0 to test code to cope with either). Second argument is the X displacement, third argument is the Y displacement. Fourth argument is which mouse or touch event triggered the event. */ +const float IE_MOUSEABS = 3; /* Specifies that a mouse cursor or touch event was moved to a specific location relative to the virtual screen space. Second argument is the new X position, third argument is the new Y position. Fourth argument is which mouse or touch event triggered the event. */ +const float IE_ACCELEROMETER = 4; +const float IE_FOCUS = 5; /* Specifies that input focus was given. parama says mouse focus, paramb says keyboard focus. If either are -1, then it is unchanged. */ +const float IE_JOYAXIS = 6; /* Specifies that what value a joystick/controller axis currently specifies. x=axis, y=value. Will be called multiple times, once for each axis of each active controller. */ + +#define printf(x, ...) print(sprintf(x, __VA_ARGS__)) + +#endif +float _sui_draw_initialized; + + +// framing + +// pseudo windowing, sets a new "frame" for whatever we're drawing, instead of +// always using screen [0, 0] as min and [screen_width, screen_height] as max. +// also allows for aligning content to frame start/end/center on both axis + +struct _frame_t { + vector pos; + vector size; + vector align; +}; +const float MAX_FRAMES = 64; +_frame_t _frames[MAX_FRAMES]; +float _frame_index; + +const float SUI_ALIGN_START = 0; +const float SUI_ALIGN_CENTER = 1; +const float SUI_ALIGN_END = 2; + +void() sui_reset_align = +{ + _frames[_frame_index].align = [SUI_ALIGN_START, SUI_ALIGN_START]; +}; + +void(float align) sui_set_x_align = +{ + _frames[_frame_index].align.x = align; +}; + +void(float align) sui_set_y_align = +{ + _frames[_frame_index].align.y = align; +}; + +void(vector align) sui_set_align = +{ + _frames[_frame_index].align = align; +}; + +void(__inout vector point) sui_transform_point = +{ + int idx = _frame_index; + switch (_frames[idx].align.x) + { + case SUI_ALIGN_START: point_x += _frames[idx].pos.x; break; + case SUI_ALIGN_CENTER: point_x += _frames[idx].pos.x + _frames[idx].size.x * 0.5; break; + case SUI_ALIGN_END: point_x += _frames[idx].pos.x + _frames[idx].size.x; break; + default: break; + } + switch (_frames[idx].align.y) + { + case SUI_ALIGN_START: point_y += _frames[idx].pos.y; break; + case SUI_ALIGN_CENTER: point_y += _frames[idx].pos.y + _frames[idx].size.y * 0.5; break; + case SUI_ALIGN_END: point_y += _frames[idx].pos.y + _frames[idx].size.y; break; + default: break; + } +}; + +void(__inout vector point, vector size) sui_transform_box = +{ + int idx = _frame_index; + switch (_frames[idx].align.x) + { + case SUI_ALIGN_START: + point_x += _frames[idx].pos.x; + break; + case SUI_ALIGN_CENTER: + point_x += _frames[idx].pos.x + _frames[idx].size.x * 0.5 - size_x * 0.5; + break; + case SUI_ALIGN_END: + point_x += _frames[idx].pos.x + _frames[idx].size.x - size_x; + break; + default: break; + } + switch (_frames[idx].align.y) + { + case SUI_ALIGN_START: + point_y += _frames[idx].pos.y; + break; + case SUI_ALIGN_CENTER: + point_y += _frames[idx].pos.y + _frames[idx].size.y * 0.5 - size_y * 0.5; + break; + case SUI_ALIGN_END: + point_y += _frames[idx].pos.y + _frames[idx].size.y - size_y; + break; + default: break; + } +}; + +vector() sui_current_frame_pos = +{ + return _frames[_frame_index].pos; +}; + +vector() sui_current_frame_size = +{ + return _frames[_frame_index].size; +}; + +float _sui_is_clipping; +vector _sui_clip_area_mins; +vector _sui_clip_area_maxs; +void() sui_clip_to_frame = +{ + vector pos = _frames[_frame_index].pos; + vector size = _frames[_frame_index].size; + _sui_is_clipping = TRUE; + _sui_clip_area_mins = pos; + _sui_clip_area_maxs = pos + size; + drawsetcliparea(pos.x, pos.y, size.x, size.y); +}; + +void() sui_reset_clip = +{ + _sui_is_clipping = FALSE; + drawresetcliparea(); +}; + +float() sui_is_clipping = +{ + return _sui_is_clipping; +}; + +void(vector pos, vector size) sui_push_frame = +{ + sui_transform_box(pos, size); + + _frame_index += 1; + if (_frame_index >= MAX_FRAMES) + { + printf("^3sui warning: amount of frames = %.0f exceeds MAX_FRAMES = %.0f, consider increasing MAX_FRAMES\n", _frame_index, MAX_FRAMES); + return; + } + + _frames[_frame_index].pos = pos; + _frames[_frame_index].size = size; + _frames[_frame_index].align = [SUI_ALIGN_START, SUI_ALIGN_START]; // TODO allow customizing this +}; + +void() sui_pop_frame = +{ + if (_frame_index > 0) _frame_index -= 1; +}; + +void() sui_reset_frame = +{ + _frame_index = 0; + sui_reset_align(); +}; + + +// actions + +// interaction for sui elements, relies a lot on reading globals to see which +// element id is under cursor or held or whatever, not the most elegant +// solution but in this highly imperative world of QuakeC we can live with it + +float _holding_click; +vector _cursor_click; +vector _cursor_position; +vector _cursor_relative_click; +vector _cursor_relative_hover; +struct _action_element_t { + vector pos; + vector size; + string id; + void(float index, vector click_ratios) action; +}; +const float MAX_ACTION_ELEMENTS = 256; +_action_element_t _action_elements[MAX_ACTION_ELEMENTS]; +float _action_elements_index; + + +// TODO better naming +float(vector point, vector min, vector max) is_2dpoint_in_bounds = +{ + if (point_x <= min_x || point_y <= min_y) return FALSE; + if (point_x > max_x || point_y > max_y) return FALSE; + return TRUE; +}; + +// TODO better naming +float(vector point, vector pos, vector size) is_2dpoint_in_bbox = +{ + return is_2dpoint_in_bounds(point, pos, pos + size); +}; + +void() _action_element_count_sanity = +{ + if (_action_elements_index > MAX_ACTION_ELEMENTS) + { + // let the user know if they're hitting the bounds + printf("^3sui warning: amount of action elements = %.0f exceeds MAX_ACTION_ELEMENTS = %.0f, consider increasing MAX_ACTION_ELEMENTS\n", _action_elements_index, MAX_ACTION_ELEMENTS); + } +}; + +const float MAX_MOUSE_ACTIONS = 16; +string _hover_actions[MAX_MOUSE_ACTIONS]; +string _click_actions[MAX_MOUSE_ACTIONS]; +string _hold_actions[MAX_MOUSE_ACTIONS]; +string _release_actions[MAX_MOUSE_ACTIONS]; +string _last_clicked_actions[MAX_MOUSE_ACTIONS]; + +float _hover_action_count; +float _click_action_count; +float _hold_action_count; +float _release_action_count; +float _last_clicked_action_count; + + +// Resets things you might want to persist normally +void() sui_reset_actions = +{ + _hover_action_count = 0; + _click_action_count = 0; + _hold_action_count = 0; + _release_action_count = 0; + _last_clicked_action_count = 0; + _holding_click = FALSE; +}; + +// Per frame reset? +void() sui_reset_click = +{ + _hold_action_count = 0; + _click_action_count = 0; + _holding_click = FALSE; +}; + +float() sui_click_held = { return _holding_click; }; + + +// click: on mouse1 button down AND button op, once + +// Returns true if id was the topmost click (what usually is cared about the most) +float(string id) sui_is_clicked = +{ + return _click_action_count > 0 && _click_actions[0] == id; +}; + +// Returns the index of the clicked id, -1 if wasn't hit at all. 0 is topmost +float(string id) sui_click_index = +{ + for (int i = 0; i < _click_action_count; i++) + { + if (_click_actions[i] == id) return i; + } + return -1; +}; + + +// hover: mouse is on top of the action element id + +float(string id) sui_is_hovered = +{ + return _hover_action_count > 0 && _hover_actions[0] == id; +}; + +float(string id) sui_hover_index = +{ + for (int i = 0; i < _hover_action_count; i++) + { + if (_hover_actions[i] == id) return i; + } + return -1; +}; + + +// hold: mouse button was clicked on top of this id and is held down, but not necessarily over this id anymore + +float(string id) sui_is_held = +{ + return _hold_action_count > 0 && _hold_actions[0] == id; +}; + +float(string id) sui_hold_index = +{ + for (int i = 0; i < _hold_action_count; i++) + { + if (_hold_actions[i] == id) return i; + } + return -1; +}; + + +// last clicked: is this the last action element that was clicked, good for focusing on input boxes for example + +float(string id) sui_is_last_clicked = +{ + return _last_clicked_action_count > 0 && _last_clicked_actions[0] == id; +}; + +float(string id) sui_last_clicked_index = +{ + for (int i = 0; i < _last_clicked_action_count; i++) + { + if (_last_clicked_actions[i] == id) return i; + } + return -1; +}; + + +// release: a thing was held, but now it was released, once + +float(string id) sui_is_released = +{ + return _release_action_count > 0 && _release_actions[0] == id; +}; + +float(string id) sui_release_index = +{ + for (int i = 0; i < _release_action_count; i++) + { + if (_release_actions[i] == id) return i; + } + return -1; +}; + + +float(float num) mouse_action_sanity = +{ + if (num >= MAX_MOUSE_ACTIONS) + { + printf("^3sui warning: you have exceeded the amount of overlapping action elements with %.0f, MAX_MOUSE_ACTIONS = %.0f\n", num, MAX_MOUSE_ACTIONS); + return TRUE; + } + return FALSE; +}; + +// mouse move, mostly just update hovers + +void(vector pos) _sui_mouse_move = +{ + _cursor_position = pos; + _action_element_count_sanity(); + + // Reset hover, it'll be back to what it used to be before draw gets called if mouse is still on same element + _hover_action_count = 0; + + // Iterate front to back, so topmost element gets the click/hover + for (int i = min(MAX_ACTION_ELEMENTS, _action_elements_index) - 1; i >= 0; i--) + { + if (is_2dpoint_in_bbox(_cursor_position, _action_elements[i].pos, _action_elements[i].size)) + { + if (mouse_action_sanity(_hover_action_count)) break; + + if (_hover_action_count == 0) _cursor_relative_hover = _cursor_position - _action_elements[i].pos; + _hover_actions[_hover_action_count] = _action_elements[i].id; + _hover_action_count += 1; + } + } +}; + +// JERK ALERT: hard to pass input params for it without them just being the globals +// ... so it just straight up uses the globals... optimization +void() _sui_mouse1_down = +{ + // Cheap but it should work... + _cursor_click = _cursor_position; + _cursor_relative_click = _cursor_relative_hover; + for (int i = 0; i < _hover_action_count; i++) _hold_actions[i] = _hover_actions[i]; + _hold_action_count = _hover_action_count; + _holding_click = TRUE; + _last_clicked_action_count = 0; +}; + +void() _sui_mouse1_up = +{ + // Can't be cheap here, we have to get the action fn of the element anyway so.. + _action_element_count_sanity(); + + // Assume we won't hit anything + _click_action_count = 0; + _last_clicked_action_count = 0; + + // Iterate front to back, so topmost element gets the click/hover + for (int i = min(MAX_ACTION_ELEMENTS, _action_elements_index) - 1; i >= 0; i--) + { + // If the thing wasn't the same thing we started pressing down on, ignore + for (int j = 0; j < _hold_action_count; j++) + { + if (_hold_actions[j] == _action_elements[i].id) // yes this element was held + { + // Still in bounds? + if (is_2dpoint_in_bbox(_cursor_position, _action_elements[i].pos, _action_elements[i].size)) + { + if (mouse_action_sanity(_click_action_count)) break; + + // Register click + _click_actions[_click_action_count] = _action_elements[i].id; + _last_clicked_actions[_last_clicked_action_count] = _action_elements[i].id; + _click_action_count += 1; + _last_clicked_action_count += 1; + } + } + } + } + + // In case someone is keeping state on hold and wants to do stuff on release, even if cursor has moved + for (int i = 0; i < _hold_action_count; i++) _release_actions[i] = _hold_actions[i]; + _release_action_count = _hold_action_count; + _hold_action_count = 0; + _holding_click = FALSE; +}; + +void(vector pos, vector size, string id, void(float index, vector click_ratios) action) sui_action_element = +{ + if (!_sui_draw_initialized) + { + print("^1sui error: adding sui elements before sui_pre_draw!\n^1 Always do your sui menus between sui_pre_draw and sui_draw!\n"); + } + if (_action_elements_index >= MAX_ACTION_ELEMENTS) + { + // Silently fail here, sui will let us know another way, increase the count + // so that the error in click/mousemove handlers prints correct numbers. + _action_elements_index += 1; + return; + } + + sui_transform_box(pos, size); + + if (_sui_is_clipping) + { + vector oldpos = pos; + pos_x = max(pos_x, _sui_clip_area_mins_x); + pos_y = max(pos_y, _sui_clip_area_mins_y); + + size -= pos - oldpos; + + size_x -= bound(0, (pos_x + size_x - _sui_clip_area_maxs_x), size_x); + size_y -= bound(0, (pos_y + size_y - _sui_clip_area_maxs_y), size_y); + } + + _action_elements[_action_elements_index].pos = pos; + _action_elements[_action_elements_index].size = size; + _action_elements[_action_elements_index].id = id; + _action_elements[_action_elements_index].action = action; + + _action_elements_index += 1; +}; + + +// Input related stuff + +string _sui_binding_command; +string _sui_binding_command_name; + +struct _input_t { + float char; + float scan; +}; +const float MAX_INPUTS = 64; + +_input_t _input_buffer[MAX_INPUTS]; +float _input_index; +float _input_length; + + +// probably good to use it like while (sui_get_input(char, scan)) { ... }; +float(__inout float char, __inout float scan) sui_get_input = +{ + if (_input_index >= _input_length) return FALSE; + + char = _input_buffer[_input_index].char; + scan = _input_buffer[_input_index].scan; + _input_index++; + + return TRUE; +}; + +// if 2 controls want to read the same input for some reason.. +void() sui_reread_input = +{ + _input_index = 0; +}; + +void() sui_clear_input = +{ + _input_length = 0; + _input_index = 0; +}; + +float(float char, float scan) _sui_add_input = +{ + // TODO check if input was listened, return FALSE if not + if (_input_length >= MAX_INPUTS) + { + printf("^3sui warning: exceeded amount of per frame inputs count MAX_INPUTS = %.0f\n" + "^3 - make sure sui_input_event isn't being called without sui_draw being called in update loop\n" + "^3 - consider increasing MAX_INPUTS\n", MAX_INPUTS); + return TRUE; + } + _input_buffer[_input_length].char = char; + _input_buffer[_input_length].scan = scan; + _input_length += 1; + return TRUE; +}; + +// Listen to a certain keycode if it was pressed, this way sui know it was requested +float(float keycode) sui_listen_keycode_down = +{ + return FALSE; +}; + +// all text that was input between last and current frame +string() sui_listen_text_input = +{ + return ""; +}; + +void(float char, float scan, __inout string text, __inout float cursor) sui_handle_text_input = +{ + float maxlen = 128; + + string prev = text; + string pre_cursor, post_cursor; + float length = strlen(prev); + if (char > 31 && char < 128) //an actual input + { + if (length >= maxlen) return; + pre_cursor = substring(prev, 0, cursor); + post_cursor = substring(prev, cursor, length); + + text = sprintf("%s%s%s", pre_cursor, chr2str(char), post_cursor); + cursor += 1; + } + else if (char == 8) // backspace + { + if (cursor <= 0) return; + pre_cursor = substring(prev, 0, cursor - 1); + post_cursor = substring(prev, cursor, length); + cursor -= 1; + cursor = max(0, cursor); + text = strcat(pre_cursor, post_cursor); + } + else if (scan == K_DEL) + { + if (cursor >= length) return; + pre_cursor = substring(prev, 0, cursor); + post_cursor = substring(prev, cursor + 1, length); + text = strcat(pre_cursor, post_cursor); + } + else if (char == 13 || char == 27) // enter or escape + { + // Commit and deselect... + // Let's try a hack.. + _last_clicked_action_count = 0; + } + else if (scan == K_LEFTARROW) + { + cursor -= 1; + cursor = max(0, cursor); + } + else if (scan == K_RIGHTARROW) + { + cursor += 1; + cursor = min(strlen(prev), cursor); + } +}; + +void(float maxlen, __inout string text, __inout float cursor) sui_cap_input_length = +{ + if (strlen(text) > maxlen) + { + text = substring(text, 0, strlen(text)); + cursor = strlen(text); + } +}; + +void(string command) _sui_unbind = +{ + tokenize(findkeysforcommand(command)); + string keyname = keynumtostring(stof(argv(0))); + string altkeyname = keynumtostring(stof(argv(1))); + localcmd(sprintf("unbind %s\n", keyname)); + localcmd(sprintf("unbind %s\n", altkeyname)); +}; + +void(float scan, string command) _sui_do_keybind = +{ + if (scan == K_ESCAPE) + { + _sui_binding_command = ""; + _sui_binding_command_name = ""; + return; + } + if (scan == K_BACKSPACE) + { + _sui_unbind(command); + _sui_binding_command = ""; + _sui_binding_command_name = ""; + return; + } + string keyname = keynumtostring(scan); + _sui_unbind(command); + localcmd(sprintf("bind %s %s\n", keyname, command)); + _sui_binding_command = ""; + _sui_binding_command_name = ""; +}; + +void(string command, string command_name) sui_start_bind = +{ + _sui_binding_command = command; + _sui_binding_command_name = command_name; +}; + +// void(float evtype, float scanx, float chary, float devid) sui_input_event +// same args is CSQC_InputEvent. +// return value tells you if sui used the event or not, in case you want to +// not let engine handle it if it was used. +// Sets all the internal sui action stuff, call it in CSQC_InputEvent +float(float evtype, float scanx, float chary, float devid) sui_input_event = +{ + switch (evtype) + { + case IE_MOUSEABS: + _sui_mouse_move([scanx, chary]); + return TRUE; + break; + case IE_MOUSEDELTA: + // Big question mark... + // maybe make our own delta based sui_cursor here.. + // maybe just ignore delta and let user fake mouseabs with their own + // delta cursor by passing different params to this func...? + // for MVP let's just use mouseabs only + return FALSE; + break; + case IE_KEYDOWN: + if (_sui_binding_command != "") + { + // Nothing + return TRUE; + } + else if (scanx == K_MOUSE1) + { + _sui_mouse1_down(); + return TRUE; + } + else + { + if ((scanx == K_ESCAPE || scanx == K_BACKSPACE) && _sui_binding_command != "") + return TRUE; + else if (scanx == K_ESCAPE) + return FALSE; + return _sui_add_input(chary, scanx); + } + break; + case IE_KEYUP: + if (_sui_binding_command != "") + { + _sui_do_keybind(scanx, _sui_binding_command); + return TRUE; + } + else if (scanx == K_MOUSE1) + { + _sui_mouse1_up(); + return TRUE; + } + break; + default: + break; + } + + return FALSE; +}; + + +// void() sui_pre_draw +// Resets state for sui actions so that no trouble happens. +// Call it before your menu code per frame in your draw/updateview. +void(float width, float height) sui_begin = +{ + _action_elements_index = 0; + _sui_draw_initialized = TRUE; + + sui_reset_frame(); + sui_push_frame([0, 0], [width, height]); +} + +void() sui_draw_bind_overlay; + +// void() sui_end +// Call after your menu code per frame in your draw/updateview. +void() sui_end = +{ + // Todo: move overlay drawing elsewhere: + sui_draw_bind_overlay(); + // Dirty part: + _sui_draw_initialized = FALSE; + // reset "once" type actions + _click_action_count = 0; + _release_action_count = 0; + // empty input buffer + sui_clear_input(); +}; + + +// Different draw components: + +void(vector pos, vector size, vector color, float alpha, float flags) sui_fill = +{ + sui_transform_box(pos, size); + + drawfill(pos, size, color, alpha, flags); +}; + +void(vector pos, vector size, string pic, vector color, float alpha, float flags) sui_pic = +{ + sui_transform_box(pos, size); + + drawpic(pos, pic, size, color, alpha, flags); +}; + +void(vector pos, vector size, float width, vector color, float alpha, float flags) sui_border_box = +{ + sui_transform_box(pos, size); + + // Top line + drawfill(pos, [size_x, width], color, alpha, flags); + // Bottom line + drawfill([pos_x, pos_y + size_y - width], [size_x, width], color, alpha, flags); + // Left line + drawfill([pos_x, pos_y + width], [width, size_y - width * 2], color, alpha, flags); + // Right line + drawfill([pos_x + size_x - width, pos_y + width], [width, size_y - width * 2], color, alpha, flags); +}; + + +void(vector pos, vector size, string text, vector color, float alpha, float flags) sui_text = +{ + sui_transform_box(pos, [stringwidth(text, 1, size), size_y]); + + drawstring(pos, text, size, color, alpha, flags); +}; + +void(float index, vector click_ratios) sui_noop = {}; + +void(float value) sui_slider_noop = {}; + +float(string id, vector pos, vector size, vector minmaxsteps, float value, void(float value) action) sui_slidercontrol = +{ + sui_action_element(pos, size, id, sui_noop); + float newvalue = value; + + sui_transform_box(pos, size); + // user is clicking and holding the slider + if (sui_is_held(id)) + { + float min = minmaxsteps[0]; + float max = minmaxsteps[1]; + float steps = minmaxsteps[2]; + float click_ratio = (_cursor_position_x - pos_x) / size_x; + click_ratio = bound(0, click_ratio, 1); + if (steps > 0) click_ratio = rint(click_ratio * steps) / steps; + newvalue = min + click_ratio * (max - min); + if (newvalue != value) action(newvalue); + } + return newvalue; +}; + +void(string id, vector pos, vector size, __inout string text, __inout float cursor) sui_text_input = +{ + sui_action_element(pos, size, id, sui_noop); + if (sui_is_clicked(id)) cursor = strlen(text); + if (sui_is_last_clicked(id)) + { + float char = 0; + float scan = 0; + while(sui_get_input(char, scan)) sui_handle_text_input(char, scan, text, cursor); + } +}; + + +void(string id, vector size, vector contentsize, __inout vector offset, vector scrollbar_widths) sui_scrollbar = +{ + vector maxoffset = contentsize - size; + maxoffset_x = max(0, maxoffset_x); + maxoffset_y = max(0, maxoffset_y); + sui_push_frame([0, 0], size); + float ofs; + float length; + vector barpos, barsize; + float scan = 0; + float char = 0; + string barname; + if (maxoffset_y > 0 && contentsize_y > 0) + { + sui_set_align([SUI_ALIGN_END, SUI_ALIGN_START]); + sui_push_frame([0, 0], [scrollbar_widths_y, size_y]); + ofs = (offset_y / contentsize_y) * size_y; + length = (size_y / contentsize_y) * size_y; + barpos = [0, ofs]; + barsize = [scrollbar_widths_y, length]; + barname = strcat(id, "vbar"); + + if (sui_is_held(barname)) + { + vector anchor = barpos + _cursor_relative_click; + sui_transform_point(anchor); + float diff = _cursor_position_y - anchor_y; + offset_y += (diff * contentsize_y) / size_y; // * contentsize_y; // (size_y / contentsize_y); + } + + sui_fill(barpos, barsize, '0.1 0.1 0.1' * (1 - sui_is_hovered(barname)), 0.66, 0); + sui_action_element(barpos, barsize, barname, sui_noop); + sui_pop_frame(); + } + sui_pop_frame(); +}; + +void(string id, vector pos, vector size, vector contentsize, __inout vector offset, vector scrollbar_widths) sui_scroll_view_begin = +{ + // make space for scrollbars + sui_push_frame(pos, size - [scrollbar_widths_y, scrollbar_widths_x]); + sui_action_element([0, 0], size, id, sui_noop); + + if (sui_hover_index(id) > -1) + { + float scrollamount = 0; + float char = 0; + float scan = 0; + sui_reread_input(); + while (sui_get_input(char, scan)) + { + if (scan == K_MWHEELUP) scrollamount -= 20; + if (scan == K_MWHEELDOWN) scrollamount += 20; + } + offset_y += scrollamount; + } + + vector maxoffset = contentsize - size; + maxoffset_x = max(0, maxoffset_x); + maxoffset_y = max(0, maxoffset_y); + offset_x = bound(0, offset_x, maxoffset_x); + offset_y = bound(0, offset_y, maxoffset_y); + + sui_scrollbar(id, size, contentsize, offset, scrollbar_widths); + + offset_x = bound(0, offset_x, maxoffset_x); + offset_y = bound(0, offset_y, maxoffset_y); + + sui_clip_to_frame(); + + + sui_push_frame(-1 * offset, contentsize); +}; + +void() sui_scroll_view_end = +{ + sui_pop_frame(); + sui_reset_clip(); + sui_pop_frame(); +}; + +float _sui_list_item_height; +float _sui_list_first; +float _sui_list_last; +float _sui_list_pos; +int _sui_list_index; +void(string id, vector pos, vector size, vector itemsize, float numitems, __inout vector offset, vector scrollbar_widths) sui_list_view_begin = +{ + vector contentsize = [itemsize_x, itemsize_y * numitems]; + sui_scroll_view_begin(id, pos, size, contentsize, offset, scrollbar_widths); + + _sui_list_item_height = itemsize_y; + float hidden_above = floor(offset_y / itemsize_y); + _sui_list_first = max(0, hidden_above); // Index of first elem + _sui_list_last = min(_sui_list_first + rint(size_y / itemsize_y) + 1, numitems); + _sui_list_pos = hidden_above * itemsize_y; + _sui_list_index = _sui_list_first; +}; + +float(__inout vector pos) sui_list_item = +{ + if (_sui_list_index >= _sui_list_last) return -1; + pos = _sui_list_index * [0, _sui_list_item_height]; + _sui_list_index += 1; + return _sui_list_index - 1; +}; + +void() sui_list_view_end = +{ + sui_scroll_view_end(); +}; + +string(string id, vector pos, vector size, string name, string command) sui_binder = +{ + sui_action_element(pos, size, id, sui_noop); + if (sui_is_released(id)) + { + sui_start_bind(command, name); + } + + tokenize(findkeysforcommand(command)); + string keyname = keynumtostring(stof(argv(0))); + if (keyname == "01") keyname = "unbound"; + + return keyname; +}; + +void() sui_draw_bind_overlay = +{ + if (_sui_binding_command != "") + { + vector size = sui_current_frame_size(); + sui_fill([0, 0], size, '0 0 0', 0.5, 0); + sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]); + float textsize = 16; + sui_text([0, -16], [textsize, textsize], "Press a key for", '1 1 1', 1, 0); + sui_text([0, 0], [textsize, textsize], sprintf("'%s'", _sui_binding_command_name), '1 1 1', 1, 0); + sui_text([0, 16], [textsize - 4, textsize - 4], "ESC to cancel, BACKSPACE to remove", '1 1 1', 1, 0); + } +}; + + +// -------------------- END OF SUI SYSTEM STUFF -------------------- \ No newline at end of file diff --git a/tools/qc-compiler-lin.sh b/tools/qc-compiler-lin.sh index 4570ab8..6768843 100755 --- a/tools/qc-compiler-lin.sh +++ b/tools/qc-compiler-lin.sh @@ -18,6 +18,12 @@ echo "" ./fteqcc-cli-lin -srcfile ../progs/fte-server.src echo "" echo "====================" +echo "compiling FTE MENUQC" +echo "====================" +echo "" +./fteqcc-cli-lin -srcfile ../progs/fte-menu.src +echo "" +echo "====================" echo " compiling PSP QC " echo "====================" echo "" diff --git a/tools/qc-compiler-win.bat b/tools/qc-compiler-win.bat index 8ae6eef..9e19540 100644 --- a/tools/qc-compiler-win.bat +++ b/tools/qc-compiler-win.bat @@ -20,6 +20,12 @@ echo. fteqcc-cli-win.exe -srcfile ../progs/fte-server.src echo. echo ==================== +echo compiling FTE MENUQC +echo ==================== +echo. +fteqcc-cli-win.exe -srcfile ../progs/fte-menu.src +echo. +echo ==================== echo compiling PSP QC echo ==================== echo.