CL_UpdateViewModel();
// when csqc is loaded, it will call this in CSQC_UpdateView
- if (!CLVM_prog->loaded)
+ if (!CLVM_prog->loaded || CLVM_prog->flag & PRVM_CSQC_SIMPLE)
{
// clear the CL_Mesh_Scene() used for some engine effects
CL_MeshEntities_Scene_Clear();
// if CSQC is loaded, it is required to provide the CSQC_UpdateView function,
// and won't render a view if it does not call that.
- if (CLVM_prog->loaded)
+ if (CLVM_prog->loaded && !(CLVM_prog->flag & PRVM_CSQC_SIMPLE))
CL_VM_UpdateView(r_stereo_side ? 0.0 : max(0.0, cl.time - cl.oldtime));
else
{
SCR_DrawTurtle ();
SCR_DrawPause ();
if (!r_letterbox.value)
+ {
Sbar_Draw();
+ if (CLVM_prog->loaded && CLVM_prog->flag & PRVM_CSQC_SIMPLE)
+ CL_VM_DrawHud(r_stereo_side ? 0.0 : max(0.0, cl.time - cl.oldtime));
+ }
SHOWLMP_drawall();
SCR_CheckDrawCenterString();
}
PRVM_clientglobalfloat(trace_networkentity) = 0;
}
-//[515]: these are required funcs
-static const char *cl_required_func[] =
-{
- "CSQC_Init",
- "CSQC_InputEvent",
- "CSQC_UpdateView",
- "CSQC_ConsoleCommand",
-};
-static int cl_numrequiredfunc = sizeof(cl_required_func) / sizeof(char*);
+/** Previous DP versions declined to load csprogs if it lacked any of:
+ * CSQC_Init, CSQC_InputEvent, CSQC_UpdateView, CSQC_ConsoleCommand
+ * whereas in FTE and QSS-based engines the minimum is either CSQC_UpdateView
+ * or CSQC_DrawHud (only called in CSQC_SIMPLE aka hud-only mode)
+ * and the other funcs are optional, so we now behave the same here.
+ */
+static void CL_CheckRequiredFuncs(prvm_prog_t *prog, const char *filename)
+{
+ if (PRVM_ED_FindFunction(prog, "CSQC_UpdateView"))
+ return;
+ else if (PRVM_ED_FindFunction(prog, "CSQC_DrawHud"))
+ prog->flag |= PRVM_CSQC_SIMPLE;
+ else
+ prog->error_cmd("%s: no CSQC_UpdateView (EXT_CSQC) or CSQC_DrawHud (CSQC_SIMPLE) function found in %s", prog->name, filename);
+}
#define CL_REQFIELDS (sizeof(cl_reqfields) / sizeof(prvm_required_field_t))
return true;
}
+void CL_VM_DrawHud(double frametime)
+{
+ prvm_prog_t *prog = CLVM_prog;
+
+ R_TimeReport("pre-DrawHud");
+
+ PRVM_clientglobalfloat(time) = cl.time;
+ PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity];
+ CSQC_SetGlobals(frametime);
+
+ VectorSet(PRVM_G_VECTOR(OFS_PARM0), vid_conwidth.integer, vid_conheight.integer, 0);
+ PRVM_G_FLOAT(OFS_PARM1) = sb_showscores;
+ prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_DrawHud), "QC function CSQC_DrawHud is missing");
+
+ if (PRVM_clientfunction(CSQC_DrawScores))
+ {
+ VectorSet(PRVM_G_VECTOR(OFS_PARM0), vid_conwidth.integer, vid_conheight.integer, 0);
+ PRVM_G_FLOAT(OFS_PARM1) = sb_showscores;
+ if (key_dest != key_menu)
+ prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_DrawScores), "QC function CSQC_DrawScores is missing");
+ }
+ else if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
+ if (!cl.islocalgame) // LadyHavoc: changed to draw the deathmatch overlays in any multiplayer mode
+ Sbar_DeathmatchOverlay ();
+
+ R_TimeReport("DrawHud");
+}
+
+
qbool CL_VM_ConsoleCommand(const char *text, size_t textlen)
{
prvm_prog_t *prog = CLVM_prog;
prog->error_cmd = Host_Error;
prog->ExecuteProgram = CLVM_ExecuteProgram;
- PRVM_Prog_Load(prog, csprogsfn, csprogsdata, csprogsdatasize, cl_numrequiredfunc, cl_required_func, CL_REQFIELDS, cl_reqfields, CL_REQGLOBALS, cl_reqglobals);
+ PRVM_Prog_Load(prog, csprogsfn, csprogsdata, csprogsdatasize, CL_CheckRequiredFuncs, CL_REQFIELDS, cl_reqfields, CL_REQGLOBALS, cl_reqglobals);
if (!prog->loaded)
{
VectorCopy(cl.world.maxs, PRVM_clientedictvector(prog->edicts, maxs));
VectorCopy(cl.world.mins, PRVM_clientedictvector(prog->edicts, absmin));
VectorCopy(cl.world.maxs, PRVM_clientedictvector(prog->edicts, absmax));
+ PRVM_clientedictfloat(prog->edicts, solid) = SOLID_BSP;
+ PRVM_clientedictfloat(prog->edicts, modelindex) = 1;
+ PRVM_clientedictfloat(prog->edicts, model) = PRVM_SetEngineString(prog, cl.worldmodel->name);
- // call the prog init
- prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Init), "QC function CSQC_Init is missing");
+ // call the prog init if it exists
+ if (PRVM_clientfunction(CSQC_Init))
+ {
+ PRVM_G_FLOAT(OFS_PARM0) = 1.0f; // CSQC_SIMPLE engines always pass 0, FTE always passes 1
+ PRVM_G_INT(OFS_PARM1) = PRVM_SetEngineString(prog, gamename);
+ PRVM_G_FLOAT(OFS_PARM2) = 1.0f; // TODO DP versions...
+ prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Init), "QC function CSQC_Init is missing");
+ }
// Once CSQC_Init was called, we consider csqc code fully initialized.
prog->inittime = host.realtime;
float trace_inwater;
//
-// required prog functions
+// prog functions called by engine
//
-void() CSQC_Init;
-void() CSQC_Shutdown;
-float(float f, float t, float n) CSQC_InputEvent;
-void(float w, float h) CSQC_UpdateView;
-float(string s) CSQC_ConsoleCommand;
+void CSQC_Init(float apilevel, string enginename, float engineversion);
+void CSQC_Shutdown();
+float CSQC_InputEvent(float evtype, float scanx, float chary);
+void CSQC_UpdateView(float vid_width, float vid_height, float notmenu); // required for EXT_CSQC (preferred)
+float CSQC_ConsoleCommand(string cmdstr);
+#ifdef CSQC_SIMPLE // hud-only CSQC
+ void CSQC_DrawHud(vector virtsize, float showscores); // required for CSQC_SIMPLE (fallback)
+ void CSQC_DrawScores(vector virtsize, float showscores);
+#endif
//these fields are read and set by the default player physics
vector pmove_org;
//============================================================================
// Menu prog handling
-static const char *m_required_func[] = {
-"m_init",
-"m_keydown",
-"m_draw",
-"m_toggle",
-"m_shutdown",
-};
+static void MP_CheckRequiredFuncs(prvm_prog_t *prog, const char *filename)
+{
+ int i;
+ const char *m_required_func[] = {
+ "m_init",
+ "m_keydown",
+ "m_draw",
+ "m_toggle",
+ "m_shutdown",
+ };
+ int m_numrequiredfunc = sizeof(m_required_func) / sizeof(char*);
-static int m_numrequiredfunc = sizeof(m_required_func) / sizeof(char*);
+ for(i = 0; i < m_numrequiredfunc; ++i)
+ if(PRVM_ED_FindFunction(prog, m_required_func[i]) == 0)
+ prog->error_cmd("%s: %s not found in %s",prog->name, m_required_func[i], filename);
+}
static prvm_required_field_t m_required_fields[] =
{
// allocate the mempools
prog->progs_mempool = Mem_AllocPool(menu_progs.string, 0, NULL);
- PRVM_Prog_Load(prog, menu_progs.string, NULL, 0, m_numrequiredfunc, m_required_func, m_numrequiredfields, m_required_fields, m_numrequiredglobals, m_required_globals);
+ PRVM_Prog_Load(prog, menu_progs.string, NULL, 0, MP_CheckRequiredFuncs, m_numrequiredfields, m_required_fields, m_numrequiredglobals, m_required_globals);
// note: OP_STATE is not supported by menu qc, we don't even try to detect
// it here
#endif
//============================================================================
-#define PRVM_OP_STATE 1
+// prog->flag
+#define PRVM_OP_STATE 1
+#define PRVM_CSQC_SIMPLE 2
#ifdef DP_SMALLMEMORY
#define PRVM_MAX_STACK_DEPTH 128
const char *name; // [INIT]
// flag - used to store general flags like PRVM_GE_SELF, etc.
- int flag;
+ unsigned flag;
const char **extensionstring; // [INIT]
*/
// Load expects to be called right after Reset
void PRVM_Prog_Init(prvm_prog_t *prog, struct cmd_state_s *cmd);
-void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data, int64_t size, int numrequiredfunc, const char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, prvm_required_field_t *required_global);
+void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data, fs_offset_t size, void CheckRequiredFuncs(prvm_prog_t *prog, const char *filename), int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, prvm_required_field_t *required_global);
void PRVM_Prog_Reset(prvm_prog_t *prog);
void PRVM_StackTrace(prvm_prog_t *prog);
===============
*/
static void PRVM_UpdateBreakpoints(prvm_prog_t *prog);
-void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * data, fs_offset_t size, int numrequiredfunc, const char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, prvm_required_field_t *required_global)
+void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data, fs_offset_t size, void CheckRequiredFuncs(prvm_prog_t *prog, const char *filename), int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, prvm_required_field_t *required_global)
{
int i;
dprograms_t *dprograms;
Mem_Free(dprograms);
dprograms = NULL;
- // check required functions
- for(i=0 ; i < numrequiredfunc ; i++)
- if(PRVM_ED_FindFunction(prog, required_func[i]) == 0)
- prog->error_cmd("%s: %s not found in %s",prog->name, required_func[i], filename);
+ prog->flag = 0;
+ // expected to not return (call prog->error_cmd) if checks fail
+ CheckRequiredFuncs(prog, filename);
PRVM_LoadLNO(prog, filename);
// set flags & mdef_ts in prog
- prog->flag = 0;
-
PRVM_FindOffsets(prog);
prog->init_cmd(prog);
PRVM_DECLARE_clientfunction(CSQC_Parse_TempEntity)
PRVM_DECLARE_clientfunction(CSQC_Shutdown)
PRVM_DECLARE_clientfunction(CSQC_UpdateView)
+PRVM_DECLARE_clientfunction(CSQC_DrawHud)
+PRVM_DECLARE_clientfunction(CSQC_DrawScores)
PRVM_DECLARE_clientfunction(GameCommand)
PRVM_DECLARE_clientfunction(URI_Get_Callback)
PRVM_DECLARE_clientglobaledict(other)
PRVM_DECLARE_function(CSQC_Parse_TempEntity)
PRVM_DECLARE_function(CSQC_Shutdown)
PRVM_DECLARE_function(CSQC_UpdateView)
+PRVM_DECLARE_function(CSQC_DrawHud)
+PRVM_DECLARE_function(CSQC_DrawScores)
PRVM_DECLARE_function(ClientConnect)
PRVM_DECLARE_function(ClientDisconnect)
PRVM_DECLARE_function(ClientKill)
struct prvm_prog_s;
void R_UpdateFog(void);
qbool CL_VM_UpdateView(double frametime);
+void CL_VM_DrawHud(double frametime);
void SCR_DrawConsole(void);
void R_Shadow_EditLights_DrawSelectedLightProperties(void);
void R_DecalSystem_Reset(decalsystem_t *decalsystem);
cvar_t crosshair_size = {CF_CLIENT | CF_ARCHIVE, "crosshair_size", "1", "adjusts size of the crosshair on the screen"};
static void Sbar_MiniDeathmatchOverlay (int x, int y);
-static void Sbar_DeathmatchOverlay (void);
static void Sbar_IntermissionOverlay (void);
static void Sbar_FinaleOverlay (void);
Cvar_RegisterVariable(&sbar_miniscoreboard_size);
Cvar_RegisterVariable(&sbar_info_pos);
Cvar_RegisterVariable(&cl_deathscoreboard);
+ // This name is used by QuakeSpasm-based engines and is read by the Alkaline 1.2 CSQC
+ Cvar_RegisterVirtual(&sbar_alpha_bg, "scr_sbaralpha");
Cvar_RegisterVariable(&crosshair_color_red);
Cvar_RegisterVariable(&crosshair_color_green);
int Sbar_GetSortedPlayerIndex (int index);
void Sbar_SortFrags (void);
+extern cvar_t cl_deathscoreboard;
+void Sbar_DeathmatchOverlay (void);
+
#endif
"SVC_PARTICLE"
};
-#define SV_REQFUNCS 0
-#define sv_reqfuncs NULL
-//#define SV_REQFUNCS (sizeof(sv_reqfuncs) / sizeof(const char *))
-//static const char *sv_reqfuncs[] = {
-//};
+static void SV_CheckRequiredFuncs(prvm_prog_t *prog, const char *filename)
+{
+ // no required funcs?!
+}
#define SV_REQFIELDS (sizeof(sv_reqfields) / sizeof(prvm_required_field_t))
prog->error_cmd = Host_Error;
prog->ExecuteProgram = SVVM_ExecuteProgram;
- PRVM_Prog_Load(prog, sv_progs.string, NULL, 0, SV_REQFUNCS, sv_reqfuncs, SV_REQFIELDS, sv_reqfields, SV_REQGLOBALS, sv_reqglobals);
+ PRVM_Prog_Load(prog, sv_progs.string, NULL, 0, SV_CheckRequiredFuncs, SV_REQFIELDS, sv_reqfields, SV_REQGLOBALS, sv_reqglobals);
// some mods compiled with scrambling compilers lack certain critical
// global names and field names such as "self" and "time" and "nextthink"