From bfe545222e16a8a13fd84dbdf4c4d8107c450324 Mon Sep 17 00:00:00 2001 From: Spoike Date: Sun, 29 Dec 2013 22:48:28 +0000 Subject: [PATCH] added con_textsize to resize console separately from everything else. qcc: added support for variable arguments via the va_arg intrinsic. qcc: fix up some comment/whitespace issues with the preprocessor. random hacks to try to improve dp compatibility a little. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4573 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/cl_ents.c | 13 ++ engine/client/cl_input.c | 21 ++- engine/client/cl_parse.c | 8 +- engine/client/cl_plugin.inc | 8 +- engine/client/cl_screen.c | 29 +++- engine/client/cl_tent.c | 2 +- engine/client/clhl_game.c | 173 ++++++++++++++---- engine/client/client.h | 1 + engine/client/console.c | 36 ++-- engine/client/keys.c | 10 +- engine/client/keys.h | 2 +- engine/client/m_items.c | 4 +- engine/client/m_single.c | 6 +- engine/client/merged.h | 1 + engine/client/net_master.c | 3 + engine/client/p_classic.c | 2 +- engine/client/p_null.c | 2 +- engine/client/p_script.c | 37 ++-- engine/client/pr_csqc.c | 120 +++++++++++-- engine/client/pr_menu.c | 150 ++++++++++++++-- engine/client/r_2d.c | 79 ++++++--- engine/client/r_surf.c | 70 +++++++- engine/client/render.h | 7 +- engine/client/renderer.c | 10 +- engine/client/sbar.c | 44 ++--- engine/client/screen.h | 5 +- engine/client/snd_dma.c | 9 +- engine/client/spritegn.h | 19 +- engine/client/sys_win.c | 21 ++- engine/client/textedit.c | 12 +- engine/client/view.c | 24 +-- engine/common/bothdefs.h | 4 +- engine/common/bspfile.h | 14 +- engine/common/cmd.c | 2 +- engine/common/common.c | 27 ++- engine/common/console.h | 2 - engine/common/fs.c | 2 +- engine/common/gl_q2bsp.c | 2 +- engine/common/particles.h | 2 +- engine/common/pmovetst.c | 5 + engine/common/pr_bgcmd.c | 63 ++++++- engine/common/pr_common.h | 5 + engine/d3d/d3d11_backend.c | 5 +- engine/dotnet2005/ftequake.vcproj | 2 +- engine/gl/gl_backend.c | 74 ++++---- engine/gl/gl_font.c | 23 +-- engine/gl/gl_hlmdl.c | 18 +- engine/gl/gl_model.c | 66 +++++-- engine/gl/gl_model.h | 9 +- engine/gl/gl_rmain.c | 130 +++++++++----- engine/gl/gl_rmisc.c | 125 +++++++------ engine/gl/gl_screen.c | 2 + engine/gl/gl_shader.c | 18 +- engine/gl/model_hl.h | 2 + engine/qclib/pr_exec.c | 9 +- engine/qclib/pr_multi.c | 51 ++++-- engine/qclib/progsint.h | 2 +- engine/qclib/progslib.h | 2 +- engine/qclib/qcc.h | 16 +- engine/qclib/qcc_cmdlib.c | 27 ++- engine/qclib/qcc_pr_comp.c | 280 +++++++++++++++++++++++------- engine/qclib/qcc_pr_lex.c | 190 ++++++++++++++------ engine/qclib/qccmain.c | 15 +- engine/server/net_preparse.c | 35 ++-- engine/server/pr_cmds.c | 107 ++++-------- engine/server/progdefs.h | 3 +- engine/server/sv_init.c | 199 ++++++++++++--------- engine/server/sv_main.c | 9 +- engine/server/sv_phys.c | 99 ++++++++++- engine/server/sv_user.c | 1 + engine/server/svhl_game.c | 200 +++++++++++++++++---- engine/server/svhl_gcapi.h | 6 +- engine/server/svhl_phys.c | 80 +++++---- engine/server/svmodel.c | 4 +- engine/server/world.c | 13 +- 75 files changed, 2053 insertions(+), 825 deletions(-) diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index f690fe32f..a3374e7f2 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -1624,6 +1624,19 @@ void CL_RotateAroundTag(entity_t *ent, int entnum, int parenttagent, int parentt model = ps->modelindex; CL_LerpNetFrameState(FS_REG, &fstate, &cl.lerpents[parenttagent]); + + /*inherit certain properties from the parent entity*/ + if (ps->dpflags & RENDER_VIEWMODEL) + ent->flags |= Q2RF_WEAPONMODEL|Q2RF_MINLIGHT|Q2RF_DEPTHHACK; + if ((ps->dpflags & RENDER_EXTERIORMODEL) || r_refdef.playerview->viewentity == ps->number) + ent->flags |= Q2RF_EXTERNALMODEL; + + if (ent->playerindex == -1 && ps->colormap > 0 && ps->colormap <= cl.allocated_client_slots) + { + ent->playerindex = ps->colormap-1; + ent->topcolour = cl.players[ent->playerindex].ttopcolor; + ent->bottomcolour = cl.players[ent->playerindex].tbottomcolor; + } } else { diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 22797bc6c..a20c34f5a 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -696,14 +696,17 @@ void CL_ClampPitch (int pnum) vang[PITCH] *= -1; /*edit it*/ - if (vang[PITCH] < -180) + vang[PITCH] += cl.playerview[pnum].viewanglechange[PITCH]; + vang[YAW] += cl.playerview[pnum].viewanglechange[YAW]; + if (vang[PITCH] <= -180) vang[PITCH] += 360; if (vang[PITCH] > 180) vang[PITCH] -= 360; - if (vang[ROLL] > 180) + if (vang[ROLL] >= 180) vang[ROLL] -= 360; - vang[PITCH] += cl.playerview[pnum].viewanglechange[PITCH]; - vang[YAW] += cl.playerview[pnum].viewanglechange[YAW]; + if (vang[ROLL] < -180) + vang[ROLL] += 360; + /*keep the player looking relative to their ground (smoothlyish)*/ if (!vang[ROLL]) { @@ -715,9 +718,15 @@ void CL_ClampPitch (int pnum) if (fabs(vang[ROLL]) < host_frametime*180) vang[ROLL] = 0; else if (vang[ROLL] > 0) + { + Con_Printf("Roll %f\n", vang[ROLL]); vang[ROLL] -= host_frametime*180; + } else + { + Con_Printf("Roll %f\n", vang[ROLL]); vang[ROLL] += host_frametime*180; + } } VectorClear(cl.playerview[pnum].viewanglechange); /*clamp pitch*/ @@ -737,6 +746,10 @@ void CL_ClampPitch (int pnum) VectorAngles(view[0], view[2], cl.playerview[pnum].viewangles); cl.playerview[pnum].viewangles[PITCH] *= -1; + if (cl.playerview[pnum].viewangles[ROLL] >= 360) + cl.playerview[pnum].viewangles[ROLL] -= 360; + if (cl.playerview[pnum].viewangles[ROLL] < 0) + cl.playerview[pnum].viewangles[ROLL] += 360; if (cl.playerview[pnum].viewangles[PITCH] < -180) cl.playerview[pnum].viewangles[PITCH] += 360; return; diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 9ddf4d907..1bd791447 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -5877,13 +5877,13 @@ void CLQW_ParseServerMessage (void) case svcfte_cgamepacket: csqcpacket = true; -#ifdef HLCLIENT - if (CLHL_ParseGamePacket()) - break; -#endif #ifdef CSQC_DAT if (CSQC_ParseGamePacket()) break; +#endif +#ifdef HLCLIENT + if (CLHL_ParseGamePacket()) + break; #endif Con_Printf("Unable to parse gamecode packet\n"); break; diff --git a/engine/client/cl_plugin.inc b/engine/client/cl_plugin.inc index 0abf984d5..dc6b662df 100644 --- a/engine/client/cl_plugin.inc +++ b/engine/client/cl_plugin.inc @@ -261,9 +261,9 @@ qintptr_t VARGS Plug_Draw_Character(void *offset, quintptr_t mask, const qintptr int x, y; if (qrenderer == QR_NONE) return 0; - Font_BeginString(font_conchar, arg[0], arg[1], &x, &y); + Font_BeginString(font_default, arg[0], arg[1], &x, &y); Font_DrawChar(x, y, CON_WHITEMASK | 0xe000 | (unsigned int)arg[2]); - Font_EndString(font_conchar); + Font_EndString(font_default); return 0; } qintptr_t VARGS Plug_Draw_String(void *offset, quintptr_t mask, const qintptr_t *arg) @@ -274,7 +274,7 @@ qintptr_t VARGS Plug_Draw_String(void *offset, quintptr_t mask, const qintptr_t return 0; COM_ParseFunString(CON_WHITEMASK, VM_POINTER(arg[2]), buffer, sizeof(buffer), false); str = buffer; - Font_BeginString(font_conchar, VM_FLOAT(arg[0]), VM_FLOAT(arg[1]), &px, &py); + Font_BeginString(font_default, VM_FLOAT(arg[0]), VM_FLOAT(arg[1]), &px, &py); ipx = px; while(*str) { @@ -286,7 +286,7 @@ qintptr_t VARGS Plug_Draw_String(void *offset, quintptr_t mask, const qintptr_t px = Font_DrawChar(px, py, *str); str++; } - Font_EndString(font_conchar); + Font_EndString(font_default); return 0; } diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index ab25991a2..f300f1072 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -580,7 +580,7 @@ void SCR_CheckDrawCenterString (void) continue; SCR_VRectForPlayer(&rect, pnum); - SCR_DrawCenterString(&rect, p, font_conchar); + SCR_DrawCenterString(&rect, p, font_default); } } @@ -599,13 +599,26 @@ void R_DrawTextField(int x, int y, int w, int h, char *text, unsigned int defaul p.time_off = scr_centertime.value; p.time_start = cl.time; - SCR_DrawCenterString(&r, &p, font_conchar); + SCR_DrawCenterString(&r, &p, font_default); } void SCR_DrawCursor(int prydoncursornum) { extern cvar_t cl_cursor, cl_cursorbias, cl_cursorsize; mpic_t *p; + + if (key_dest_absolutemouse & kdm_game) + { + //if the game is meant to be drawing a cursor, don't draw one over the top. + key_dest_absolutemouse &= ~kdm_game; + if (!Key_MouseShouldBeFree()) + { //unless something else wants a cursor too. + key_dest_absolutemouse |= kdm_game; + return; + } + key_dest_absolutemouse |= kdm_game; + } + if (!*cl_cursor.string || prydoncursornum>1) p = R2D_SafeCachePic(va("gfx/prydoncursor%03i.lmp", prydoncursornum)); else @@ -620,11 +633,11 @@ void SCR_DrawCursor(int prydoncursornum) else { float x, y; - Font_BeginScaledString(font_conchar, mousecursor_x, mousecursor_y, 8, 8, &x, &y); + Font_BeginScaledString(font_default, mousecursor_x, mousecursor_y, 8, 8, &x, &y); x -= Font_CharWidth('+' | 0xe000 | CON_WHITEMASK)/2; y -= Font_CharHeight()/2; Font_DrawScaleChar(x, y, '+' | 0xe000 | CON_WHITEMASK); - Font_EndString(font_conchar); + Font_EndString(font_default); } } static void SCR_DrawSimMTouchCursor(void) @@ -635,11 +648,11 @@ static void SCR_DrawSimMTouchCursor(void) { if (multicursor_active[i]) { - Font_BeginScaledString(font_conchar, multicursor_x[i], multicursor_y[i], 8, 8, &x, &y); + Font_BeginScaledString(font_default, multicursor_x[i], multicursor_y[i], 8, 8, &x, &y); x -= Font_CharWidth('+' | 0xe000 | CON_WHITEMASK)/2; y -= Font_CharHeight()/2; Font_DrawScaleChar(x, y, '+' | 0xe000 | CON_WHITEMASK); - Font_EndString(font_conchar); + Font_EndString(font_default); } } } @@ -1090,7 +1103,7 @@ void SCR_StringXY(char *str, float x, float y) char *s2; int px, py; - Font_BeginString(font_conchar, ((x<0)?vid.width:x), ((y<0)?vid.height - sb_lines:y), &px, &py); + Font_BeginString(font_default, ((x<0)?vid.width:x), ((y<0)?vid.height - sb_lines:y), &px, &py); if (x < 0) { @@ -1103,7 +1116,7 @@ void SCR_StringXY(char *str, float x, float y) while (*str) px = Font_DrawChar(px, py, CON_WHITEMASK|*str++); - Font_EndString(font_conchar); + Font_EndString(font_default); } void SCR_DrawFPS (void) diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 56c30b0bb..9c19ea775 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -1603,7 +1603,7 @@ void CL_ParseTEnt (void) gravity = MSG_ReadByte (); //gravity flag jitter = MSG_ReadCoord(); //jitter - P_RunParticleCube(pos, pos2, dir, cnt, colour, gravity, jitter); + P_RunParticleCube(P_INVALID, pos, pos2, dir, dir, cnt, colour, gravity, jitter); } break; case TEDP_PARTICLERAIN: diff --git a/engine/client/clhl_game.c b/engine/client/clhl_game.c index 55e177a2d..2f0b9df39 100644 --- a/engine/client/clhl_game.c +++ b/engine/client/clhl_game.c @@ -21,9 +21,14 @@ struct hlcvar_s *QDECL GHL_CVarGetPointer(char *varname); //I hope you're c99 and have a __func__ #endif +extern cvar_t temp1; #define ignore(s) Con_Printf("Fixme: " s "\n") #define notimpl(l) Con_Printf("halflife cl builtin not implemented on line %i\n", l) #define notimpf(f) Con_Printf("halflife cl builtin %s not implemented\n", f) +#define notimp() Con_Printf("halflife cl builtin %s not implemented\n", __func__) +#define bi_begin() if (temp1.ival)Con_Printf("enter %s\n", __func__) +#define bi_end() if (temp1.ival)Con_Printf("leave %s\n", __func__) +#define bi_trace() bi_begin(); bi_end() #if HLCLIENT >= 1 #define HLCL_API_VERSION HLCLIENT @@ -34,21 +39,28 @@ struct hlcvar_s *QDECL GHL_CVarGetPointer(char *varname); void *vgui_panel; +void *(QDECL *vgui_init)(void); +void (QDECL *vgui_frame)(void); +void (QDECL *vgui_key)(int down, int scan); +void (QDECL *vgui_mouse)(int x, int y); + qboolean VGui_Setup(void) { void *vguidll; - int (QDECL *init)(void); dllfunction_t funcs[] = { - {(void*)&init, "init"}, + {(void*)&vgui_init, "init"}, + {(void*)&vgui_frame, "frame"}, + {(void*)&vgui_key, "key"}, + {(void*)&vgui_mouse, "mouse"}, {NULL} }; vguidll = Sys_LoadLibrary("vguiwrap", funcs); if (vguidll) - vgui_panel = init(); + vgui_panel = vgui_init(); return !!vgui_panel; } @@ -89,17 +101,17 @@ typedef struct { short lerpmsecs; qbyte msec; + //pad1 vec3_t viewangles; - float forwardmove; float sidemove; float upmove; - qbyte lightlevel; + //pad1 unsigned short buttons; qbyte impulse; qbyte weaponselect; - + //pad2 int impact_index; vec3_t impact_position; } hlusercmd_t; @@ -120,6 +132,7 @@ typedef struct qbyte isus; qbyte isspec; qbyte pl; + //pad3 char *model; short tcolour; short bcolour; @@ -372,11 +385,16 @@ int hl_viewmodelsequencebody; HLPIC QDECL CLGHL_pic_load (char *picname) { - return Mod_ForName(picname, false); + void *ret; + bi_begin(); + ret = Mod_ForName(picname, false); + bi_end(); + return ret; // return R2D_SafeCachePic(picname); } int QDECL CLGHL_pic_getnumframes (HLPIC pic) { + bi_trace(); if (pic) return pic->numframes; else @@ -387,9 +405,10 @@ static mspriteframe_t *getspriteframe(HLPIC pic, int frame) { msprite_t *psprite; mspritegroup_t *pgroup; + bi_trace(); if (!pic) return NULL; - psprite = pic->cache.data; + psprite = pic->meshinfo; if (!psprite) return NULL; @@ -404,6 +423,7 @@ static mspriteframe_t *getspriteframe(HLPIC pic, int frame) static mpic_t *getspritepic(HLPIC pic, int frame) { mspriteframe_t *f; + bi_trace(); f = getspriteframe(pic, frame); if (f) return f->shader; @@ -413,6 +433,7 @@ static mpic_t *getspritepic(HLPIC pic, int frame) int QDECL CLGHL_pic_getheight (HLPIC pic, int frame) { mspriteframe_t *pframe; + bi_trace(); pframe = getspriteframe(pic, frame); if (!pframe) @@ -423,6 +444,7 @@ int QDECL CLGHL_pic_getheight (HLPIC pic, int frame) int QDECL CLGHL_pic_getwidth (HLPIC pic, int frame) { mspriteframe_t *pframe; + bi_trace(); pframe = getspriteframe(pic, frame); if (!pframe) @@ -432,12 +454,14 @@ int QDECL CLGHL_pic_getwidth (HLPIC pic, int frame) } void QDECL CLGHL_pic_select (HLPIC pic, int r, int g, int b) { + bi_trace(); selectedpic = pic; R2D_ImageColours(r/255.0f, g/255.0f, b/255.0f, 1); } void QDECL CLGHL_pic_drawcuropaque (int frame, int x, int y, hlsubrect_t *loc) { mpic_t *pic = getspritepic(selectedpic, frame); + bi_trace(); if (!pic) return; @@ -453,6 +477,7 @@ void QDECL CLGHL_pic_drawcuropaque (int frame, int x, int y, hlsubrect_t *loc) void QDECL CLGHL_pic_drawcuralphtest (int frame, int x, int y, hlsubrect_t *loc) { mpic_t *pic = getspritepic(selectedpic, frame); + bi_trace(); if (!pic) return; //use some kind of alpha @@ -467,6 +492,8 @@ void QDECL CLGHL_pic_drawcuralphtest (int frame, int x, int y, hlsubrect_t *loc) void QDECL CLGHL_pic_drawcuradditive (int frame, int x, int y, hlsubrect_t *loc) { mpic_t *pic = getspritepic(selectedpic, frame); + + bi_trace(); if (!pic) return; @@ -494,9 +521,23 @@ void QDECL CLGHL_pic_drawcuradditive (int frame, int x, int y, hlsubrect_t *loc) } void QDECL CLGHL_pic_enablescissor (int x, int y, int width, int height) { + srect_t srect; + + bi_trace(); + + srect.x = x / vid.width; + srect.y = y / vid.height; + srect.width = width / vid.width; + srect.height = height / vid.height; + srect.dmin = -99999; + srect.dmax = 99999; + srect.y = (1-srect.y) - srect.height; + BE_Scissor(&srect); } void QDECL CLGHL_pic_disablescissor (void) { + bi_trace(); + BE_Scissor(NULL); } hlspriteinf_t *QDECL CLGHL_pic_parsepiclist (char *filename, int *numparsed) { @@ -506,6 +547,8 @@ hlspriteinf_t *QDECL CLGHL_pic_parsepiclist (char *filename, int *numparsed) void *file; char *pos; + bi_trace(); + *numparsed = 0; FS_LoadFile(filename, &file); @@ -556,10 +599,12 @@ hlspriteinf_t *QDECL CLGHL_pic_parsepiclist (char *filename, int *numparsed) void QDECL CLGHL_fillrgba (int x, int y, int width, int height, int r, int g, int b, int a) { + bi_trace(); } int QDECL CLGHL_getscreeninfo (hlscreeninfo_t *info) { int i; + bi_trace(); if (info->size != sizeof(*info)) return false; @@ -574,10 +619,12 @@ int QDECL CLGHL_getscreeninfo (hlscreeninfo_t *info) } void QDECL CLGHL_setcrosshair (HLPIC pic, hlsubrect_t rect, int r, int g, int b) { + bi_trace(); } struct hlcvar_s *QDECL CLGHL_cvar_register (char *name, char *defvalue, int flags) { + bi_trace(); if (Cvar_Get(name, defvalue, 0, "Halflife cvars")) return GHL_CVarGetPointer(name); else @@ -586,6 +633,7 @@ struct hlcvar_s *QDECL CLGHL_cvar_register (char *name, char *defvalue, int flag float QDECL CLGHL_cvar_getfloat (char *name) { cvar_t *var = Cvar_FindVar(name); + bi_trace(); if (var) return var->value; return 0; @@ -593,6 +641,7 @@ float QDECL CLGHL_cvar_getfloat (char *name) char *QDECL CLGHL_cvar_getstring (char *name) { cvar_t *var = Cvar_FindVar(name); + bi_trace(); if (var) return var->string; return ""; @@ -600,11 +649,13 @@ char *QDECL CLGHL_cvar_getstring (char *name) void QDECL CLGHL_cmd_register (char *name, xcommand_t func) { + bi_trace(); Cmd_AddCommand(name, func); } void QDECL CLGHL_hooknetmsg (char *msgname, void *func) { int i; + bi_trace(); //update the current list now. for (i = 0; i < sizeof(usermsgs)/sizeof(usermsgs[0]); i++) { @@ -631,16 +682,19 @@ void QDECL CLGHL_hooknetmsg (char *msgname, void *func) } void QDECL CLGHL_forwardcmd (char *command) { + bi_trace(); CL_SendClientCommand(true, "%s", command); } void QDECL CLGHL_localcmd (char *command) { + bi_trace(); Cbuf_AddText(command, RESTRICT_SERVER); } void QDECL CLGHL_getplayerinfo (int entnum, hlplayerinfo_t *result) { player_info_t *player; + bi_trace(); entnum--; if (entnum < 0 || entnum >= MAX_CLIENTS) return; @@ -662,6 +716,7 @@ void QDECL CLGHL_getplayerinfo (int entnum, hlplayerinfo_t *result) void QDECL CLGHL_startsound_name (char *name, float vol) { sfx_t *sfx = S_PrecacheSound (name); + bi_trace(); if (!sfx) { Con_Printf ("CLGHL_startsound_name: can't cache %s\n", name); @@ -672,6 +727,7 @@ void QDECL CLGHL_startsound_name (char *name, float vol) void QDECL CLGHL_startsound_idx (int idx, float vol) { sfx_t *sfx = cl.sound_precache[idx]; + bi_trace(); if (!sfx) { Con_Printf ("CLGHL_startsound_name: index not precached %s\n", name); @@ -682,68 +738,80 @@ void QDECL CLGHL_startsound_idx (int idx, float vol) void QDECL CLGHL_anglevectors (float *ina, float *outf, float *outr, float *outu) { + bi_trace(); AngleVectors(ina, outf, outr, outu); } hlmsginfo_t *QDECL CLGHL_get_message_info (char *name) { - //fixme: add parser + //fixme: add parser for titles.txt hlmsginfo_t *ret; + bi_trace(); ret = Z_Malloc(sizeof(*ret)); memset(ret, 0, sizeof(*ret)); ret->name = name; ret->message = name; - ret->x = 0; - ret->y = 0; + ret->x = -1; + ret->y = -1; *(int*)&ret->c1 = 0xffffffff; *(int*)&ret->c2 = 0xffffffff; ret->effect = 0; - ret->fadein = 0; - ret->fadeout = 0; + ret->fadein = 1; + ret->fadeout = 1.5; ret->fxtime = 0; - ret->holdtime = 1000; + ret->holdtime = 3; return ret; } int QDECL CLGHL_drawchar (int x, int y, int charnum, int r, int g, int b) { + bi_trace(); return 0; } int QDECL CLGHL_drawstring (int x, int y, char *string) { + bi_trace(); return 0; } void QDECL CLGHL_settextcolour(float r, float g, float b) { + bi_trace(); } void QDECL CLGHL_drawstring_getlen (char *string, int *outlen, int *outheight) { + bi_trace(); *outlen = strlen(string)*8; *outheight = 8; } void QDECL CLGHL_consoleprint (char *str) { + bi_trace(); Con_Printf("%s", str); } void QDECL CLGHL_centerprint (char *str) { + bi_trace(); SCR_CenterPrint(0, str, true); } int QDECL CLGHL_getwindowcenterx(void) { + bi_trace(); return window_center_x; } int QDECL CLGHL_getwindowcentery(void) { + bi_trace(); return window_center_y; } void QDECL CLGHL_getviewnangles(float*ang) { + bi_trace(); VectorCopy(cl.playerview[0].viewangles, ang); } void QDECL CLGHL_setviewnangles(float*ang) { + bi_trace(); VectorCopy(ang, cl.playerview[0].viewangles); } void QDECL CLGHL_getmaxclients(float*ang){notimpf(__func__);} @@ -751,25 +819,29 @@ void QDECL CLGHL_cvar_setvalue(char *cvarname, char *value){notimpf(__func__);} int QDECL CLGHL_cmd_argc(void) { + bi_trace(); return Cmd_Argc(); } char *QDECL CLGHL_cmd_argv(int i) { + bi_trace(); return Cmd_Argv(i); } -#define CLGHL_con_printf Con_Printf//void CLGHL_con_printf(char *fmt, ...){notimp(__LINE__);} -#define CLGHL_con_dprintf Con_DPrintf//void CLGHL_con_dprintf(char *fmt, ...){notimp(__LINE__);} +#define CLGHL_con_printf Con_Printf +#define CLGHL_con_dprintf Con_DPrintf void QDECL CLGHL_con_notificationprintf(int pos, char *fmt, ...){notimpf(__func__);} void QDECL CLGHL_con_notificationprintfex(void *info, char *fmt, ...){notimpf(__func__);} char *QDECL CLGHL_physkey(char *key){notimpf(__func__);return NULL;} char *QDECL CLGHL_serverkey(char *key){notimpf(__func__);return NULL;} float QDECL CLGHL_getclientmaxspeed(void) { + bi_trace(); return 320; } int QDECL CLGHL_checkparm(char *str, const char **next) { int i; + bi_trace(); i = COM_CheckParm(str); if (next) { @@ -782,6 +854,7 @@ int QDECL CLGHL_checkparm(char *str, const char **next) } int QDECL CLGHL_keyevent(int key, int down) { + bi_trace(); if (key >= 241 && key <= 241+5) Key_Event(0, K_MOUSE1+key-241, 0, down); else @@ -789,11 +862,18 @@ int QDECL CLGHL_keyevent(int key, int down) return true; //fixme: check the return type } void QDECL CLGHL_getmousepos(int *outx, int *outy){notimpf(__func__);} -int QDECL CLGHL_movetypeisnoclip(void){notimpf(__func__);return 0;} +int QDECL CLGHL_movetypeisnoclip(void) +{ + bi_trace(); + if (cl.playerview[0].pmovetype == PM_SPECTATOR) + return true; + return false; +} struct hlclent_s *QDECL CLGHL_getlocalplayer(void){notimpf(__func__);return NULL;} struct hlclent_s *QDECL CLGHL_getviewent(void){notimpf(__func__);return NULL;} struct hlclent_s *QDECL CLGHL_getentidx(int idx) { + bi_trace(); notimpf(__func__);return NULL; } float QDECL CLGHL_getlocaltime(void){return cl.time;} @@ -813,6 +893,7 @@ unsigned short QDECL CLGHL_precacheevent(int evtype, char *name){notimpf(__func_ void QDECL CLGHL_playevent(int flags, struct hledict_s *ent, unsigned short evindex, float delay, float *origin, float *angles, float f1, float f2, int i1, int i2, int b1, int b2){notimpf(__func__);} void QDECL CLGHL_weaponanimate(int newsequence, int body) { + bi_trace(); hl_viewmodelsequencetime = cl.time; hl_viewmodelsequencecur = newsequence; hl_viewmodelsequencebody = body; @@ -821,28 +902,34 @@ float QDECL CLGHL_randfloat(float minv, float maxv){notimpf(__func__);return min long QDECL CLGHL_randlong(long minv, long maxv){notimpf(__func__);return minv;} void QDECL CLGHL_hookevent(char *name, void (*func)(struct hlevent_s *event)) { + bi_trace(); Con_Printf("CLGHL_hookevent: not implemented. %s\n", name); // notimpf(__func__); } int QDECL CLGHL_con_isshown(void) { + bi_trace(); return scr_con_current > 0; } char *QDECL CLGHL_getgamedir(void) { extern char gamedirfile[]; + bi_trace(); return gamedirfile; } struct hlcvar_s *QDECL CLGHL_cvar_find(char *name) { + bi_trace(); return GHL_CVarGetPointer(name); } char *QDECL CLGHL_lookupbinding(char *command) { + bi_trace(); return NULL; } char *QDECL CLGHL_getlevelname(void) { + bi_trace(); if (!cl.worldmodel) return ""; return cl.worldmodel->name; @@ -851,10 +938,12 @@ void QDECL CLGHL_getscreenfade(struct hlsfade_s *fade){notimpf(__func__);} void QDECL CLGHL_setscreenfade(struct hlsfade_s *fade){notimpf(__func__);} void *QDECL CLGHL_vgui_getpanel(void) { + bi_trace(); return vgui_panel; } void QDECL CLGHL_vgui_paintback(int extents[4]) { + bi_trace(); notimpf(__func__); } @@ -862,6 +951,7 @@ void *QDECL CLGHL_loadfile(char *path, int alloctype, int *length) { void *ptr = NULL; int flen = -1; + bi_trace(); if (alloctype == 5) { flen = FS_LoadFile(path, &ptr); @@ -876,10 +966,12 @@ void *QDECL CLGHL_loadfile(char *path, int alloctype, int *length) } char *QDECL CLGHL_parsefile(char *data, char *token) { + bi_trace(); return COM_ParseOut(data, token, 1024); } void QDECL CLGHL_freefile(void *file) { + bi_trace(); //only valid for alloc type 5 FS_FreeFile(file); } @@ -887,10 +979,12 @@ void QDECL CLGHL_freefile(void *file) int QDECL CLGHL_forcedspectator(void) { + bi_trace(); return cls.demoplayback; } model_t *QDECL CLGHL_loadmapsprite(char *name) { + bi_trace(); notimpf(__func__);return NULL; } @@ -906,12 +1000,14 @@ int QDECL CLGHL_playerfromtracker(int tracker){notimpf(__func__);return 0;} int QDECL CLGHL_sendcmd_unreliable(char *cmd){notimpf(__func__);return 0;} void QDECL CLGHL_getsysmousepos(long *xandy) { + bi_trace(); #ifdef _WIN32 GetCursorPos((LPPOINT)xandy); #endif } void QDECL CLGHL_setsysmousepos(int x, int y) { + bi_trace(); #ifdef _WIN32 SetCursorPos(x, y); #endif @@ -919,6 +1015,7 @@ void QDECL CLGHL_setsysmousepos(int x, int y) void QDECL CLGHL_setmouseenable(qboolean enable) { extern cvar_t _windowed_mouse; + bi_trace(); Cvar_Set(&_windowed_mouse, enable?"1":"0"); } @@ -927,29 +1024,33 @@ void QDECL CLGHL_setmouseenable(qboolean enable) #if HLCL_API_VERSION >= 7 int QDECL CLGHL_demo_isrecording(void) { + bi_trace(); return cls.demorecording; } int QDECL CLGHL_demo_isplaying(void) { + bi_trace(); return cls.demoplayback; } int QDECL CLGHL_demo_istimedemo(void) { + bi_trace(); return cls.timedemo; } void QDECL CLGHL_demo_writedata(int size, void *data) { + bi_trace(); notimpf(__func__); } struct hl_demo_api_s hl_demo_api = { - CLGHL_demo_isrecording, - CLGHL_demo_isplaying, - CLGHL_demo_istimedemo, - CLGHL_demo_writedata, + CLGHL_demo_isrecording, + CLGHL_demo_isplaying, + CLGHL_demo_istimedemo, + CLGHL_demo_writedata, - 0xdeadbeef + 0xdeadbeef }; #endif @@ -1153,7 +1254,8 @@ void CLHL_UnloadClientGame(void) void CLHL_LoadClientGame(void) { char fullname[MAX_OSPATH]; - char *path; + char path[MAX_OSPATH]; + void *iterator; int (QDECL *initfunc)(CLHL_enginecgamefuncs_t *funcs, int version); dllfunction_t funcs[] = @@ -1166,19 +1268,14 @@ void CLHL_LoadClientGame(void) memset(&CLHL_cgamefuncs, 0, sizeof(CLHL_cgamefuncs)); - clg = NULL;//Sys_LoadLibrary("C:/Incoming/d/Half-Life/sdks/hlsdk-2.3-p3/hlsdk-2.3-p3/multiplayer/cl_dll/Debug/client", funcs); - if (!clg) + clg = NULL; + iterator = NULL; + while(COM_IteratePaths(&iterator, path, sizeof(path))) { - path = NULL; - while((path = COM_NextPath (path))) - { - if (!path) - return; // couldn't find one anywhere - snprintf (fullname, sizeof(fullname), "%s/%s", path, "cl_dlls/client"); - clg = Sys_LoadLibrary(fullname, funcs); - if (clg) - break; - } + snprintf (fullname, sizeof(fullname), "%s%s", path, "cl_dlls/client"); + clg = Sys_LoadLibrary(fullname, funcs); + if (clg) + break; } if (!clg) @@ -1244,6 +1341,7 @@ int CLHL_DrawHud(void) { extern kbutton_t in_attack; hllocalclientdata_t state; + int ret; if (!clg || !CLHL_cgamefuncs.HUD_Redraw) return false; @@ -1263,11 +1361,12 @@ int CLHL_DrawHud(void) state.weapons = cl.playerview[0].stats[STAT_ITEMS]; state.fov = 90; - V_StopPitchDrift(0); + V_StopPitchDrift(&cl.playerview[0]); CLHL_cgamefuncs.HUD_UpdateClientData(&state, cl.time); - return CLHL_cgamefuncs.HUD_Redraw(cl.time, cl.intermission); + ret = CLHL_cgamefuncs.HUD_Redraw(cl.time, cl.intermission); + return ret; } int CLHL_AnimateViewEntity(entity_t *ent) diff --git a/engine/client/client.h b/engine/client/client.h index e3320072e..3cad80bce 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -1144,6 +1144,7 @@ qboolean CSQC_UnconnectedInit(void); qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checksum); qboolean CSQC_ConsoleLink(char *text, char *info); void CSQC_RegisterCvarsAndThings(void); +qboolean CSQC_SetupToRenderPortal(int entnum); qboolean CSQC_DrawView(void); void CSQC_Shutdown(void); qboolean CSQC_StuffCmd(int lplayernum, char *cmd, char *cmdend); diff --git a/engine/client/console.c b/engine/client/console.c index ca6e03232..fdcc70e72 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -67,6 +67,7 @@ cvar_t con_notifytime_chat = CVAR("con_notifytime_chat", "8"); cvar_t con_separatechat = CVAR("con_separatechat", "0"); cvar_t con_timestamps = CVAR("con_timestamps", "0"); cvar_t con_timeformat = CVAR("con_timeformat", "(%H:%M:%S) "); +cvar_t con_textsize = CVARD("con_textsize", "8", "Resize the console text to be a different height, scaled separately from the hud. The value is the height in (virtual) pixels."); #define NUM_CON_TIMES 24 @@ -588,6 +589,7 @@ void Con_Init (void) Cvar_Register (&con_separatechat, "Console controls"); Cvar_Register (&con_timestamps, "Console controls"); Cvar_Register (&con_timeformat, "Console controls"); + Cvar_Register (&con_textsize, "Console controls"); Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f); Cmd_AddCommand ("messagemode", Con_MessageMode_f); @@ -1183,7 +1185,7 @@ void Con_DrawNotifyOne (console_t *con) int maxlines; float t; - Font_BeginString(font_conchar, x, y, &x, &y); + Font_BeginString(font_console, x, y, &x, &y); Font_Transform(con->notif_w, 0, &w, NULL); if (con->notif_l < 0) @@ -1250,7 +1252,7 @@ void Con_DrawNotifyOne (console_t *con) lines++; } - Font_EndString(font_conchar); + Font_EndString(font_console); } void Con_DrawNotify (void) @@ -1286,7 +1288,7 @@ void Con_DrawNotify (void) conchar_t *c, *end; char *foo = va(chat_team?"say_team: %s":"say: %s", chat_buffer?chat_buffer:""); int lines, i, pos; - Font_BeginString(font_conchar, 0, 0, &x, &y); + Font_BeginString(font_console, 0, 0, &x, &y); y = con_main.notif_l * Font_CharHeight(); i = chat_team?10:5; @@ -1315,7 +1317,7 @@ void Con_DrawNotify (void) Font_LineDraw(x, y, starts[i], ends[i]); y += Font_CharHeight(); } - Font_EndString(font_conchar); + Font_EndString(font_console); } } @@ -1510,8 +1512,8 @@ int Con_DrawAlternateConsoles(int lines) if (lines == (int)scr_conlines && consshown > 1) { int mx, my, h; - Font_BeginString(font_conchar, mousecursor_x, mousecursor_y, &mx, &my); - Font_BeginString(font_conchar, 0, y, &x, &y); + Font_BeginString(font_console, mousecursor_x, mousecursor_y, &mx, &my); + Font_BeginString(font_console, 0, y, &x, &y); h = Font_CharHeight(); for (x = 0, con = &con_main; con; con = con->next) { @@ -1525,7 +1527,7 @@ int Con_DrawAlternateConsoles(int lines) lx = 0; for (lx = x, start = buffer; start < end; start++) { - lx = Font_CharEndCoord(font_conchar, lx, *start); + lx = Font_CharEndCoord(font_console, lx, *start); } if (lx > Font_ScreenWidth()) { @@ -1535,7 +1537,7 @@ int Con_DrawAlternateConsoles(int lines) for (lx = x, start = buffer; start < end; start++) { Font_DrawChar(lx, y, *start); - lx = Font_CharEndCoord(font_conchar, lx, *start); + lx = Font_CharEndCoord(font_console, lx, *start); } lx += 8; if (mx >= x && mx < lx && my >= y && my < y+h) @@ -1543,7 +1545,7 @@ int Con_DrawAlternateConsoles(int lines) x = lx; } y+= h; - Font_EndString(font_conchar); + Font_EndString(font_console); y = (y*(int)vid.height) / (float)vid.rotpixelheight; } @@ -1838,9 +1840,9 @@ void Con_DrawConsole (int lines, qboolean noback) con_current->selendline = NULL; selactive = Key_GetConsoleSelectionBox(con_current, &selsx, &selsy, &selex, &seley); - Font_BeginString(font_conchar, x, y, &x, &y); - Font_BeginString(font_conchar, selsx, selsy, &selsx, &selsy); - Font_BeginString(font_conchar, selex, seley, &selex, &seley); + Font_BeginString(font_console, x, y, &x, &y); + Font_BeginString(font_console, selsx, selsy, &selsx, &selsy); + Font_BeginString(font_console, selex, seley, &selex, &seley); ex = Font_ScreenWidth(); sx = x; ex -= sx; @@ -1857,7 +1859,7 @@ void Con_DrawConsole (int lines, qboolean noback) { char *version = version_string(); int i; - Font_BeginString(font_conchar, vid.width, lines, &x, &y); + Font_BeginString(font_console, vid.width, lines, &x, &y); y -= Font_CharHeight(); for (i = 0; version[i]; i++) x -= Font_CharWidth(version[i] | CON_WHITEMASK|CON_HALFALPHA); @@ -1865,7 +1867,7 @@ void Con_DrawConsole (int lines, qboolean noback) x = Font_DrawChar(x, y, version[i] | CON_WHITEMASK|CON_HALFALPHA); } - Font_EndString(font_conchar); + Font_EndString(font_console); if (con_current->selstartline) { @@ -1904,17 +1906,17 @@ void Con_DrawConsole (int lines, qboolean noback) //FIXME: support line breaks. conchar_t buffer[2048], *starts[8], *ends[8]; int lines, i, px, py; - Font_BeginString(font_conchar, x, y, &px, &py); + Font_BeginString(font_console, x, y, &px, &py); lines = Font_LineBreaks(buffer, COM_ParseFunString(CON_WHITEMASK|CON_NONCLEARBG, key, buffer, sizeof(buffer), false), 256, 8, starts, ends); ih = max(Font_CharHeight()*lines, ih)/2; y += ih - (Font_CharHeight()*lines)/2; - Font_BeginString(font_conchar, x, y, &px, &py); + Font_BeginString(font_console, x, y, &px, &py); for (i = 0; i < lines; i++) { Font_LineDraw(px, py, starts[i], ends[i]); py += Font_CharHeight(); } - Font_EndString(font_conchar); + Font_EndString(font_console); } } } diff --git a/engine/client/keys.c b/engine/client/keys.c index 3994dfaea..2dc55477d 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -141,6 +141,7 @@ keyname_t keynames[] = {"KP_PLUS", K_KP_PLUS}, {"KP_NUMLOCK", K_KP_NUMLOCK}, {"KP_STAR", K_KP_STAR}, + {"KP_MULTIPLY", K_KP_STAR}, {"KP_EQUALS", K_KP_EQUALS}, //fuhquake compatible. @@ -1568,7 +1569,8 @@ void Key_Unbind_f (void) b = Key_StringToKeynum (Cmd_Argv(1), &modifier); if (b==-1) { - Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1)); + if (cl_warncmd.ival) + Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1)); return; } @@ -1605,7 +1607,8 @@ void Key_Bind_f (void) b = Key_StringToKeynum (Cmd_Argv(1), &modifier); if (b==-1) { - Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1)); + if (cl_warncmd.ival) + Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1)); return; } @@ -1652,7 +1655,8 @@ void Key_BindLevel_f (void) b = Key_StringToKeynum (Cmd_Argv(1), &modifier); if (b==-1) { - Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1)); + if (cl_warncmd.ival) + Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1)); return; } diff --git a/engine/client/keys.h b/engine/client/keys.h index a55f0f239..226624eed 100644 --- a/engine/client/keys.h +++ b/engine/client/keys.h @@ -198,7 +198,7 @@ extern qboolean chat_team; void Key_Event (int devid, int key, unsigned int unicode, qboolean down); void Key_Init (void); -void Key_WriteBindings (vfsfile_t *f); +void Key_WriteBindings (struct vfsfile_s *f); void Key_SetBinding (int keynum, int modifier, char *binding, int cmdlevel); void Key_ClearStates (void); void Key_Unbindall_f (void); //aka: Key_Shutdown diff --git a/engine/client/m_items.c b/engine/client/m_items.c index 0fc15fbc6..f1bf16a61 100644 --- a/engine/client/m_items.c +++ b/engine/client/m_items.c @@ -483,14 +483,14 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu range = 1; option->slider.vx = x; x -= 8; - Font_BeginString(font_conchar, x, y, &x, &y); + Font_BeginString(font_default, x, y, &x, &y); x = Font_DrawChar(x, y, 0xe080 | CON_WHITEMASK); s = x; for (i=0 ; iselecteditem = (menuoption_t*) MC_AddConsoleCommand (menu, 64, 40, "Easy", "closemenu; skill 0;deathmatch 0; coop 0;newgame\n"); MC_AddConsoleCommand (menu, 64, 48, "Medium", "closemenu; skill 1;deathmatch 0; coop 0;newgame\n"); @@ -264,6 +265,7 @@ void M_Menu_SinglePlayer_f (void) else { MC_AddCenterPicture(menu, 0, 60, "gfx/menu/title1.lmp"); + //startmap selection in hexen2 is nasty. if (havemp) { menu->selecteditem = (menuoption_t*) @@ -314,7 +316,7 @@ void M_Menu_SinglePlayer_f (void) MC_AddCenterPicture(menu, 0, 24, "gfx/p_option.lmp"); menu->selecteditem = (menuoption_t*) - MC_AddConsoleCommandQBigFont (menu, 72, 32, "New Game", "closemenu;disconnect;maxclients 1;deathmatch 0;coop 0;map start\n"); + MC_AddConsoleCommandQBigFont (menu, 72, 32, "New Game", "closemenu;disconnect;maxclients 1;deathmatch 0;coop 0;startmap_sp\n"); MC_AddConsoleCommandQBigFont (menu, 72, 52, "Load Game", "menu_load\n"); MC_AddConsoleCommandQBigFont (menu, 72, 72, "Save Game", "menu_save\n"); @@ -340,7 +342,7 @@ void M_Menu_SinglePlayer_f (void) { MC_AddPicture(menu, 72, 32, 232, 64, "gfx/sp_menu.lmp"); - b = MC_AddConsoleCommand (menu, 16, 32, "", "closemenu;disconnect;maxclients 1;deathmatch 0;coop 0;map start\n"); + b = MC_AddConsoleCommand (menu, 16, 32, "", "closemenu;disconnect;maxclients 1;deathmatch 0;coop 0;startmap_sp\n"); menu->selecteditem = (menuoption_t *)b; b->common.width = p->width; b->common.height = 20; diff --git a/engine/client/merged.h b/engine/client/merged.h index a98e71c9b..0408a17d0 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -64,6 +64,7 @@ void R2D_TransPicTranslate (float x, float y, int width, int height, qbyte *pic, void R2D_TileClear (float x, float y, float w, float h); void R2D_FadeScreen (void); +void R2D_Font_Changed(void); void R2D_ConsoleBackground (int firstline, int lastline, qboolean forceopaque); void R2D_EditorBackground (void); diff --git a/engine/client/net_master.c b/engine/client/net_master.c index 0c42eb50d..d16437abb 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -505,6 +505,9 @@ char *Master_ReadKeyString(serverinfo_t *server, int keynum) { static char adr[MAX_ADR_SIZE]; + if (!server) + return ""; + if (keynum < SLKEY_CUSTOM) { switch(keynum) diff --git a/engine/client/p_classic.c b/engine/client/p_classic.c index b728ed303..59fcdf0df 100644 --- a/engine/client/p_classic.c +++ b/engine/client/p_classic.c @@ -202,7 +202,7 @@ static void PClassic_RunParticleWeather(vec3_t minb, vec3_t maxb, vec3_t dir, fl } //DP extension: add particles within a box. -static void PClassic_RunParticleCube(vec3_t minb, vec3_t maxb, vec3_t dir, float count, int colour, qboolean gravity, float jitter) +static void PClassic_RunParticleCube(int ptype, vec3_t minb, vec3_t maxb, vec3_t dir_min, vec3_t dir_max, float count, int colour, qboolean gravity, float jitter) { } diff --git a/engine/client/p_null.c b/engine/client/p_null.c index ab975bd6c..d9f918c29 100644 --- a/engine/client/p_null.c +++ b/engine/client/p_null.c @@ -15,7 +15,7 @@ static int PNULL_RunParticleEffectTypeString (vec3_t org, vec3_t dir, float coun static int PNULL_ParticleTrail (vec3_t startpos, vec3_t end, int type, int dlkey, trailstate_t **tsk){return 1;} static int PNULL_RunParticleEffectState (vec3_t org, vec3_t dir, float count, int typenum, trailstate_t **tsk){return 1;} static void PNULL_RunParticleWeather(vec3_t minb, vec3_t maxb, vec3_t dir, float count, int colour, char *efname){} -static void PNULL_RunParticleCube(vec3_t minb, vec3_t maxb, vec3_t dir, float count, int colour, qboolean gravity, float jitter){} +static void PNULL_RunParticleCube(int typenum, vec3_t minb, vec3_t maxb, vec3_t dir_min, vec3_t dir_max, float count, int colour, qboolean gravity, float jitter){} static void PNULL_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count){} static void PNULL_RunParticleEffect2 (vec3_t org, vec3_t dmin, vec3_t dmax, int color, int effect, int count){} static void PNULL_RunParticleEffect3 (vec3_t org, vec3_t box, int color, int effect, int count){} diff --git a/engine/client/p_script.c b/engine/client/p_script.c index e49ff6091..296a124c1 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -2214,21 +2214,21 @@ static void P_ImportEffectInfo_f(void) ptype->flags = (ptype->flags & ~PT_NODLSHADOW) | (!atoi(arg[1])?PT_NODLSHADOW:0); else if (!strcmp(arg[0], "lightcubemapnum") && args == 2) ptype->dl_cubemapnum = atoi(arg[1]); -#if 0 - else if (!strcmp(arg[0], "staincolor") && args == 2) - ; - else if (!strcmp(arg[0], "stainalpha") && args == 2) - ; - else if (!strcmp(arg[0], "stainsize") && args == 2) - ; - else if (!strcmp(arg[0], "staintex") && args == 2) - ; - else if (!strcmp(arg[0], "stainless") && args == 1) - ; - else if (!strcmp(arg[0], "rotate") && args == 2) - ; - else if (!strcmp(arg[0], "rotate") && args == 4) - ; +#if 1 + else if (!strcmp(arg[0], "staincolor") && args == 3) + Con_DPrintf("Particle effect token not recognised, or invalid args: %s %s %s %s %s %s\n", arg[0], args<2?"":arg[1], args<3?"":arg[2], args<4?"":arg[3], args<5?"":arg[4], args<6?"":arg[5]); + else if (!strcmp(arg[0], "stainalpha") && args == 3) + Con_DPrintf("Particle effect token not recognised, or invalid args: %s %s %s %s %s %s\n", arg[0], args<2?"":arg[1], args<3?"":arg[2], args<4?"":arg[3], args<5?"":arg[4], args<6?"":arg[5]); + else if (!strcmp(arg[0], "stainsize") && args == 3) + Con_DPrintf("Particle effect token not recognised, or invalid args: %s %s %s %s %s %s\n", arg[0], args<2?"":arg[1], args<3?"":arg[2], args<4?"":arg[3], args<5?"":arg[4], args<6?"":arg[5]); + else if (!strcmp(arg[0], "staintex") && args == 3) + Con_DPrintf("Particle effect token not recognised, or invalid args: %s %s %s %s %s %s\n", arg[0], args<2?"":arg[1], args<3?"":arg[2], args<4?"":arg[3], args<5?"":arg[4], args<6?"":arg[5]); + else if (!strcmp(arg[0], "stainless") && args == 2) + Con_DPrintf("Particle effect token not recognised, or invalid args: %s %s %s %s %s %s\n", arg[0], args<2?"":arg[1], args<3?"":arg[2], args<4?"":arg[3], args<5?"":arg[4], args<6?"":arg[5]); + else if (!strcmp(arg[0], "rotate") && args == 3) + Con_DPrintf("Particle effect token not recognised, or invalid args: %s %s %s %s %s %s\n", arg[0], args<2?"":arg[1], args<3?"":arg[2], args<4?"":arg[3], args<5?"":arg[4], args<6?"":arg[5]); + else if (!strcmp(arg[0], "rotate") && args == 5) + Con_DPrintf("Particle effect token not recognised, or invalid args: %s %s %s %s %s %s\n", arg[0], args<2?"":arg[1], args<3?"":arg[2], args<4?"":arg[3], args<5?"":arg[4], args<6?"":arg[5]); #endif else Con_Printf("Particle effect token not recognised, or invalid args: %s %s %s %s %s %s\n", arg[0], args<2?"":arg[1], args<3?"":arg[2], args<4?"":arg[3], args<5?"":arg[4], args<6?"":arg[5]); @@ -3940,14 +3940,15 @@ static void PScript_RunParticleEffect4 (vec3_t org, float radius, int color, int } } -static void PScript_RunParticleCube(vec3_t minb, vec3_t maxb, vec3_t dir, float count, int colour, qboolean gravity, float jitter) +static void PScript_RunParticleCube(int ptype, vec3_t minb, vec3_t maxb, vec3_t dir_min, vec3_t dir_max, float count, int colour, qboolean gravity, float jitter) { vec3_t org; int i, j; float num; float invcount; - int ptype = P_FindParticleType(va("te_cube%s_%i", gravity?"_g":"", colour)); + if (ptype < 0) + ptype = P_FindParticleType(va("te_cube%s_%i", gravity?"_g":"", colour)); if (ptype < 0) { ptype = P_FindParticleType(va("te_cube%s", gravity?"_g":"")); @@ -3970,7 +3971,7 @@ static void PScript_RunParticleCube(vec3_t minb, vec3_t maxb, vec3_t dir, float num = rand() / (float)RAND_MAX; org[j] = minb[j] + num*(maxb[j]-minb[j]); } - P_RunParticleEffectType(org, dir, invcount, ptype); + P_RunParticleEffectType(org, dir_min, invcount, ptype); } } diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 06c87aeba..b9f0121ee 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -1167,14 +1167,14 @@ void QCBUILTIN PF_R_PolygonEnd(pubprogfuncs_t *prinst, struct globalvars_s *pr_g qboolean csqc_rebuildmatricies; float csqc_proj_matrix[16]; float csqc_proj_matrix_inverse[16]; -void V_ApplyAFov(void); +void V_ApplyAFov(playerview_t *pv); void buildmatricies(void) { float modelview[16]; float proj[16]; + float ofovx = r_refdef.fov_x,ofovy=r_refdef.fov_y; - if (r_refdef.dirty & RDFD_FOV) - V_ApplyAFov(); + V_ApplyAFov(csqc_playerview); /*build modelview and projection*/ Matrix4x4_CM_ModelViewMatrix(modelview, r_refdef.viewangles, r_refdef.vieworg); @@ -1187,6 +1187,9 @@ void buildmatricies(void) Matrix4_Invert(csqc_proj_matrix, csqc_proj_matrix_inverse); csqc_rebuildmatricies = false; + + r_refdef.fov_x = ofovx, + r_refdef.fov_y = ofovy; } static void QCBUILTIN PF_cs_project (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -2104,6 +2107,31 @@ static void QCBUILTIN PF_cs_setsensativityscaler (pubprogfuncs_t *prinst, struct in_sensitivityscale = G_FLOAT(OFS_PARM0); } +static void QCBUILTIN PF_cs_boxparticles(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int effectnum = CL_TranslateParticleFromServer(G_FLOAT(OFS_PARM0)); + csqcedict_t *ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM1); + float *org_from = G_VECTOR(OFS_PARM2); + float *org_to = G_VECTOR(OFS_PARM3); + float *vel_from = G_VECTOR(OFS_PARM4); + float *vel_to = G_VECTOR(OFS_PARM5); + float count = G_FLOAT(OFS_PARM6); + int flags = (prinst->callargc < 7)?0:G_FLOAT(OFS_PARM7); + + if (flags & 128) + { + flags &= ~128; + P_ParticleTrail(org_from, org_to, effectnum, 0, NULL); + } + else + { + P_RunParticleCube(effectnum, org_from, org_to, vel_from, vel_to, count, 0, true, 0); + } + + if (flags) + Con_DPrintf("PF_cs_boxparticles: flags & %x is not supported\n", flags); +} + static void QCBUILTIN PF_cs_pointparticles (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { int effectnum = G_FLOAT(OFS_PARM0); @@ -3295,7 +3323,7 @@ static void QCBUILTIN PF_cl_te_particlecube (pubprogfuncs_t *prinst, struct glob float gravity = G_FLOAT(OFS_PARM5); float jitter = G_FLOAT(OFS_PARM6); - P_RunParticleCube(minb, maxb, vel, howmany, color, gravity, jitter); + P_RunParticleCube(P_INVALID, minb, maxb, vel, vel, howmany, color, gravity, jitter); } static void QCBUILTIN PF_cl_te_spark (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -4111,7 +4139,31 @@ static void QCBUILTIN PF_getentity(pubprogfuncs_t *prinst, struct globalvars_s * } } +static void QCBUILTIN PF_V_CalcRefdef(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + csqcedict_t *ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0); + extern cvar_t cl_forcesplitclient; + Con_DPrintf("Warning: V_CalcRefdef (builtin 640) not implemented.\n"); +// if (ent->xv->entnum >= 1 && ent->xv->entnum <= MAX_CLIENTS) +// CSQC_ChangeLocalPlayer(ent->xv->entnum-1); + csqc_rebuildmatricies = true; + + CL_DecayLights (); + +#if defined(SKELETALOBJECTS) || defined(RAGDOLLS) + skel_dodelete(csqcprogs); +#endif + CL_ClearEntityLists(); + + V_ClearRefdef(csqc_playerview); + r_refdef.drawsbar = false; //csqc defaults to no sbar. + csqc_addcrosshair = false; + + VectorCopy(ent->v->origin, csqc_playerview->simorg); + + V_CalcRefdef(csqc_playerview); //set up the defaults +} #if 1 //static void QCBUILTIN PF_ReadServerEntityState(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -4276,9 +4328,6 @@ static void QCBUILTIN PF_ReadServerEntityState(pubprogfuncs_t *prinst, struct gl //PF_cs_ - works in csqc only (dependant upon globals or fields) //PF_cl_ - works in csqc and menu (if needed...) -//these are the builtins that still need to be added. -#define PS_cs_setattachment PF_Fixme - //warning: functions that depend on globals are bad, mkay? static struct { char *name; @@ -4466,7 +4515,7 @@ static struct { {"shaderforname", PF_shaderforname, 238}, // #238 {"te_bloodqw", PF_cl_te_bloodqw, 239}, // #239 void te_bloodqw(vector org[, float count]) (FTE_TE_STANDARDEFFECTBUILTINS) -// {"checkpvs", PF_checkpvs, 240}, + {"checkpvs", PF_checkpvs, 240}, // {"matchclientname", PF_matchclient, 241}, {"sendpacket", PF_NoCSQC, 242}, //void(string dest, string content) sendpacket = #242; (FTE_QC_SENDPACKET) @@ -4694,7 +4743,7 @@ static struct { {"clientcommand", PF_NoCSQC, 440}, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND) (don't implement) {"tokenize", PF_Tokenize, 441}, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND) {"argv", PF_ArgV, 442}, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND) - {"setattachment", PS_cs_setattachment,443}, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS) + {"setattachment", PF_setattachment, 443}, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS) {"search_begin", PF_search_begin, 444}, // #444 float search_begin(string pattern, float caseinsensitive, float quiet) (DP_QC_FS_SEARCH) {"search_end", PF_search_end, 445}, // #445 void search_end(float handle) (DP_QC_FS_SEARCH) @@ -4799,7 +4848,7 @@ static struct { //DP_SV_WRITEPICTURE {"WritePicture", PF_ReadPicture, 501}, // #501 void(float to, string s, float sz) WritePicture -// {"boxparticles", PF_Fixme, 502}, + {"boxparticles", PF_cs_boxparticles, 502}, //DP_QC_WHICHPACK {"whichpack", PF_whichpack, 503}, // #503 string(string filename) whichpack @@ -4872,7 +4921,8 @@ static struct { {"getbindmaps", PF_cl_GetBindMap, 631}, {"setbindmaps", PF_cl_SetBindMap, 632}, - {"digest_hex", PF_digest_hex, 639}, + {"digest_hex", PF_digest_hex, 639}, + {"V_CalcRefdef", PF_V_CalcRefdef, 640}, {NULL} }; @@ -5056,7 +5106,7 @@ void CSQC_Shutdown(void) { key_dest_absolutemouse &= ~kdm_game; CSQC_ForgetThreads(); - PR_ResetFonts(true); + PR_ResetFonts(kdm_game); PR_Common_Shutdown(csqcprogs, false); csqcprogs->CloseProgs(csqcprogs); } @@ -5695,6 +5745,46 @@ void CSQC_CvarChanged(cvar_t *var) } } +//evil evil function. calling qc from inside the renderer is BAD. +qboolean CSQC_SetupToRenderPortal(int entkeynum) +{ +#ifdef TEXTEDITOR + extern qboolean editormodal; + if (editormodal) + return false; +#endif + + if (csqcprogs && entkeynum < 0) + { + csqcedict_t *e = (void*)EDICT_NUM(csqcprogs, -entkeynum); + if (e->xv->camera_transform) + { + int oself = *csqcg.self; + void *pr_globals = PR_globals(csqcprogs, PR_CURRENT); + + *csqcg.self = EDICT_TO_PROG(csqcprogs, e); + VectorCopy(r_refdef.vieworg, G_VECTOR(OFS_PARM0)); + VectorAngles(vpn, vup, G_VECTOR(OFS_PARM1)); + VectorCopy(vpn, csqcg.forward); + VectorCopy(vright, csqcg.right); + VectorCopy(vup, csqcg.up); + VectorCopy(r_refdef.vieworg/*r_refdef.pvsorigin*/, csqcg.trace_endpos); + + PR_ExecuteProgram (csqcprogs, e->xv->camera_transform); + + VectorCopy(csqcg.forward, vpn); + VectorCopy(csqcg.right, vright); + VectorCopy(csqcg.up, vup); + VectorCopy(G_VECTOR(OFS_RETURN), r_refdef.vieworg); + VectorCopy(csqcg.trace_endpos, r_refdef.pvsorigin); + + *csqcg.self = oself; + return true; + } + } + return false; +} + qboolean CSQC_DrawView(void) { int ticlimit = 10; @@ -6304,10 +6394,10 @@ void CSQC_ParseEntities(void) if (msg_readcount != packetstart+packetsize) { if (msg_readcount > packetstart+packetsize) - Con_Printf("CSQC overread entity %i. Size %i, read %i\n", entnum, packetsize, msg_readcount - packetsize); + Con_Printf("CSQC overread entity %i. Size %i, read %i", entnum, packetsize, msg_readcount - packetstart); else - Con_Printf("CSQC underread entity %i. Size %i, read %i\n", entnum, packetsize, msg_readcount - packetsize); - Con_Printf("First byte is %i\n", net_message.data[msg_readcount]); + Con_Printf("CSQC underread entity %i. Size %i, read %i", entnum, packetsize, msg_readcount - packetstart); + Con_Printf(", first byte is %i(%x)\n", net_message.data[msg_readcount], net_message.data[msg_readcount]); #ifndef CLIENTONLY if (sv.state) { diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index c8dd909f0..004b70702 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -68,23 +68,24 @@ void QCBUILTIN PF_CL_drawresetcliparea (pubprogfuncs_t *prinst, struct globalvar } #define FONT_SLOTS 16 -#define FONT_SIZES 4 +#define FONT_SIZES 16 struct { + unsigned int owner; //kdm_foo. whoever has an interest in this font. font is purged when this becomes 0. char slotname[16]; - char facename[64]; + char facename[MAX_OSPATH]; int sizes; - int size[4]; - struct font_s *font[4]; + int size[FONT_SIZES]; + struct font_s *font[FONT_SIZES]; } fontslot[FONT_SLOTS]; -static struct font_s *PR_CL_ChooseFont(world_t *world, float szx, float szy) +struct font_s *PR_CL_ChooseFont(float *fontsel, float szx, float szy) { int fontidx = 0; //default by default... - struct font_s *font = font_conchar; + struct font_s *font = font_default; - if (world->g.drawfont) + if (fontsel) { - fontidx = *world->g.drawfont; + fontidx = *fontsel; } if (fontidx >= 0 && fontidx < FONT_SLOTS) @@ -106,7 +107,7 @@ static struct font_s *PR_CL_ChooseFont(world_t *world, float szx, float szy) void PR_CL_BeginString(pubprogfuncs_t *prinst, float vx, float vy, float szx, float szy, float *px, float *py) { world_t *world = prinst->parms->user; - struct font_s *font = PR_CL_ChooseFont(world, szx, szy); + struct font_s *font = PR_CL_ChooseFont(world->g.drawfont, szx, szy); if (world->g.drawfontscale && (world->g.drawfontscale[0] || world->g.drawfontscale[1])) { szx *= world->g.drawfontscale[0]; @@ -135,11 +136,18 @@ int PR_findnamedfont(char *name, qboolean isslotname) } return -1; } -void PR_ResetFonts(qboolean purge) +//purgeowner 0 will reload all fonts. other values will purge only fonts which are now unused. +void PR_ResetFonts(unsigned int purgeowner) { int i, j; for (i = 0; i < FONT_SLOTS; i++) { + fontslot[i].owner &= ~purgeowner; + + //don't bother flushing fonts when we don't really need to. + if (fontslot[i].owner && purgeowner) + return; + for (j = 0; j < fontslot[i].sizes; j++) { if (fontslot[i].font[j]) @@ -147,16 +155,22 @@ void PR_ResetFonts(qboolean purge) fontslot[i].font[j] = NULL; } - if (purge) + //if noone is interested in it now, it can be purged fully. + if (!fontslot[i].owner) { fontslot[i].sizes = 0; fontslot[i].slotname[0] = '\0'; fontslot[i].facename[0] = '\0'; } else - { + { //otherwise load it. for (j = 0; j < fontslot[i].sizes; j++) - fontslot[i].font[j] = Font_LoadFont(fontslot[i].size[j], fontslot[i].facename); + { + if (qrenderer == QR_NONE) + fontslot[i].font[j] = NULL; + else + fontslot[i].font[j] = Font_LoadFont(fontslot[i].size[j], fontslot[i].facename); + } } } } @@ -174,6 +188,7 @@ void QCBUILTIN PF_CL_loadfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_g //float fix_scale = G_FLOAT(OFS_PARM4); //float fix_voffset = G_FLOAT(OFS_PARM5); int i, sz; + world_t *world = prinst->parms->user; G_FLOAT(OFS_RETURN) = 0; //return default on failure. @@ -200,7 +215,9 @@ void QCBUILTIN PF_CL_loadfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_g Font_Free(fontslot[slotnum].font[i]); fontslot[slotnum].font[i] = NULL; } + fontslot[slotnum].owner = 0; } + fontslot[slotnum].owner |= world->keydestmask; while(*sizestr) { @@ -216,13 +233,113 @@ void QCBUILTIN PF_CL_loadfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_g if (i >= FONT_SIZES) break; fontslot[slotnum].size[i] = sz; - fontslot[slotnum].font[i] = Font_LoadFont(fontslot[slotnum].size[i], facename); + if (qrenderer == QR_NONE) + fontslot[slotnum].font[i] = NULL; + else + fontslot[slotnum].font[i] = Font_LoadFont(fontslot[slotnum].size[i], facename); fontslot[slotnum].sizes++; } } G_FLOAT(OFS_RETURN) = slotnum; } +void CL_LoadFont_f(void) +{ + //console command for compat with dp/debug. + if (Cmd_Argc() == 1) + { + int i, j; + for (i = 0; i < FONT_SLOTS; i++) + { + if (fontslot[i].sizes) + { + Con_Printf("%s: %s (", fontslot[i].slotname, fontslot[i].facename); + for (j = 0; j < fontslot[i].sizes; j++) + { + if (j) + Con_Printf(", ", fontslot[i].size[j]); + Con_Printf("%i", fontslot[i].size[j]); + } + Con_Printf(")\n"); + } + } + } + else + { + int i; + int slotnum = 0; + char *slotname = Cmd_Argv(1); + char *facename = Cmd_Argv(2); + int sizenum = 3; + + //loadfont slot face size1 size2... + + slotnum = PR_findnamedfont(slotname, true); + if (slotnum < 0) + { + char *dpnames[] = {"default", "console", "sbar", "notify", "chat", "centerprint", "infobar", "menu", "user0", "user1", "user2", "user3", "user4", "user5", "user6", "user7", NULL}; + for (i = 0; dpnames[i]; i++) + { + if (!strcmp(dpnames[i], slotname)) + { + //assign it to this slot only if this slot does not already have a face. avoids corrupting already-loaded fonts. + if (!*fontslot[i].facename) + slotnum = i; + break; + } + } + if (slotnum < 0) + slotnum = PR_findnamedfont("", true); //whatever is still free + } + if (slotnum < 0) + { + Con_Printf("out of font slots\n"); + return; + } + + //if there's a new font in this slot, purge the old and change the name+face strings + if (stricmp(fontslot[slotnum].slotname, slotname) || stricmp(fontslot[slotnum].facename, facename)) + { + Q_strncpyz(fontslot[slotnum].slotname, slotname, sizeof(fontslot[slotnum].slotname)); + Q_strncpyz(fontslot[slotnum].facename, facename, sizeof(fontslot[slotnum].facename)); + for (i = 0; i < fontslot[slotnum].sizes; i++) + { + if (fontslot[slotnum].font[i]) + Font_Free(fontslot[slotnum].font[i]); + fontslot[slotnum].font[i] = NULL; + } + fontslot[slotnum].owner = 0; + } + if (!*facename) + return; + fontslot[slotnum].owner |= kdm_console; //fonts owned by the console are never forgotten. + + while(sizenum < Cmd_Argc()) + { + int sz = atoi(Cmd_Argv(sizenum++)); + if (sz <= 0) + sz = 8; + + for (i = 0; i < fontslot[slotnum].sizes; i++) + { + if (fontslot[slotnum].size[i] == sz) + break; + } + if (i == fontslot[slotnum].sizes) + { + if (i >= FONT_SIZES) + break; + fontslot[slotnum].size[i] = sz; + if (qrenderer == QR_NONE) + fontslot[slotnum].font[i] = NULL; + else + fontslot[slotnum].font[i] = Font_LoadFont(fontslot[slotnum].size[i], facename); + fontslot[slotnum].sizes++; + } + } + } +} + void QCBUILTIN PF_CL_DrawTextField (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { float *pos = G_VECTOR(OFS_PARM0); @@ -696,7 +813,7 @@ void QCBUILTIN PF_SubConDraw (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl fontsize *= world->g.drawfontscale[1]; } - Con_DrawOneConsole(con, PR_CL_ChooseFont(world, fontsize, fontsize), pos[0], pos[1], size[0], size[1]); + Con_DrawOneConsole(con, PR_CL_ChooseFont(world->g.drawfont, fontsize, fontsize), pos[0], pos[1], size[0], size[1]); } qboolean Key_Console (console_t *con, unsigned int unicode, int key); void Key_ConsoleRelease (console_t *con, unsigned int unicode, int key); @@ -1715,7 +1832,7 @@ void MP_Shutdown (void) PR_Common_Shutdown(menu_world.progs, false); menu_world.progs->CloseProgs(menu_world.progs); memset(&menu_world, 0, sizeof(menu_world)); - PR_ResetFonts(true); + PR_ResetFonts(kdm_menu); #ifdef CL_MASTER Master_ClearMasks(); @@ -1960,6 +2077,7 @@ void MP_RegisterCvarsAndCmds(void) Cmd_AddCommand("menu_restart", MP_Reload_f); Cmd_AddCommand("menu_cmd", MP_GameCommand_f); Cmd_AddCommand("breakpoint_menu", MP_Breakpoint_f); + Cmd_AddCommand("loadfont", CL_LoadFont_f); Cvar_Register(&forceqmenu, MENUPROGSGROUP); Cvar_Register(&pr_menuqc_coreonerror, MENUPROGSGROUP); diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index a693430e8..09ce1a822 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -41,6 +41,7 @@ extern cvar_t gl_screenangle; extern cvar_t vid_conautoscale; extern cvar_t vid_conheight; extern cvar_t vid_conwidth; +extern cvar_t con_textsize; void R2D_Font_Callback(struct cvar_s *var, char *oldvalue); void R2D_Conautoscale_Callback(struct cvar_s *var, char *oldvalue); void R2D_ScreenAngle_Callback(struct cvar_s *var, char *oldvalue); @@ -115,9 +116,15 @@ void R2D_Shutdown(void) cl_numstris = 0; cl_maxstris = 0; - if (font_conchar) - Font_Free(font_conchar); - font_conchar = NULL; + if (font_console == font_default) + font_console = NULL; + + if (font_console) + Font_Free(font_console); + font_console = NULL; + if (font_default) + Font_Free(font_default); + font_default = NULL; if (font_tiny) Font_Free(font_tiny); font_tiny = NULL; @@ -659,17 +666,30 @@ void R2D_Font_AddFontLink(char *buffer, int buffersize, char *fontname) } } #endif -void R2D_Font_Callback(struct cvar_s *var, char *oldvalue) +void R2D_Font_Changed(void) { - if (font_conchar) - Font_Free(font_conchar); - font_conchar = NULL; + if (!con_textsize.modified) + return; + con_textsize.modified = false; + + if (font_console == font_default) + font_console = NULL; + if (font_console) + Font_Free(font_console); + font_console = NULL; + if (font_default) + Font_Free(font_default); + font_default = NULL; + +#if defined(MENU_DAT) || defined(CSQC_DAT) + PR_ResetFonts(0); +#endif if (qrenderer == QR_NONE) return; #if defined(_WIN32) && !defined(_SDL) - if (!strcmp(var->string, "?")) + if (!strcmp(gl_font.string, "?")) { BOOL (APIENTRY *pChooseFontA)(LPCHOOSEFONTA) = NULL; dllfunction_t funcs[] = @@ -681,7 +701,11 @@ void R2D_Font_Callback(struct cvar_s *var, char *oldvalue) LOGFONT lf = {0}; CHOOSEFONTA cf = {sizeof(cf)}; extern HWND mainwindow; - font_conchar = Font_LoadFont(8, ""); + font_default = Font_LoadFont(8, ""); + if (con_textsize.ival != 8 && con_textsize.ival >= 1) + font_console = Font_LoadFont(con_textsize.ival, ""); + if (!font_console) + font_console = font_default; cf.hwndOwner = mainwindow; cf.iPointSize = (8 * vid.rotpixelheight)/vid.height; @@ -710,15 +734,29 @@ void R2D_Font_Callback(struct cvar_s *var, char *oldvalue) } R2D_Font_AddFontLink(fname, sizeof(fname), lf.lfFaceName); - Cvar_Set(var, fname); + Cvar_Set(&gl_font, fname); } return; } #endif - font_conchar = Font_LoadFont(8, var->string); - if (!font_conchar && *var->string) - font_conchar = Font_LoadFont(8, ""); + font_default = Font_LoadFont(8, gl_font.string); + if (!font_default && *gl_font.string) + font_default = Font_LoadFont(8, ""); + + if (con_textsize.ival != 8 && con_textsize.ival >= 1) + { + font_console = Font_LoadFont(con_textsize.ival, gl_font.string); + if (!font_console) + font_console = Font_LoadFont(con_textsize.ival, ""); + } + if (!font_console) + font_console = font_default; +} + +void R2D_Font_Callback(struct cvar_s *var, char *oldvalue) +{ + con_textsize.modified = true; } // console size manipulation callbacks @@ -795,19 +833,8 @@ void R2D_Console_Resize(void) vid.width = cwidth; vid.height = cheight; - if (font_tiny) - Font_Free(font_tiny); - font_tiny = NULL; - if (font_conchar) - Font_Free(font_conchar); - font_conchar = NULL; - Cvar_ForceCallback(&gl_font); -#if defined(MENU_DAT) || defined(CSQC_DAT) - PR_ResetFonts(false); -#endif - #ifdef PLUGINS Plug_ResChanged(); #endif @@ -1201,13 +1228,13 @@ void R2D_DrawCrosshair(void) for (sc = 0; sc < cl.splitclients; sc++) { SCR_CrosshairPosition(&cl.playerview[sc], &sx, &sy); - Font_BeginScaledString(font_conchar, sx, sy, size, size, &sx, &sy); + Font_BeginScaledString(font_default, sx, sy, size, size, &sx, &sy); sx -= Font_CharScaleWidth('+' | 0xe000 | CON_WHITEMASK)/2; sy -= Font_CharScaleHeight()/2; Font_ForceColour(ch_color[0], ch_color[1], ch_color[2], crosshairalpha.value); Font_DrawScaleChar(sx, sy, '+' | 0xe000 | CON_WHITEMASK); Font_InvalidateColour(); - Font_EndString(font_conchar); + Font_EndString(font_default); } return; } diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index ae69466a8..3960d83af 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -926,10 +926,10 @@ static void Surf_BuildLightMap (msurface_t *surf, qbyte *dest, qbyte *deluxdest, } else if (!currentmodel->lightdata) { - /*fullbright if map is not lit*/ + /*fullbright if map is not lit. but not overbright*/ for (i=0 ; isamples) @@ -1887,26 +1887,73 @@ start: } #endif -static void Surf_CleanChains(void) +static void Surf_PushChains(model_t *model) { - model_t *model = cl.worldmodel; batch_t *batch; int i; - if (r_refdef.recurse) + if (r_refdef.recurse == R_MAX_RECURSE) + Sys_Error("Recursed too deep\n"); + + if (!r_refdef.recurse) + { + for (i = 0; i < SHADER_SORT_COUNT; i++) + for (batch = model->batches[i]; batch; batch = batch->next) + { + batch->firstmesh = 0; + } + } +#if R_MAX_RECURSE > 2 + else if (r_refdef.recurse > 1) + { + for (i = 0; i < SHADER_SORT_COUNT; i++) + for (batch = model->batches[i]; batch; batch = batch->next) + { + batch->recursefirst[r_refdef.recurse] = batch->firstmesh; + batch->firstmesh = batch->meshes; + } + } +#endif + else + { + for (i = 0; i < SHADER_SORT_COUNT; i++) + for (batch = model->batches[i]; batch; batch = batch->next) + { + batch->firstmesh = batch->meshes; + } + } +} +static void Surf_PopChains(model_t *model) +{ + batch_t *batch; + int i; + + if (!r_refdef.recurse) + { + for (i = 0; i < SHADER_SORT_COUNT; i++) + for (batch = model->batches[i]; batch; batch = batch->next) + { + batch->meshes = 0; + } + } +#if R_MAX_RECURSE > 2 + else if (r_refdef.recurse > 1) { for (i = 0; i < SHADER_SORT_COUNT; i++) for (batch = model->batches[i]; batch; batch = batch->next) { batch->meshes = batch->firstmesh; + batch->firstmesh = batch->recursefirst[r_refdef.recurse]; } } +#endif else { for (i = 0; i < SHADER_SORT_COUNT; i++) for (batch = model->batches[i]; batch; batch = batch->next) { batch->meshes = batch->firstmesh; + batch->firstmesh = 0; } } } @@ -2191,6 +2238,9 @@ void Surf_GenBrushBatches(batch_t **batches, entity_t *ent) if (b->buildmeshes) b->buildmeshes(b); + if (!b->shader) + b->shader = R_TextureAnimation(ent->framestate.g[FS_REG].frame[0], b->texture)->shader; + if (bef & BEF_FORCEADDITIVE) { b->next = batches[SHADER_SORT_ADDITIVE]; @@ -2244,6 +2294,8 @@ void Surf_DrawWorld (void) Surf_LightmapShift(cl.worldmodel); + Surf_PushChains(cl.worldmodel); + #ifdef Q2BSPS if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3) { @@ -2337,7 +2389,7 @@ void Surf_DrawWorld (void) if (cl.worldmodel->fromgame == fg_quake || cl.worldmodel->fromgame == fg_halflife) Surf_LessenStains(); - Surf_CleanChains(); + Surf_PopChains(cl.worldmodel); } } @@ -2589,7 +2641,11 @@ void Surf_BuildModelLightmaps (model_t *m) shift = Surf_LightmapShift(currentmodel); if (*m->name == '*' && m->fromgame == fg_quake3) //FIXME: should be all bsp formats + { + if (!cl.model_precache[1] || cl.model_precache[1]->needload) + return; newfirst = cl.model_precache[1]->lightmaps.first; + } else { if (!m->lightdata && m->lightmaps.count && m->fromgame == fg_quake3) @@ -2758,6 +2814,8 @@ void Surf_BuildLightmaps (void) m = cl.model_precache[j]; if (!m) break; + if (m->needload) + continue; Surf_BuildModelLightmaps(m); } for (j=1 ; jfrags; \ sprintf(num, "%3i",f); \ \ - Font_BeginString(font_conchar, x+8, y, &cx, &cy); \ + Font_BeginString(font_default, x+8, y, &cx, &cy); \ Font_DrawChar(cx, cy, num[0] | 0xe000 | CON_WHITEMASK); \ - Font_BeginString(font_conchar, x+16, y, &cx, &cy); \ + Font_BeginString(font_default, x+16, y, &cx, &cy); \ Font_DrawChar(cx, cy, num[1] | 0xe000 | CON_WHITEMASK); \ - Font_BeginString(font_conchar, x+24, y, &cx, &cy); \ + Font_BeginString(font_default, x+24, y, &cx, &cy); \ Font_DrawChar(cx, cy, num[2] | 0xe000 | CON_WHITEMASK); \ \ if ((cl.spectator && k == Cam_TrackNum(pv)) ||\ (!cl.spectator && k == pv->playernum)) \ { \ - Font_BeginString(font_conchar, x, y, &cx, &cy); \ + Font_BeginString(font_default, x, y, &cx, &cy); \ Font_DrawChar(cx, cy, 16 | 0xe000 | CON_WHITEMASK); \ - Font_BeginString(font_conchar, x+32, y, &cx, &cy); \ + Font_BeginString(font_default, x+32, y, &cx, &cy); \ Font_DrawChar(cx, cy, 17 | 0xe000 | CON_WHITEMASK); \ } \ - Font_EndString(font_conchar); \ + Font_EndString(font_default); \ } \ }) #define COLUMN_TEAMNAME COLUMN(team, 4*8, \ @@ -3226,19 +3226,19 @@ static void Sbar_MiniDeathmatchOverlay (playerview_t *pv) f = s->frags; sprintf (num, "%3i",f); - Font_BeginString(font_conchar, x+8, y, &px, &py); + Font_BeginString(font_default, x+8, y, &px, &py); Font_DrawChar ( px, py, num[0] | 0xe000 | CON_WHITEMASK); - Font_BeginString(font_conchar, x+16, y, &px, &py); + Font_BeginString(font_default, x+16, y, &px, &py); Font_DrawChar ( px, py, num[1] | 0xe000 | CON_WHITEMASK); - Font_BeginString(font_conchar, x+24, y, &px, &py); + Font_BeginString(font_default, x+24, y, &px, &py); Font_DrawChar ( px, py, num[2] | 0xe000 | CON_WHITEMASK); if ((cl.spectator && k == pv->cam_spec_track) || (!cl.spectator && k == pv->playernum)) { - Font_BeginString(font_conchar, x, y, &px, &py); + Font_BeginString(font_default, x, y, &px, &py); Font_DrawChar ( px, py, 16 | 0xe000 | CON_WHITEMASK); - Font_BeginString(font_conchar, x+32, y, &px, &py); + Font_BeginString(font_default, x+32, y, &px, &py); Font_DrawChar ( px, py, 17 | 0xe000 | CON_WHITEMASK); } @@ -3280,11 +3280,11 @@ static void Sbar_MiniDeathmatchOverlay (playerview_t *pv) if (!strncmp(cl.players[pv->playernum].team, tm->team, 16)) { - Font_BeginString(font_conchar, x-8, y, &px, &py); + Font_BeginString(font_default, x-8, y, &px, &py); Font_DrawChar(px, py, 16|0xe000|CON_WHITEMASK); - Font_BeginString(font_conchar, x+32, y, &px, &py); + Font_BeginString(font_default, x+32, y, &px, &py); Font_DrawChar(px, py, 17|0xe000|CON_WHITEMASK); - Font_EndString(font_conchar); + Font_EndString(font_default); } y += 8; diff --git a/engine/client/screen.h b/engine/client/screen.h index 004d7e650..c2e00b8e3 100644 --- a/engine/client/screen.h +++ b/engine/client/screen.h @@ -115,9 +115,10 @@ int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int max int Font_LineWidth(conchar_t *start, conchar_t *end); float Font_LineScaleWidth(conchar_t *start, conchar_t *end); void Font_LineDraw(int x, int y, conchar_t *start, conchar_t *end); -extern struct font_s *font_conchar; +extern struct font_s *font_default; +extern struct font_s *font_console; extern struct font_s *font_tiny; -void PR_ResetFonts(qboolean purge); //for menu/csqc +void PR_ResetFonts(unsigned int purgeowner); //for menu/csqc /*end fonts*/ void R_NetgraphInit(void); diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index bb76f8eea..e07aced40 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -1592,7 +1592,7 @@ static soundcardinfo_t *SNDDMA_Init(char *driver, char *device) { //if the sample speeds of multiple soundcards do not match, it'll fail. if (snd_speed != sc->sn.speed) { - Con_Printf("S_Startup: Ignoring soundcard %s due to mismatched sample speeds.\n", sc->name); + Con_TPrintf("S_Startup: Ignoring soundcard %s due to mismatched sample speeds.\n", sc->name); S_ShutdownCard(sc); continue; } @@ -1624,7 +1624,7 @@ static soundcardinfo_t *SNDDMA_Init(char *driver, char *device) { //if the sample speeds of multiple soundcards do not match, it'll fail. if (snd_speed != sc->sn.speed) { - Con_Printf("S_Startup: Ignoring soundcard %s due to mismatched sample speeds.\nTry running Quake with -singlesound to use just the primary soundcard\n", sc->name); + Con_TPrintf("S_Startup: Ignoring soundcard %s due to mismatched sample speeds.\nTry running Quake with -singlesound to use just the primary soundcard\n", sc->name); S_ShutdownCard(sc); continue; } @@ -1640,7 +1640,10 @@ static soundcardinfo_t *SNDDMA_Init(char *driver, char *device) } Z_Free(sc); - Con_Printf("Could not start \"%s\" device \"%s\"\n", driver?driver:"audio", device?device:"default"); + if (!driver) + Con_TPrintf("Could not start audio device \"%s\"\n", device?device:"default"); + else + Con_TPrintf("Could not start \"%s\" device \"%s\"\n", driver, device?device:"default"); return NULL; } diff --git a/engine/client/spritegn.h b/engine/client/spritegn.h index 8b66928f2..1514648f2 100644 --- a/engine/client/spritegn.h +++ b/engine/client/spritegn.h @@ -73,6 +73,7 @@ typedef struct { int ident; int version; int type; + //int rendermode; //present only in halflife sprites. float boundingradius; int width; int height; @@ -81,11 +82,19 @@ typedef struct { synctype_t synctype; } dsprite_t; -#define SPR_VP_PARALLEL_UPRIGHT 0 -#define SPR_FACING_UPRIGHT 1 -#define SPR_VP_PARALLEL 2 -#define SPR_ORIENTED 3 -#define SPR_VP_PARALLEL_ORIENTED 4 +#define SPR_VP_PARALLEL_UPRIGHT 0 //xy faces view. z is always up. +#define SPR_FACING_UPRIGHT 1 //xy faces view. z is always up. +#define SPR_VP_PARALLEL 2 //faces camera (traditional sprite) +#define SPR_ORIENTED 3 //uses axis +#define SPR_VP_PARALLEL_ORIENTED 4 //faces camera *then* rotated +#define SPRDP_LABEL 5 +#define SPRDP_LABEL_SCALE 6 +#define SPRDP_OVERHEAD 7 + +#define SPRHL_OPAQUE 0 +#define SPRHL_ADDITIVE 1 +#define SPRHL_INDEXALPHA 2 +#define SPRHL_ALPHATEST 3 typedef struct { int origin[2]; diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index 84770ce14..e860da157 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -852,11 +852,8 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart } if (match[nest] == '/') { - char utf8[MAX_OSPATH]; - wchar_t wroot[MAX_OSPATH]; char submatch[MAX_OSPATH]; char tmproot[MAX_OSPATH]; - char file[MAX_OSPATH]; if (!wild) return Sys_EnumerateFiles2(match, matchstart, nest+1, func, parm, spath); @@ -872,13 +869,18 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart memcpy(tmproot, match, neststart); strcpy(tmproot+neststart, "*.*"); - r = FindFirstFileW(widen(wroot, sizeof(wroot), tmproot), &fd); + { + wchar_t wroot[MAX_OSPATH]; + r = FindFirstFileW(widen(wroot, sizeof(wroot), tmproot), &fd); + } strcpy(tmproot+neststart, ""); if (r==(HANDLE)-1) return 1; go = true; do { + char utf8[MAX_OSPATH]; + char file[MAX_OSPATH]; narrowen(utf8, sizeof(utf8), fd.cFileName); if (*utf8 == '.'); //don't ever find files with a name starting with '.' else if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //is a directory @@ -902,22 +904,25 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart { const char *submatch = match + neststart; char tmproot[MAX_OSPATH]; - wchar_t wroot[MAX_OSPATH]; - char utf8[MAX_OSPATH]; - char file[MAX_OSPATH]; if (neststart+4 > MAX_OSPATH) return 1; memcpy(tmproot, match, neststart); strcpy(tmproot+neststart, "*.*"); - r = FindFirstFileW(widen(wroot, sizeof(wroot), tmproot), &fd); + { + wchar_t wroot[MAX_OSPATH]; + r = FindFirstFileW(widen(wroot, sizeof(wroot), tmproot), &fd); + } strcpy(tmproot+neststart, ""); if (r==(HANDLE)-1) return 1; go = true; do { + char utf8[MAX_OSPATH]; + char file[MAX_OSPATH]; + narrowen(utf8, sizeof(utf8), fd.cFileName); if (*utf8 == '.') ; //don't ever find files with a name starting with '.' (includes .. and . directories, and unix hidden files) diff --git a/engine/client/textedit.c b/engine/client/textedit.c index 5ee15c725..ca081c19c 100644 --- a/engine/client/textedit.c +++ b/engine/client/textedit.c @@ -909,7 +909,7 @@ static void Draw_Line(int vy, fileblock_t *b, int cursorx) else c = NULL; - Font_BeginString(font_conchar, nx, vy, &nx, &y); + Font_BeginString(font_default, nx, vy, &nx, &y); if (ts < 1) ts = 4; @@ -946,7 +946,7 @@ static void Draw_Line(int vy, fileblock_t *b, int cursorx) nnx-=(nnx - -viewportx)%ts; } else - nnx = Font_CharEndCoord(font_conchar, nx, (int)d[i] | (colour)); + nnx = Font_CharEndCoord(font_default, nx, (int)d[i] | (colour)); if (smx >= nx && smx <= nnx) { @@ -1048,14 +1048,14 @@ static void Draw_Line(int vy, fileblock_t *b, int cursorx) { if (*tooltip == '\n') break; - smx = Font_CharEndCoord(font_conchar, smx, *tooltip); + smx = Font_CharEndCoord(font_default, smx, *tooltip); } y = Font_CharHeight(); - Font_EndString(font_conchar); + Font_EndString(font_default); R2D_ImageColours(0, 0, 0, 1); R2D_FillBlock(((nx)*vid.width) / vid.pixelwidth, ((smy)*vid.height) / vid.pixelheight, ((smx - nx)*vid.width) / vid.pixelwidth, (y*vid.height) / vid.pixelheight); R2D_ImageColours(1, 1, 1, 1); - Font_BeginString(font_conchar, nx, vy, &y, &y); + Font_BeginString(font_default, nx, vy, &y, &y); for(smx = nx; t < tooltip; t++) { smx = Font_DrawChar(smx, smy, (COLOR_CYAN<bob = sqrt(pv->simvel[0]*pv->simvel[0] + pv->simvel[1]*pv->simvel[1]) * cl_bob.value; - pv->bob = pv->bob*0.3 + pv->bob*0.7*sin(cycle); - if (pv->bob > 4) - pv->bob = 4; - else if (pv->bob < -7) - pv->bob = -7; + hspeed = DotProduct(pv->simvel, pv->gravitydir); + VectorMA(pv->simvel, hspeed, pv->gravitydir, hvel); + hspeed = VectorLength(hvel); + hspeed = bound(0, hspeed, 400); + bob = hspeed * bound(0, cl_bob.value, 0.05); + pv->bob = bob*0.3 + bob*0.7*sin(cycle); return pv->bob; } @@ -1028,7 +1028,7 @@ float CalcFov (float fov_x, float width, float height) return a; } -void V_ApplyAFov(void) +void V_ApplyAFov(playerview_t *pv) { //explicit fov overrides aproximate fov. //aproximate fov is our regular fov value. explicit is settable by gamecode for weird aspect ratios @@ -1040,8 +1040,8 @@ void V_ApplyAFov(void) float afov = r_refdef.afov; if (!afov) //make sure its sensible. afov = scr_fov.value; - if (r_refdef.playerview->stats[STAT_VIEWZOOM]) - afov *= r_refdef.playerview->stats[STAT_VIEWZOOM]/255.0f; + if (pv && pv->stats[STAT_VIEWZOOM]) + afov *= pv->stats[STAT_VIEWZOOM]/255.0f; ws = 1; if (r_stereo_method.ival == 5 && r_stereo_separation.value) @@ -1152,7 +1152,7 @@ void V_ApplyRefdef (void) r_refdef.vrect.y += r_refdef.grect.y; if (r_refdef.dirty & RDFD_FOV) - V_ApplyAFov(); + V_ApplyAFov(r_refdef.playerview); r_refdef.dirty = 0; } diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index dcfe7aec1..c50ffa31e 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -97,6 +97,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #define AVAIL_OPENAL + #define AVAIL_FREETYPE #if !defined(NO_DIRECTX) && !defined(NODIRECTX) && defined(_WIN32) #define AVAIL_DINPUT @@ -132,7 +133,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. //#define BOTLIB_STATIC #endif -#define AVAIL_FREETYPE #ifdef _WIN32 //needs testing on other platforms //#define AVAIL_OPENAL @@ -160,8 +160,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #undef AVAIL_FREETYPE #endif -//#define AVAIL_FREETYPE - //set any additional defines or libs in win32 #define SVRANKING diff --git a/engine/common/bspfile.h b/engine/common/bspfile.h index d9adbf965..905fc26c9 100644 --- a/engine/common/bspfile.h +++ b/engine/common/bspfile.h @@ -30,13 +30,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. //#define MAX_MAP_ENTITIES 1024 //#define MAX_MAP_ENTSTRING 65536 -#define MAX_MAP_PLANES 65636*2 //sanity (used by q2) -#define SANITY_MAX_MAP_NODES 65535 //sanity -#define SANITY_MAX_MAP_CLIPNODES 65535 //sanity -#define MAX_MAP_LEAFS 65535 //pvs buffer size. not sanity. -#define SANITY_MAX_MAP_VERTS 65535 //sanity -#define SANITY_MAX_MAP_FACES 65535 //sanity -//#define MAX_MAP_MARKSURFACES 65535 //sanity +#define MAX_MAP_PLANES 65536*2 //sanity (used by q2) +#define SANITY_MAX_MAP_NODES 65536 //sanity +#define SANITY_MAX_MAP_CLIPNODES 65536 //sanity +#define MAX_MAP_LEAFS 65536 //pvs buffer size. not sanity. +#define SANITY_MAX_MAP_VERTS 65536 //sanity +#define SANITY_MAX_MAP_FACES 65536 //sanity +//#define MAX_MAP_MARKSURFACES 65536 //sanity //#define MAX_MAP_TEXINFO 4096 //sanity #define MAX_MAP_EDGES 256000 //#define MAX_MAP_SURFEDGES 512000 diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 09a38d518..b3e0ea79d 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -2094,7 +2094,7 @@ void Cmd_ExecuteString (char *text, int level) return; } #endif - if (cl_warncmd.value || developer.value) + if ((cl_warncmd.value && level <= RESTRICT_LOCAL) || developer.value) Con_TPrintf ("Unknown command \"%s\"\n", Cmd_Argv(0)); } diff --git a/engine/common/common.c b/engine/common/common.c index 973e3ed1b..c2967c068 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -2062,7 +2062,7 @@ unsigned int utf8_decode(int *error, const void *in, char **out) if (*error == 4) { *out = lowend; - uc = (((uc&0x3ffu) << 10) || (lowsur&0x3ffu)) + 0x10000; + uc = (((uc&0x3ffu) << 10) | (lowsur&0x3ffu)) + 0x10000; *error = false; } else @@ -2115,7 +2115,7 @@ unsigned int unicode_decode(int *error, const void *in, char **out) { //quake *error = 0; charcode = *(unsigned char*)in; - if (charcode != '\n' && charcode != '\t' && charcode != '\r' && (charcode < ' ' || charcode > 127)) + if (charcode && charcode != '\n' && charcode != '\t' && charcode != '\r' && (charcode < ' ' || charcode > 127)) charcode |= 0xe000; *out = (char*)in + 1; } @@ -2856,6 +2856,27 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t continue; } } + else if (str[1] == 'x') //RGB colours + { + if (ishexcode(str[2]) && ishexcode(str[3]) && ishexcode(str[4])) + { + int r, g, b; + r = dehex(str[2]); + g = dehex(str[3]); + b = dehex(str[4]); + + ext = (ext & ~CON_RICHFOREMASK) | CON_RICHFORECOLOUR; + ext |= r<= '0' && x <= '9') || (x >= 'A' && x <= 'F') || x == '-') #define ishexcode(x) ((x >= '0' && x <= '9') || (x >= 'A' && x <= 'F') || (x >= 'a' && x <= 'f')) diff --git a/engine/common/fs.c b/engine/common/fs.c index 9825af936..d2509921f 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -3504,8 +3504,8 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs) #endif } } - blockcache = false; } + blockcache = false; COM_Effectinfo_Clear(); #ifndef SERVERONLY diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index eefd2a6e9..981b2d746 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -294,7 +294,7 @@ static int numplanes; static mplane_t map_planes[MAX_Q2MAP_PLANES+6]; // extra for box hull static int numleafs = 1; // allow leaf funcs to be called without a map -static mleaf_t map_leafs[MAX_MAP_LEAFS]; +static mleaf_t map_leafs[(MAX_MAP_LEAFS+7)/8]; static int emptyleaf; static int numleafbrushes; diff --git a/engine/common/particles.h b/engine/common/particles.h index bf306582f..2ee02e3a9 100644 --- a/engine/common/particles.h +++ b/engine/common/particles.h @@ -130,7 +130,7 @@ typedef struct { int (*ParticleTrail) (vec3_t startpos, vec3_t end, int type, int dlkey, trailstate_t **tsk); int (*RunParticleEffectState) (vec3_t org, vec3_t dir, float count, int typenum, trailstate_t **tsk); void (*RunParticleWeather) (vec3_t minb, vec3_t maxb, vec3_t dir, float count, int colour, char *efname); - void (*RunParticleCube) (vec3_t minb, vec3_t maxb, vec3_t dir, float count, int colour, qboolean gravity, float jitter); + void (*RunParticleCube) (int typenum, vec3_t minb, vec3_t maxb, vec3_t dir_min, vec3_t dir_max, float count, int colour, qboolean gravity, float jitter); //typenum may be P_INVALID void (*RunParticleEffect) (vec3_t org, vec3_t dir, int color, int count); void (*RunParticleEffect2) (vec3_t org, vec3_t dmin, vec3_t dmax, int color, int effect, int count); void (*RunParticleEffect3) (vec3_t org, vec3_t box, int color, int effect, int count); diff --git a/engine/common/pmovetst.c b/engine/common/pmovetst.c index efaefc873..52dabe859 100644 --- a/engine/common/pmovetst.c +++ b/engine/common/pmovetst.c @@ -91,6 +91,9 @@ int PM_TransformedModelPointContents (model_t *mod, vec3_t p, vec3_t origin, vec vec3_t p_l, axis[3]; VectorSubtract (p, origin, p_l); + if (!mod->funcs.PointContents) + return FTECONTENTS_EMPTY; + // rotate start and end into the models frame of reference if (angles[0] || angles[1] || angles[2]) { @@ -117,10 +120,12 @@ int PM_PointContents (vec3_t p) physent_t *pe; model_t *pm; + //check world. pm = pmove.physents[0].model; if (!pm || pm->needload) return FTECONTENTS_EMPTY; pc = pm->funcs.PointContents(pm, NULL, p); + //we need this for e2m2 - waterjumping on to plats wouldn't work otherwise. for (num = 1; num < pmove.numphysent; num++) { diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 7f60c0e55..6a21e9cc5 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -305,7 +305,7 @@ void QCBUILTIN PF_getsurfacetexture(pubprogfuncs_t *prinst, struct globalvars_s if (!model || model->type != mod_brush) return; - if (surfnum < 0 || surfnum > model->nummodelsurfaces) + if (surfnum < 0 || surfnum >= model->nummodelsurfaces) return; surfnum += model->firstmodelsurface; surf = &model->surfaces[surfnum]; @@ -598,6 +598,57 @@ void QCBUILTIN PF_getsurfacepointattribute(pubprogfuncs_t *prinst, struct global } } +qbyte qcpvs[(MAX_MAP_LEAFS+7)/8]; +//#240 float(vector viewpos, entity viewee) checkpvs (FTE_QC_CHECKPVS) +//note: this requires a correctly setorigined entity. +void QCBUILTIN PF_checkpvs(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + world_t *world = prinst->parms->user; + float *viewpos = G_VECTOR(OFS_PARM0); + wedict_t *ent = G_WEDICT(prinst, OFS_PARM1); + + if (!world->worldmodel || world->worldmodel->needload) + G_FLOAT(OFS_RETURN) = false; + else + { + //FIXME: Make all alternatives of FatPVS not recalulate the pvs. + //and yeah, this is overkill what with the whole fat thing and all. + world->worldmodel->funcs.FatPVS(world->worldmodel, viewpos, qcpvs, sizeof(qcpvs), false); + + G_FLOAT(OFS_RETURN) = world->worldmodel->funcs.EdictInFatPVS(world->worldmodel, &ent->pvsinfo, qcpvs); + } +} + +void QCBUILTIN PF_setattachment(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + wedict_t *e = G_WEDICT(prinst, OFS_PARM0); + wedict_t *tagentity = G_WEDICT(prinst, OFS_PARM1); + char *tagname = PR_GetStringOfs(prinst, OFS_PARM2); + world_t *world = prinst->parms->user; + + model_t *model; + + int tagidx; + + tagidx = 0; + + if (tagentity != world->edicts && tagname && tagname[0]) + { + model = world->Get_CModel(world, tagentity->v->modelindex); + if (model) + { + tagidx = Mod_TagNumForName(model, tagname); + if (tagidx == 0) + Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", NUM_FOR_EDICT(prinst, e), NUM_FOR_EDICT(prinst, tagentity), tagname, tagname, NUM_FOR_EDICT(prinst, tagentity), model->name); + } + else + Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): Couldn't load model\n", NUM_FOR_EDICT(prinst, e), NUM_FOR_EDICT(prinst, tagentity), tagname); + } + + e->xv->tag_entity = EDICT_TO_PROG(prinst, tagentity); + e->xv->tag_index = tagidx; +} + #ifndef TERRAIN void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -2241,13 +2292,15 @@ void QCBUILTIN PF_chr2str (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa //returns character at position X void QCBUILTIN PF_str2chr (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { + int err; + char *next; char *instr = PR_GetStringOfs(prinst, OFS_PARM0); int ofs = (prinst->callargc>1)?G_FLOAT(OFS_PARM1):0; if (VMUTF8) { if (ofs < 0) - ofs = unicode_charcount(instr, ~0)+ofs; + ofs = unicode_charcount(instr, 1<<30)+ofs; ofs = unicode_byteofsfromcharofs(instr, ofs); } else @@ -2259,7 +2312,7 @@ void QCBUILTIN PF_str2chr (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa if (ofs && (ofs < 0 || ofs > strlen(instr))) G_FLOAT(OFS_RETURN) = '\0'; else - G_FLOAT(OFS_RETURN) = VMUTF8?unicode_decode(NULL, instr+ofs, NULL):(unsigned char)instr[ofs]; + G_FLOAT(OFS_RETURN) = VMUTF8?unicode_decode(&err, instr+ofs, &next):(unsigned char)instr[ofs]; } //FTE_STRINGS @@ -2466,7 +2519,7 @@ void QCBUILTIN PF_substring (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo //UTF-8-FIXME: start+length are chars not bytes... if (VMUTF8) - slen = unicode_charcount(s, ~0); + slen = unicode_charcount(s, 1<<30); else slen = strlen(s); @@ -2506,7 +2559,7 @@ void QCBUILTIN PF_substring (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo void QCBUILTIN PF_strlen(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { if (VMUTF8) - G_FLOAT(OFS_RETURN) = unicode_charcount(PR_GetStringOfs(prinst, OFS_PARM0), ~0); + G_FLOAT(OFS_RETURN) = unicode_charcount(PR_GetStringOfs(prinst, OFS_PARM0), 1<<30); else G_FLOAT(OFS_RETURN) = strlen(PR_GetStringOfs(prinst, OFS_PARM0)); } diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index b4e33d632..78c127e6e 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -193,6 +193,8 @@ void QCBUILTIN PF_getsurfaceclippedpoint(pubprogfuncs_t *prinst, struct globalva void QCBUILTIN PF_getsurfacenumtriangles(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_getsurfacetriangle(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_getsurfacepointattribute(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_checkpvs(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_setattachment(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); #ifndef SKELETALOBJECTS #define PF_gettaginfo PF_Fixme @@ -479,6 +481,7 @@ pbool QDECL ED_CanFree (edict_t *ed); #define SOLID_PHASEH2 5 // hexen2 flag - these ents can be freely walked through or something #define SOLID_CORPSE 5 // non-solid to solid_slidebox entities and itself. #define SOLID_LADDER 20 //dmw. touch on edge, not blocking. Touching players have different physics. Otherwise a SOLID_TRIGGER +#define SOLID_PORTAL 21 //1: traces always use point-size. 2: various movetypes automatically transform entities. 3: traces that impact portal bbox use a union. 4. traces ignore part of the world within the portal's box #define SOLID_PHYSICS_BOX 32 ///< physics object (mins, maxs, mass, origin, axis_forward, axis_left, axis_up, velocity, spinvelocity) #define SOLID_PHYSICS_SPHERE 33 ///< physics object (mins, maxs, mass, origin, axis_forward, axis_left, axis_up, velocity, spinvelocity) #define SOLID_PHYSICS_CAPSULE 34 ///< physics object (mins, maxs, mass, origin, axis_forward, axis_left, axis_up, velocity, spinvelocity) @@ -542,6 +545,8 @@ typedef enum VF_SCREENVSIZE = 204, VF_SCREENPSIZE = 205, VF_VIEWENTITY = 206, + VF_STATSENTITIY = 207, //the player number for the stats. + VF_SCREENVOFFSET = 208, } viewflags; /*FIXME: this should be changed*/ diff --git a/engine/d3d/d3d11_backend.c b/engine/d3d/d3d11_backend.c index 488e82e93..57088d1aa 100644 --- a/engine/d3d/d3d11_backend.c +++ b/engine/d3d/d3d11_backend.c @@ -268,7 +268,7 @@ static void BE_CreateSamplerStates(void) if (flags & SHADER_PASS_NEAREST) sampdesc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR; else - sampdesc.Filter = /*D3D11_FILTER_MIN_MAG_MIP_POINT;D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;*/D3D11_FILTER_MIN_MAG_MIP_LINEAR; + sampdesc.Filter = /*D3D11_FILTER_MIN_MAG_MIP_POINT;*/D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;/*D3D11_FILTER_MIN_MAG_MIP_LINEAR*/; sampdesc.ComparisonFunc = D3D11_COMPARISON_NEVER; } if (flags & SHADER_PASS_CLAMP) @@ -2053,7 +2053,8 @@ static void BE_DrawMeshChain_Internal(void) BE_RenderMeshProgram(shaderstate.shader_rtlight[shaderstate.curlmode], vertcount, idxfirst, idxcount); break; case BEM_DEPTHONLY: - BE_RenderMeshProgram(shaderstate.depthonly, vertcount, idxfirst, idxcount); + if (shaderstate.depthonly->prog) + BE_RenderMeshProgram(shaderstate.depthonly, vertcount, idxfirst, idxcount); #if 0 shaderstate.lastpasscount = 0; i = 0; diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index ef06c03dd..2ed87e8e6 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -1689,7 +1689,7 @@ PreprocessorDefinitions="NDEBUG;GLQUAKE;WIN32;_WINDOWS;BOTLIB_STATIC;MULTITHREAD" StringPooling="true" ExceptionHandling="0" - BufferSecurityCheck="false" + BufferSecurityCheck="true" EnableEnhancedInstructionSet="2" FloatingPointModel="2" RuntimeTypeInfo="false" diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 040caf749..2baccd7a2 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -58,7 +58,7 @@ static const char LIGHTPASS_SHADER[] = "\ }\n\ }"; -extern cvar_t r_glsl_offsetmapping, r_noportals; +extern cvar_t r_glsl_offsetmapping, r_portalrecursion; static void BE_SendPassBlendDepthMask(unsigned int sbits); void GLBE_SubmitBatch(batch_t *batch); @@ -3241,6 +3241,7 @@ void GLBE_SelectMode(backendmode_t mode) { extern int gldepthfunc; +// shaderstate.lastuniform = 0; if (mode != shaderstate.mode) { shaderstate.mode = mode; @@ -3488,6 +3489,9 @@ void GLBE_Scissor(srect_t *rect) */ qglDisable(GL_SCISSOR_TEST); if (qglDepthBoundsEXT) qglDisable(GL_DEPTH_BOUNDS_TEST_EXT); + +// if (qglDepthBoundsEXT) +// qglDepthBoundsEXT(0, 1); } } @@ -4101,7 +4105,7 @@ void GLBE_SubmitBatch(batch_t *batch) static void GLBE_SubmitMeshesPortals(batch_t **worldlist, batch_t *dynamiclist) { - batch_t *batch, *old; + batch_t *batch, *masklists[2]; int i; /*attempt to draw portal shaders*/ if (shaderstate.mode == BEM_STANDARD) @@ -4116,34 +4120,33 @@ static void GLBE_SubmitMeshesPortals(batch_t **worldlist, batch_t *dynamiclist) if (batch->buildmeshes) batch->buildmeshes(batch); - /*draw already-drawn portals as depth-only, to ensure that their contents are not harmed*/ - GLBE_SelectMode(BEM_DEPTHONLY); - for (old = worldlist[SHADER_SORT_PORTAL]; old && old != batch; old = old->next) - { - if (old->meshes == old->firstmesh) - continue; - GLBE_SubmitBatch(old); - } - if (!old) - { - for (old = dynamiclist; old != batch; old = old->next) - { - if (old->meshes == old->firstmesh) - continue; - GLBE_SubmitBatch(old); - } - } - GLBE_SelectMode(BEM_STANDARD); - - GLR_DrawPortal(batch, worldlist, 0); + masklists[0] = worldlist[SHADER_SORT_PORTAL]; + masklists[1] = dynamiclist; + GLR_DrawPortal(batch, worldlist, masklists, 0); /*clear depth again*/ GL_ForceDepthWritable(); qglClear(GL_DEPTH_BUFFER_BIT); - currententity = &r_worldentity; - shaderstate.curtime = shaderstate.updatetime - shaderstate.curentity->shaderTime; } } + //make sure the current scene doesn't draw over the portal where its not meant to. clamp depth so the near clip plane doesn't cause problems. + if (gl_config.arb_depth_clamp) + qglEnable(GL_DEPTH_CLAMP_ARB); + for (i = 0; i < 2; i++) + { + for (batch = i?dynamiclist:worldlist[SHADER_SORT_PORTAL]; batch; batch = batch->next) + { + if (batch->meshes == batch->firstmesh) + continue; + + /*draw depth only, to mask it off*/ + GLBE_SelectMode(BEM_DEPTHONLY); + GLBE_SubmitBatch(batch); + GLBE_SelectMode(BEM_STANDARD); + } + } + if (gl_config.arb_depth_clamp) + qglDisable(GL_DEPTH_CLAMP_ARB); } } @@ -4173,6 +4176,16 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) TRACE(("GLBE_SubmitMeshesSortList: shader %s\n", batch->shader->name)); + //FIXME:!! + if (!batch->shader) + { + Con_Printf("Shader not set...\n"); + if (batch->texture) + batch->shader = R_TextureAnimation(0, batch->texture)->shader; + else + continue; + } + if (batch->shader->flags & SHADER_NODRAW) continue; if (batch->shader->flags & SHADER_NODLIGHT) @@ -4236,7 +4249,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) GL_ForceDepthWritable(); qglClearColor(0, 0, 0, 0); qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - GLR_DrawPortal(batch, cl.worldmodel->batches, 1); + GLR_DrawPortal(batch, cl.worldmodel->batches, NULL, 1); GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, r_nulltex, false); r_refdef.vrect = orect; r_refdef.pxrect = oprect; @@ -4291,7 +4304,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) GL_ForceDepthWritable(); qglClearColor(0, 0, 0, 0); qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - GLR_DrawPortal(batch, cl.worldmodel->batches, ((batch->shader->flags & SHADER_HASREFRACTDEPTH)?3:2)); //fixme + GLR_DrawPortal(batch, cl.worldmodel->batches, NULL, ((batch->shader->flags & SHADER_HASREFRACTDEPTH)?3:2)); //fixme GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, r_nulltex, false); r_refdef.vrect = ovrect; @@ -4299,7 +4312,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) GL_ViewportUpdate(); } else - GLR_DrawPortal(batch, cl.worldmodel->batches, 3); + GLR_DrawPortal(batch, cl.worldmodel->batches, NULL, 3); } if ((batch->shader->flags & SHADER_HASRIPPLEMAP) && gl_config.ext_framebuffer_objects) { @@ -4333,9 +4346,9 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) // r_refdef.waterheight = DotProduct(batch->mesh[0]->xyz_array[0], batch->mesh[0]->normals_array[0]); - r_refdef.recurse = true; //paranoid, should stop potential infinite loops + r_refdef.recurse+=1; //paranoid, should stop potential infinite loops GLBE_SubmitMeshes(true, SHADER_SORT_RIPPLE, SHADER_SORT_RIPPLE); - r_refdef.recurse = false; + r_refdef.recurse-=1; GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, r_nulltex, false); r_refdef.vrect = orect; @@ -4354,12 +4367,13 @@ void GLBE_SubmitMeshes (qboolean drawworld, int start, int stop) { model_t *model = cl.worldmodel; int i; + int portaldepth = r_portalrecursion.ival; for (i = start; i <= stop; i++) { if (drawworld) { - if (i == SHADER_SORT_PORTAL && !r_noportals.ival && !r_refdef.recurse) + if (i == SHADER_SORT_PORTAL && r_refdef.recurse < portaldepth) GLBE_SubmitMeshesPortals(model->batches, shaderstate.mbatches[i]); GLBE_SubmitMeshesSortList(model->batches[i]); diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index f6f9d49cc..8e41f491d 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -24,7 +24,8 @@ int Font_DrawChar(int px, int py, unsigned int charcode); float Font_DrawScaleChar(float px, float py, unsigned int charcode); /*avoid using*/ void Font_EndString(struct font_s *font); int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int maxlines, conchar_t **starts, conchar_t **ends); -struct font_s *font_conchar; +struct font_s *font_default; +struct font_s *font_console; struct font_s *font_tiny; extern unsigned int r2d_be_flags; @@ -171,8 +172,8 @@ static const char *imgs[] = typedef struct ftfontface_s { - struct ftfontface_s *next; - struct ftfontface_s **link; //like prev, but not. + struct ftfontface_s *fnext; + struct ftfontface_s **flink; //like prev, but not. char name[MAX_OSPATH]; int refs; int activeheight; //needs reconfiguring when different sizes are used @@ -703,7 +704,7 @@ qboolean Font_LoadFreeTypeFont(struct font_s *f, int height, char *fontfilename) if (f->ftfaces == MAX_FTFACES) return false; - for (qface = ftfaces; qface; qface = qface->next) + for (qface = ftfaces; qface; qface = qface->fnext) { if (!strcmp(qface->name, fontfilename)) { @@ -814,9 +815,11 @@ qboolean Font_LoadFreeTypeFont(struct font_s *f, int height, char *fontfilename) { /*success!*/ qface = Z_Malloc(sizeof(*qface)); - qface->link = &ftfaces; - qface->next = *qface->link; - *qface->link = qface; + qface->flink = &ftfaces; + qface->fnext = *qface->flink; + *qface->flink = qface; + if (qface->fnext) + qface->fnext->flink = &qface->fnext; qface->face = face; qface->membuf = fbase; qface->refs++; @@ -1336,9 +1339,9 @@ void Font_Free(struct font_s *f) pFT_Done_Face(qface->face); if (qface->membuf) BZ_Free(qface->membuf); - *qface->link = qface->next; - if (qface->next) - qface->next->link = qface->link; + *qface->flink = qface->fnext; + if (qface->fnext) + qface->fnext->flink = qface->flink; Z_Free(qface); } } diff --git a/engine/gl/gl_hlmdl.c b/engine/gl/gl_hlmdl.c index f7f28c3b2..cf0661f06 100644 --- a/engine/gl/gl_hlmdl.c +++ b/engine/gl/gl_hlmdl.c @@ -199,6 +199,11 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer) shaders[i]->defaulttextures.base = R_LoadTexture8Pal24("", tex[i].w, tex[i].h, (qbyte *) texheader + tex[i].offset, (qbyte *) texheader + tex[i].w * tex[i].h + tex[i].offset, IF_NOALPHA|IF_NOGAMMA); } + model->numskins = texheader->numtextures; + model->skins = ZG_Malloc(&mod->memgroup, model->numskins*sizeof(*model->skins)); + memcpy(model->skins, (short *) ((qbyte *) texheader + texheader->skins), model->numskins*sizeof(*model->skins)); + + if (texmem) Z_Free(texmem); @@ -665,20 +670,17 @@ void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches) hlmodelcache_t *modelc = Mod_Extradata(rent->model); hlmodel_t model; int body, m; - short *skins; int batchid = 0; static mesh_t bmesh, *mptr = &bmesh; //general model model.header = (hlmdl_header_t *) ((char *)modelc + modelc->header); - model.texheader = (hlmdl_header_t *) ((char *)modelc + modelc->texheader); +// model.texheader = (hlmdl_header_t *) ((char *)modelc + modelc->texheader); model.textures = (hlmdl_tex_t *) ((char *)modelc + modelc->textures); model.bones = (hlmdl_bone_t *) ((char *)modelc + modelc->bones); model.bonectls = (hlmdl_bonecontroller_t *) ((char *)modelc + modelc->bonectls); model.shaders = (shader_t **) ((char *)modelc + modelc->shaders); - skins = (short *) ((qbyte *) model.texheader + model.texheader->skins); - for (body = 0; body < model.header->numbodyparts; body++) { /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ @@ -697,6 +699,8 @@ void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches) float tex_h; /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + if (mesh->skinindex >= modelc->numskins) + continue; if (batches) { @@ -707,7 +711,7 @@ void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches) if (!b) return; - shader = model.shaders[skins[mesh->skinindex]]; + shader = model.shaders[modelc->skins[mesh->skinindex]]; b->buildmeshes = R_HL_BuildMesh; b->ent = rent; b->mesh = NULL; @@ -754,8 +758,8 @@ void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches) { if (batchid == b->surf_first) { - tex_w = 1.0f / model.textures[skins[mesh->skinindex]].w; - tex_h = 1.0f / model.textures[skins[mesh->skinindex]].h; + tex_w = 1.0f / model.textures[modelc->skins[mesh->skinindex]].w; + tex_h = 1.0f / model.textures[modelc->skins[mesh->skinindex]].h; b->mesh = &mptr; R_HL_BuildFrame(&model, amodel, b->ent, (short *) ((qbyte *) model.header + mesh->index), tex_w, tex_h, b->mesh[0]); diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 3461ba1b6..3f459f7bc 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -2138,7 +2138,7 @@ qboolean Mod_LoadSubmodels (lump_t *l) } for ( ; jheadnode[j] = 0; - for (j=0 ; j<3 ; j++) + for (j=0 ; j<4 ; j++) out->hullavailable[j] = true; for ( ; jhullavailable[j] = false; @@ -3049,7 +3049,7 @@ void Mod_Batches_Build(mesh_t *meshlist, model_t *mod, void (*build)(model_t *mo /*assign each mesh to a batch, generating as needed*/ Mod_Batches_Generate(mod); - bmeshes = ZG_Malloc(&loadmodel->memgroup, sizeof(*bmeshes)*mod->nummodelsurfaces*2); + bmeshes = ZG_Malloc(&loadmodel->memgroup, sizeof(*bmeshes)*mod->nummodelsurfaces*R_MAX_RECURSE); //we now know which batch each surface is in, and how many meshes there are in each batch. //allocate the mesh-pointer-lists for each batch. *2 for recursion. @@ -3057,7 +3057,7 @@ void Mod_Batches_Build(mesh_t *meshlist, model_t *mod, void (*build)(model_t *mo for (batch = mod->batches[sortid]; batch != NULL; batch = batch->next) { batch->mesh = bmeshes + i; - i += batch->maxmeshes*2; + i += batch->maxmeshes*R_MAX_RECURSE; } //store the *surface* into the batch's mesh list (yes, this is an evil cast hack, but at least both are pointers) for (i=0; inummodelsurfaces; i++) @@ -3250,6 +3250,11 @@ qboolean Mod_LoadLeafs (lump_t *l, int lm) return false; } count = l->filelen / sizeof(*in); + if (count > MAX_MAP_LEAFS) + { + Con_Printf (CON_ERROR "Mod_LoadLeafs: %s has more than %i leafs\n",loadmodel->name, MAX_MAP_LEAFS); + return false; + } out = ZG_Malloc(&loadmodel->memgroup, count*sizeof(*out)); loadmodel->leafs = out; @@ -3307,6 +3312,11 @@ qboolean Mod_LoadLeafs (lump_t *l, int lm) return false; } count = l->filelen / sizeof(*in); + if (count > MAX_MAP_LEAFS) + { + Con_Printf (CON_ERROR "Mod_LoadLeafs: %s has more than %i leafs\n",loadmodel->name, MAX_MAP_LEAFS); + return false; + } out = ZG_Malloc(&loadmodel->memgroup, count*sizeof(*out)); loadmodel->leafs = out; @@ -3364,6 +3374,11 @@ qboolean Mod_LoadLeafs (lump_t *l, int lm) return false; } count = l->filelen / sizeof(*in); + if (count > MAX_MAP_LEAFS) + { + Con_Printf (CON_ERROR "Mod_LoadLeafs: %s has more than %i leafs\n",loadmodel->name, MAX_MAP_LEAFS); + return false; + } out = ZG_Malloc(&loadmodel->memgroup, count*sizeof(*out)); loadmodel->leafs = out; @@ -4561,7 +4576,7 @@ qboolean QDECL Mod_LoadSpriteModel (model_t *mod, void *buffer) int numframes; int size; dspriteframetype_t *pframetype; -// int rendertype=0; + int rendertype=SPRHL_ALPHATEST; unsigned char pal[256*4]; int sptype; @@ -4582,7 +4597,7 @@ qboolean QDECL Mod_LoadSpriteModel (model_t *mod, void *buffer) if (LittleLong(pin->version) == SPRITEHL_VERSION) { pin = (dsprite_t*)((char*)pin + 4); - /*rendertype =*/ LittleLong (pin->type); //not sure what the values mean. + rendertype = LittleLong (pin->type); //not sure what the values mean. } numframes = LittleLong (pin->numframes); @@ -4592,6 +4607,22 @@ qboolean QDECL Mod_LoadSpriteModel (model_t *mod, void *buffer) psprite = ZG_Malloc(&loadmodel->memgroup, size); mod->meshinfo = psprite; + switch(sptype) + { + case SPR_VP_PARALLEL_UPRIGHT: + case SPR_FACING_UPRIGHT: + case SPR_VP_PARALLEL: + case SPR_ORIENTED: +// case SPR_VP_PARALLEL_ORIENTED: +// case SPRDP_LABEL: +// case SPRDP_LABEL_SCALE: +// case SPRDP_OVERHEAD: + break; + default: + Con_DPrintf(CON_ERROR "%s has unsupported sprite type %i\n", mod->name, sptype); + sptype = SPR_VP_PARALLEL; + break; + } psprite->type = sptype; psprite->maxwidth = LittleLong (pin->width); @@ -4621,12 +4652,27 @@ qboolean QDECL Mod_LoadSpriteModel (model_t *mod, void *buffer) return false; } - for (i = 0; i < 256; i++) + if (rendertype == SPRHL_INDEXALPHA) { - pal[i*4+0] = *src++; - pal[i*4+1] = *src++; - pal[i*4+2] = *src++; - pal[i*4+3] = 255; + Con_Printf(CON_ERROR "%s: SPRHL_INDEXALPHA sprites are not supported\n", mod->name); + return false; + } + else + { + for (i = 0; i < 256; i++) + {//FIXME: bgr? + pal[i*4+0] = *src++; + pal[i*4+1] = *src++; + pal[i*4+2] = *src++; + pal[i*4+3] = 255; + } + if (rendertype == SPRHL_ALPHATEST) + { + pal[255*4+0] = 0; + pal[255*4+1] = 0; + pal[255*4+2] = 0; + pal[255*4+3] = 0; + } } pframetype = (dspriteframetype_t *)(src); diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index fa47fba8f..b92cbaac2 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -107,9 +107,9 @@ once a batch is known to the backend for that frame, its shader, vbo, ent, light typedef struct batch_s { mesh_t **mesh; /*list must be long enough for all surfaces that will form part of this batch times two, for mirrors/portals*/ - unsigned int firstmesh; - unsigned int meshes; struct batch_s *next; + unsigned int meshes; + unsigned int firstmesh; shader_t *shader; struct vbo_s *vbo; @@ -126,6 +126,9 @@ typedef struct batch_s struct texnums_s *skin; void (*buildmeshes)(struct batch_s *b); +#if R_MAX_RECURSE > 2 + unsigned int recursefirst[R_MAX_RECURSE-2]; //fixme: should thih, firstmesh, and meshes be made ushorts? +#endif /*caller-use, not interpreted by backend*/ union { @@ -830,7 +833,7 @@ typedef struct model_s { char name[MAX_QPATH]; int datasequence; - qboolean needload; // bmodels and sprites don't cache normally + int needload; // if needload is set, the model is not currently valid. 0=false, 1=true, 2 means it was never valid (and please don't spam about it still being invalid). most code should treat this as a simple boolean. qboolean tainted; qboolean pushdepth; // bsp submodels have this flag set so you don't get z fighting on co-planar surfaces. diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 214948eab..33d556566 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -743,7 +743,7 @@ static float sgn(float a) if (a < 0.0F) return (-1.0F); return (0.0F); } -void R_ObliqueNearClip(mplane_t *wplane) +void R_ObliqueNearClip(float *viewmat, mplane_t *wplane) { float f; vec4_t q, c; @@ -751,9 +751,9 @@ void R_ObliqueNearClip(mplane_t *wplane) vec4_t vplane; //convert world plane into view space - Matrix4x4_CM_Transform3x3(r_refdef.m_view, wplane->normal, vplane); + Matrix4x4_CM_Transform3x3(viewmat, wplane->normal, vplane); VectorScale(wplane->normal, wplane->dist, ping); - Matrix4x4_CM_Transform3(r_refdef.m_view, ping, pong); + Matrix4x4_CM_Transform3(viewmat, ping, pong); vplane[3] = -DotProduct(pong, vplane); // Calculate the clip-space corner point opposite the clipping plane @@ -776,17 +776,17 @@ void R_ObliqueNearClip(mplane_t *wplane) r_refdef.m_projection[10] = c[2] + 1.0F; r_refdef.m_projection[14] = c[3]; } -void GLR_DrawPortal(batch_t *batch, batch_t **blist, int portaltype) +void GLR_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist[2], int portaltype) { entity_t *view; // GLdouble glplane[4]; plane_t plane; + float vmat[16]; refdef_t oldrefdef; mesh_t *mesh = batch->mesh[batch->firstmesh]; - int sort; qbyte newvis[(MAX_MAP_LEAFS+7)/8]; - if (r_refdef.recurse) + if (r_refdef.recurse >= R_MAX_RECURSE-1) return; if (!mesh->normals_array) @@ -806,14 +806,14 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, int portaltype) if (DotProduct(r_refdef.vieworg, plane.normal)-plane.dist > batch->shader->portaldist) return; } - //if we're behind it, then also don't draw anything. - if (DotProduct(r_refdef.vieworg, plane.normal)-plane.dist < 0) + //if we're behind it, then also don't draw anything. for our purposes, behind is when the entire near clipplane is behind. + if (DotProduct(r_refdef.vieworg, plane.normal)-plane.dist < -gl_mindist.value) return; TRACE(("GLR_DrawPortal: portal type %i\n", portaltype)); oldrefdef = r_refdef; - r_refdef.recurse = true; + r_refdef.recurse+=1; r_refdef.externalview = true; @@ -823,6 +823,7 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, int portaltype) //fixme: pvs is surely wrong? r_refdef.flipcull ^= SHADER_CULL_FLIP; R_MirrorMatrix(&plane); + Matrix4x4_CM_ModelViewMatrixFromAxis(vmat, vpn, vright, vup, r_refdef.vieworg); break; case 2: /*fbo refraction (fucked depth, working clip plane)*/ @@ -876,10 +877,30 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, int portaltype) } // memset(newvis, 0xff, pvsbytes); } + Matrix4x4_CM_ModelViewMatrixFromAxis(vmat, vpn, vright, vup, r_refdef.vieworg); break; - default: /*q3 portal*/ - if (batch->ent != &r_worldentity) + case 0: /*q3 portal*/ + default: + if (CSQC_SetupToRenderPortal(batch->ent->keynum)) + { + plane_t oplane = plane; + float ivmat[16], trmat[16]; + + //transform the old surface plane into the new view matrix + Matrix4_Invert(r_refdef.m_view, ivmat); + Matrix4x4_CM_ModelViewMatrixFromAxis(vmat, vpn, vright, vup, r_refdef.vieworg); + Matrix4_Multiply(ivmat, vmat, trmat); + plane.normal[0] = (oplane.normal[0] * trmat[0] + oplane.normal[1] * trmat[4] + oplane.normal[2] * trmat[8]); + plane.normal[1] = (oplane.normal[0] * trmat[1] + oplane.normal[1] * trmat[5] + oplane.normal[2] * trmat[9]); + plane.normal[2] = (oplane.normal[0] * trmat[2] + oplane.normal[1] * trmat[6] + oplane.normal[2] * trmat[10]); + plane.dist = -oplane.dist + trmat[12]*oplane.normal[0] + trmat[13]*oplane.normal[1] + trmat[14]*oplane.normal[2]; + + VectorNegate(plane.normal, plane.normal); + if (Cvar_Get("temp_useplaneclip", "1", 0, "temp")->ival) + portaltype = 1; //make sure the near clipplane is used. + } + else if (batch->ent != &r_worldentity) { float d; view = batch->ent; @@ -887,11 +908,13 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, int portaltype) d-= 0.1; //nudge it past. VectorAdd(r_refdef.vieworg, view->oldorigin, r_refdef.vieworg); //trivial offset for the warpzone. VectorMA(r_refdef.vieworg, -d, plane.normal, r_refdef.pvsorigin); //clip the pvs origin to the plane. + Matrix4x4_CM_ModelViewMatrixFromAxis(vmat, vpn, vright, vup, r_refdef.vieworg); } else if (!(view = R_NearestPortal(&plane)) || VectorCompare(view->origin, view->oldorigin)) { r_refdef.flipcull ^= SHADER_CULL_FLIP; R_MirrorMatrix(&plane); + Matrix4x4_CM_ModelViewMatrixFromAxis(vmat, vpn, vright, vup, r_refdef.vieworg); } else { @@ -922,35 +945,23 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, int portaltype) TransformDir(vpn, paxis, vaxis, vpn); TransformDir(vright, paxis, vaxis, vright); TransformDir(vup, paxis, vaxis, vup); + Matrix4x4_CM_ModelViewMatrixFromAxis(vmat, vpn, vright, vup, r_refdef.vieworg); } break; } - Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, vpn, vright, vup, r_refdef.vieworg); - VectorAngles(vpn, vup, r_refdef.viewangles); - VectorCopy(r_refdef.vieworg, r_origin); - -/*FIXME: the batch stuff should be done in renderscene*/ - - /*fixup the first mesh index*/ - for (sort = 0; sort < SHADER_SORT_COUNT; sort++) - for (batch = blist[sort]; batch; batch = batch->next) - { - batch->firstmesh = batch->meshes; - } - - GL_CullFace(0); /*FIXME: can we get away with stenciling the screen?*/ /*Add to frustum culling instead of clip planes?*/ -// if (qglClipPlane) -// { -// glplane[0] = -plane.normal[0]; -// glplane[1] = -plane.normal[1]; -// glplane[2] = -plane.normal[2]; -// glplane[3] = plane.dist; -// qglClipPlane(GL_CLIP_PLANE0, glplane); -// qglEnable(GL_CLIP_PLANE0); -// } +/* if (qglClipPlane) + { + GLdouble glplane[4]; + glplane[0] = -plane.normal[0]; + glplane[1] = -plane.normal[1]; + glplane[2] = -plane.normal[2]; + glplane[3] = plane.dist; + qglClipPlane(GL_CLIP_PLANE0, glplane); + qglEnable(GL_CLIP_PLANE0); + }*/ if (r_refdef.frustum_numplanes < MAXFRUSTUMPLANES) { r_refdef.frustum[r_refdef.frustum_numplanes].normal[0] = plane.normal[0]; @@ -959,18 +970,56 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, int portaltype) r_refdef.frustum[r_refdef.frustum_numplanes].dist = plane.dist + 0.01; if (portaltype == 1 || portaltype == 2) - R_ObliqueNearClip(&r_refdef.frustum[r_refdef.frustum_numplanes]); + R_ObliqueNearClip(vmat, &r_refdef.frustum[r_refdef.frustum_numplanes]); r_refdef.frustum_numplanes++; } + + GL_CullFace(0); + if (depthmasklist) + { + /*draw already-drawn portals as depth-only, to ensure that their contents are not harmed*/ + /*we can only do this AFTER the oblique perspective matrix is calculated, to avoid depth inconsistancies, while we still have the old view matrix*/ + int i; + batch_t *dmask = NULL; + if (qglLoadMatrixf) + { + qglMatrixMode(GL_PROJECTION); + qglLoadMatrixf(r_refdef.m_projection); + } + currententity = NULL; + if (gl_config.arb_depth_clamp) + qglEnable(GL_DEPTH_CLAMP_ARB); + GL_ForceDepthWritable(); + GLBE_SelectMode(BEM_DEPTHONLY); + for (i = 0; i < 2; i++) + { + for (dmask = depthmasklist[i]; dmask; dmask = dmask->next) + { + if (dmask == batch) + continue; + if (dmask->meshes == dmask->firstmesh) + continue; + GLBE_SubmitBatch(dmask); + } + } + GLBE_SelectMode(BEM_STANDARD); + if (gl_config.arb_depth_clamp) + qglDisable(GL_DEPTH_CLAMP_ARB); + + currententity = NULL; + } + + //now determine the stuff the backend will use. + memcpy(r_refdef.m_view, vmat, sizeof(float)*16); + VectorAngles(vpn, vup, r_refdef.viewangles); + r_refdef.viewangles[0] *= -1; + VectorCopy(r_refdef.vieworg, r_origin); + + //FIXME: R_RenderScene is currently overriding r_refdef.frustum_numplanes and discarding our new near plane, resulting in wasted draw calls. R_RenderScene(); // if (qglClipPlane) // qglDisable(GL_CLIP_PLANE0); - for (sort = 0; sort < SHADER_SORT_COUNT; sort++) - for (batch = blist[sort]; batch; batch = batch->next) - { - batch->firstmesh = 0; - } r_refdef = oldrefdef; /*broken stuff*/ @@ -994,6 +1043,7 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, int portaltype) #ifdef warningmsg #pragma warningmsg("warning: there's a bug with rtlights in portals, culling is broken or something. May also be loading the wrong matrix") #endif + currententity = NULL; } diff --git a/engine/gl/gl_rmisc.c b/engine/gl/gl_rmisc.c index b9a91146f..09d3ea9ab 100644 --- a/engine/gl/gl_rmisc.c +++ b/engine/gl/gl_rmisc.c @@ -247,7 +247,8 @@ void GLR_ReInit (void) R_InitBloomTextures(); } -/* + +#if 1 typedef struct { long offset; // Position of the entry in WAD @@ -266,57 +267,66 @@ typedef struct } wad2_t; void R_MakeTexWad_f(void) { + //this function is written as little endian. nothing will fix that. miptex_t dummymip = {"", 0, 0, {0, 0, 0, 0}}; wad2_t wad2 = {"WAD2",0,0}; wad2entry_t entry[2048]; int entries = 0, i; - FILE *f; + vfsfile_t *f; char base[128]; - char *texname; // qbyte b; - float scale; + qboolean hasalpha; int width, height; qbyte *buf, *outmip; qbyte *mip, *stack; -// WIN32_FIND_DATA fd; -// HANDLE h; + char *wadname = Cmd_Argv(1); + char *imagename = Cmd_Argv(2); + float scale = atof(Cmd_Argv(3)); - scale = atof(Cmd_Argv(2)); if (!scale) scale = 2; -// h = FindFirstFile(va("%s/textures/ *.tga", com_gamedir), &fd); //if this is uncommented, clear that space... (gcc warning fix) - if (!shader) + if (!*wadname || !*imagename) return; + f=FS_OpenVFS(wadname, "w+b", FS_GAMEONLY); + if (!f) + return; + mip = BZ_Malloc(1024*1024); // initbuf = BZ_Malloc(1024*1024*4); stack = BZ_Malloc(1024*1024*4+1024); - f=fopen(va("%s/shadrtex.wad", com_gamedir), "wb"); - fwrite(&wad2, 1, sizeof(wad2_t), f); - for (shad = shader; shad; shad=shad->next) + VFS_SEEK(f, 0); + VFS_READ(f, &wad2, sizeof(wad2_t)); + + VFS_SEEK(f, wad2.offset); + VFS_READ(f, entry, sizeof(entry[0]) * wad2.num); + + //find the end of the data. + wad2.offset = sizeof(wad2_t); + for (entries = 0; entries < wad2.num; entries++) + if (wad2.offset < entry[entries].offset + entry[entries].dsize) + wad2.offset = entry[entries].offset + entry[entries].dsize; + VFS_SEEK(f, wad2.offset); + { - texname = shad->editorname; - if (!*texname) - continue; - COM_StripExtension(shad->name, base); + COM_StripExtension(imagename, base, sizeof(base)); base[15]=0; for (i =0; i < entries; i++) - if (!strcmp(entry[entries].name, base)) + if (!stricmp(entry[i].name, base)) break; if (i != entries) - { - Con_Printf("Skipped %s - duplicated shrunken name\n", texname); - continue; - } - entry[entries].offset = ftell(f); - entry[entries].dsize = entry[entries].size = 0; - entry[entries].type = TYP_MIPTEX; - entry[entries].cmprs = 0; - entry[entries].dummy = 0; - strcpy(entry[entries].name, base); + Con_Printf("Replacing %s, you'll want to compact your wad at some point.\n", base); //this will leave a gap. we don't support compacting. + else + entries++; + entry[i].offset = VFS_TELL(f); + entry[i].dsize = entry[i].size = 0; + entry[i].type = TYP_MIPTEX; + entry[i].cmprs = 0; + entry[i].dummy = 0; + strcpy(entry[i].name, base); strcpy(dummymip.name, base); @@ -330,36 +340,40 @@ void R_MakeTexWad_f(void) char *path[] ={ "%s", "override/%s.tga", - "override/%s.pcx", + + "textures/%s.png", + "textures/%s.tga", + + "%s.png", "%s.tga", "progs/%s"}; for (h = 0, buf=NULL; h < sizeof(path)/sizeof(char *); h++) { - buf = COM_LoadStackFile(va(path[h], texname), stack, 1024*1024*4+1024); + buf = COM_LoadStackFile(va(path[h], imagename), stack, 1024*1024*4+1024); if (buf) break; } - if (!buf) + if (buf) + data = Read32BitImageFile(buf, com_filesize, &width, &height, &hasalpha, imagename); + else + data = NULL; + if (!data) { - Con_Printf("Failed to find texture \"%s\"\n", texname); - continue; + data = Z_Malloc(16*16*4); + width = 16; + height = 16; } - -data = ReadTargaFile(buf, com_filesize, &width, &height, false); -if (!data) -{ - BZ_Free(data); - Con_Printf("Skipped %s - file type not supported (bad bpp?)\n", texname); - continue; -} - dummymip.width = (int)(width/scale) & ~0xf; dummymip.height = (int)(height/scale) & ~0xf; if (dummymip.width<=0) dummymip.width=16; if (dummymip.height<=0) dummymip.height=16; + if (dummymip.width > 1024) + dummymip.width = 1024; + if (dummymip.height > 1024) + dummymip.height = 1024; dummymip.offsets[0] = sizeof(dummymip); dummymip.offsets[1] = dummymip.offsets[0]+dummymip.width*dummymip.height; @@ -371,7 +385,7 @@ if (!data) yi = (float)height/dummymip.height; - fwrite(&dummymip, 1, sizeof(dummymip), f); + VFS_WRITE(f, &dummymip, sizeof(dummymip)); outmip=mip; for (outmip=mip, y = 0; y < height; y+=yi) for (x = 0; x < width; x+=xi) @@ -380,7 +394,7 @@ if (!data) data[(int)(x+y*width)*4+1], data[(int)(x+y*width)*4+2]); } - fwrite(mip, dummymip.width, dummymip.height, f); + VFS_WRITE(f, mip, dummymip.width * dummymip.height); for (outmip=mip, y = 0; y < height; y+=yi*2) for (x = 0; x < width; x+=xi*2) { @@ -388,7 +402,7 @@ if (!data) data[(int)(x+y*width)*4+1], data[(int)(x+y*width)*4+2]); } - fwrite(mip, dummymip.width/2, dummymip.height/2, f); + VFS_WRITE(f, mip, (dummymip.width/2) * (dummymip.height/2)); for (outmip=mip, y = 0; y < height; y+=yi*4) for (x = 0; x < width; x+=xi*4) { @@ -396,7 +410,7 @@ if (!data) data[(int)(x+y*width)*4+1], data[(int)(x+y*width)*4+2]); } - fwrite(mip, dummymip.width/4, dummymip.height/4, f); + VFS_WRITE(f, mip, (dummymip.width/4) * (dummymip.height/4)); for (outmip=mip, y = 0; y < height; y+=yi*8) for (x = 0; x < width; x+=xi*8) { @@ -404,30 +418,29 @@ if (!data) data[(int)(x+y*width)*4+1], data[(int)(x+y*width)*4+2]); } - fwrite(mip, dummymip.width/8, dummymip.height/8, f); + VFS_WRITE(f, mip, (dummymip.width/8) * (dummymip.height/8)); BZ_Free(data); } - entries++; + entry[i].dsize = VFS_TELL(f) - entry[i].offset; Con_Printf("Added %s\n", base); - GLSCR_UpdateScreen(); } - wad2.offset = ftell(f); + wad2.offset = VFS_TELL(f); wad2.num = entries; - fwrite(entry, entries, sizeof(wad2entry_t), f); - fseek(f, 0, SEEK_SET); - fwrite(&wad2, 1, sizeof(wad2_t), f); - fclose(f); + VFS_WRITE(f, entry, entries*sizeof(wad2entry_t)); + VFS_SEEK(f, 0); + VFS_WRITE(f, &wad2, sizeof(wad2_t)); + VFS_CLOSE(f); BZ_Free(mip); // BZ_Free(initbuf); BZ_Free(stack); - Con_Printf("Written %i mips to textures.wad\n", entries); + Con_Printf("%s now has %i entries\n", wadname, entries); } -*/ +#endif void GLR_TimeRefresh_f (void); extern cvar_t v_contrast, r_drawflat; @@ -467,7 +480,7 @@ void GLR_Init (void) { Cmd_AddCommand ("timerefresh", GLR_TimeRefresh_f); -// Cmd_AddCommand ("makewad", R_MakeTexWad_f); + Cmd_AddCommand ("makewad", R_MakeTexWad_f); // Cvar_Hook(&r_floortexture, GLR_Floortexture_Callback); // Cvar_Hook(&r_walltexture, GLR_Walltexture_Callback); diff --git a/engine/gl/gl_screen.c b/engine/gl/gl_screen.c index e47ed8960..28dbedb00 100644 --- a/engine/gl/gl_screen.c +++ b/engine/gl/gl_screen.c @@ -71,6 +71,8 @@ void GLSCR_UpdateScreen (void) vid.numpages = 2 + vid_triplebuffer.value; + R2D_Font_Changed(); + if (scr_disabled_for_loading) { extern float scr_disabled_time; diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index e7d91662b..956774220 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -489,6 +489,7 @@ static void Shader_ParseVector(shader_t *shader, char **ptr, vec3_t v) char *scratch; char *token; qboolean bracket; + qboolean fromcvar = false; token = Shader_ParseString(ptr); if (*token == '$') @@ -507,6 +508,7 @@ static void Shader_ParseVector(shader_t *shader, char **ptr, vec3_t v) scratch = var->string; token = Shader_ParseString( ptr); + fromcvar = true; } if (!Q_stricmp (token, "(")) { @@ -522,12 +524,22 @@ static void Shader_ParseVector(shader_t *shader, char **ptr, vec3_t v) bracket = false; v[0] = atof ( token ); - v[1] = Shader_ParseFloat (shader, ptr ); + + token = Shader_ParseString ( ptr ); + if ( !token[0] ) { + v[1] = fromcvar?v[0]:0; + } else if (bracket && token[strlen(token)-1] == ')' ) { + bracket = false; + token[strlen(token)-1] = 0; + v[1] = atof ( token ); + } else { + v[1] = atof ( token ); + } token = Shader_ParseString ( ptr ); if ( !token[0] ) { - v[2] = 0; - } else if ( token[strlen(token)-1] == ')' ) { + v[2] = fromcvar?v[1]:0; + } else if (bracket && token[strlen(token)-1] == ')' ) { token[strlen(token)-1] = 0; v[2] = atof ( token ); } else { diff --git a/engine/gl/model_hl.h b/engine/gl/model_hl.h index df7cdcb9f..64dbea203 100644 --- a/engine/gl/model_hl.h +++ b/engine/gl/model_hl.h @@ -224,6 +224,8 @@ typedef struct //this is stored as the cache. an hlmodel_t is generated when dra int bones; int bonectls; int shaders; + short *skins; + int numskins; } hlmodelcache_t; /* HL mathlib prototypes: */ diff --git a/engine/qclib/pr_exec.c b/engine/qclib/pr_exec.c index 66bc891a8..452aacb8f 100644 --- a/engine/qclib/pr_exec.c +++ b/engine/qclib/pr_exec.c @@ -230,6 +230,7 @@ char *QC_ucase(char *str) return s; } +//#define STACKTRACE void PDECL PR_StackTrace (pubprogfuncs_t *ppf) { progfuncs_t *progfuncs = (progfuncs_t *)ppf; @@ -282,18 +283,18 @@ void PDECL PR_StackTrace (pubprogfuncs_t *ppf) } #ifdef STACKTRACE - + if (i == pr_depth) for (arg = 0; arg < f->locals; arg++) { ddef16_t *local; local = ED_GlobalAtOfs16(progfuncs, f->parm_start+arg); if (!local) { - printf(" ofs %i: %f : %i\n", f->parm_start+arg, *(float *)(globalbase - f->locals+arg), *(int *)(globalbase - f->locals+arg) ); + //printf(" ofs %i: %f : %i\n", f->parm_start+arg, *(float *)(globalbase - f->locals+arg), *(int *)(globalbase - f->locals+arg) ); } else { - printf(" %s: %s\n", local->s_name+progfuncs->stringtable, PR_ValueString(progfuncs, local->type, (eval_t*)(globalbase - f->locals+arg))); + printf(" %s: %s\n", local->s_name+progfuncs->funcs.stringtable, PR_ValueString(progfuncs, local->type, (eval_t*)(globalbase - f->locals+arg), false)); if (local->type == ev_vector) arg+=2; } @@ -427,7 +428,7 @@ int ASMCALL PR_EnterFunction (progfuncs_t *progfuncs, dfunction_t *f, int progsn pr_depth--; PR_StackTrace (&progfuncs->funcs); - printf ("stack overflow on call to %s\n", progfuncs->funcs.stringtable+f->s_name); + printf ("stack overflow on call to %s (depth %i)\n", progfuncs->funcs.stringtable+f->s_name, pr_depth); //comment this out if you want the progs to try to continue anyway (could cause infinate loops) PR_AbortStack(&progfuncs->funcs); diff --git a/engine/qclib/pr_multi.c b/engine/qclib/pr_multi.c index fa21e9091..77f316a82 100644 --- a/engine/qclib/pr_multi.c +++ b/engine/qclib/pr_multi.c @@ -1,7 +1,8 @@ #define PROGSUSED #include "progsint.h" -#define HunkAlloc BADGDFG sdfhhsf FHS +//#define MAPPING_DEBUG +//#define MAPPING_PARANOID //may actually break unions, so beware. void PR_SetBuiltins(int type); /* @@ -243,7 +244,9 @@ int PDECL QC_RegisterFieldVar(pubprogfuncs_t *ppf, unsigned int type, char *name if (!name) //engine can use this to offset all progs fields { //which fixes constant field offsets (some ktpro arrays) progfuncs->funcs.fieldadjust = fields_size/4; -// printf("FIELD ADJUST: %i %i %i\n", progfuncs->funcs.fieldadjust, fields_size, (int)fields_size/4); +#ifdef MAPPING_DEBUG + printf("FIELD ADJUST: %i %i %i\n", progfuncs->funcs.fieldadjust, fields_size, (int)fields_size/4); +#endif return 0; } @@ -273,7 +276,9 @@ int PDECL QC_RegisterFieldVar(pubprogfuncs_t *ppf, unsigned int type, char *name if (prinst.field[i].progsofs == -1) prinst.field[i].progsofs = progsofs; -// printf("Dupfield %s %i -> %i\n", name, prinst.field[i].progsofs,prinst.field[i].ofs); +#ifdef MAPPING_DEBUG + printf("Dupfield %s %i -> %i\n", name, prinst.field[i].progsofs,prinst.field[i].ofs); +#endif return prinst.field[i].ofs-progfuncs->funcs.fieldadjust; //got a match } } @@ -315,7 +320,8 @@ int PDECL QC_RegisterFieldVar(pubprogfuncs_t *ppf, unsigned int type, char *name { //the engine is setting up a list of required field indexes. //paranoid checking of the offset. - /* for (i = 0; i < numfields-1; i++) +#if 0//def MAPPING_PARANOID + for (i = 0; i < numfields-1; i++) { if (field[i].ofs == ((unsigned)engineofs)/4) { @@ -327,7 +333,8 @@ int PDECL QC_RegisterFieldVar(pubprogfuncs_t *ppf, unsigned int type, char *name else Sys_Error("Duplicated offset"); } - }*/ + } +#endif if (engineofs&3) Sys_Error("field %s is %i&3", name, (int)engineofs); prinst.field[fnum].ofs = ofs = engineofs/4; @@ -343,19 +350,25 @@ int PDECL QC_RegisterFieldVar(pubprogfuncs_t *ppf, unsigned int type, char *name { if (prinst.field[i].progsofs == (unsigned)progsofs) { -// printf("found union field %s %i -> %i\n", prinst.field[i].name, prinst.field[i].progsofs, prinst.field[i].ofs); +#ifdef MAPPING_DEBUG + printf("found union field %s %i -> %i\n", prinst.field[i].name, prinst.field[i].progsofs, prinst.field[i].ofs); +#endif prinst.field[fnum].ofs = ofs = prinst.field[i].ofs; break; } if (prinst.field[i].type == ev_vector && prinst.field[i].progsofs+1 == (unsigned)progsofs) { -// printf("found union field %s %i -> %i\n", prinst.field[i].name, prinst.field[i].progsofs+1, prinst.field[i].ofs+1); +#ifdef MAPPING_DEBUG + printf("found union field %s %i -> %i\n", prinst.field[i].name, prinst.field[i].progsofs+1, prinst.field[i].ofs+1); +#endif prinst.field[fnum].ofs = ofs = prinst.field[i].ofs+1; break; } if (prinst.field[i].type == ev_vector && prinst.field[i].progsofs+2 == (unsigned)progsofs) { -// printf("found union field %s %i -> %i\n", prinst.field[i].name, prinst.field[i].progsofs+2, prinst.field[i].ofs+2); +#ifdef MAPPING_DEBUG + printf("found union field %s %i -> %i\n", prinst.field[i].name, prinst.field[i].progsofs+2, prinst.field[i].ofs+2); +#endif prinst.field[fnum].ofs = ofs = prinst.field[i].ofs+2; break; } @@ -372,7 +385,9 @@ int PDECL QC_RegisterFieldVar(pubprogfuncs_t *ppf, unsigned int type, char *name prinst.field[fnum].progsofs = progsofs; -// printf("Field %s %i -> %i\n", name, prinst.field[fnum].progsofs,prinst.field[fnum].ofs); +#ifdef MAPPING_DEBUG + printf("Field %s %i -> %i\n", name, prinst.field[fnum].progsofs,prinst.field[fnum].ofs); +#endif //we've finished setting the structure return ofs - progfuncs->funcs.fieldadjust; @@ -409,10 +424,14 @@ void PDECL QC_AddSharedFieldVar(pubprogfuncs_t *ppf, int num, char *stringtable) for (i=1 ; inumfielddefs; i++) { if (!strcmp(pr_fielddefs16[i].s_name+stringtable, pr_globaldefs16[num].s_name+stringtable)) - { -// int old = *(int *)&pr_globals[pr_globaldefs16[num].ofs]; + { +#ifdef MAPPING_DEBUG + int old = *(int *)&pr_globals[pr_globaldefs16[num].ofs]; +#endif *(int *)&pr_globals[pr_globaldefs16[num].ofs] = QC_RegisterFieldVar(&progfuncs->funcs, pr_fielddefs16[i].type, pr_globaldefs16[num].s_name+stringtable, -1, *(int *)&pr_globals[pr_globaldefs16[num].ofs]); -// printf("Field=%s global %i -> %i\n", pr_globaldefs16[num].s_name+stringtable, old, *(volatile int *)&pr_globals[pr_globaldefs16[num].ofs]); +#ifdef MAPPING_DEBUG + printf("Field=%s global %i -> %i\n", pr_globaldefs16[num].s_name+stringtable, old, *(volatile int *)&pr_globals[pr_globaldefs16[num].ofs]); +#endif return; } } @@ -422,9 +441,13 @@ void PDECL QC_AddSharedFieldVar(pubprogfuncs_t *ppf, int num, char *stringtable) o = prinst.field[i].progsofs; if (o == *(unsigned int *)&pr_globals[pr_globaldefs16[num].ofs]) { -// int old = *(int *)&pr_globals[pr_globaldefs16[num].ofs]; +#ifdef MAPPING_DEBUG + int old = *(int *)&pr_globals[pr_globaldefs16[num].ofs]; +#endif *(int *)&pr_globals[pr_globaldefs16[num].ofs] = prinst.field[i].ofs-progfuncs->funcs.fieldadjust; -// printf("Field global=%s %i -> %i\n", pr_globaldefs16[num].s_name+stringtable, old, *(volatile int *)&pr_globals[pr_globaldefs16[num].ofs]); +#ifdef MAPPING_DEBUG + printf("Field global=%s %i -> %i\n", pr_globaldefs16[num].s_name+stringtable, old, *(volatile int *)&pr_globals[pr_globaldefs16[num].ofs]); +#endif return; } } diff --git a/engine/qclib/progsint.h b/engine/qclib/progsint.h index 5649f6524..51c6a81db 100644 --- a/engine/qclib/progsint.h +++ b/engine/qclib/progsint.h @@ -111,7 +111,7 @@ int reorganisefields; //pr_exec.c -#define MAX_STACK_DEPTH 64 +#define MAX_STACK_DEPTH 1024 //insanely high value requried for xonotic. prstack_t pr_stack[MAX_STACK_DEPTH]; #define pr_stack prinst.pr_stack int pr_depth; diff --git a/engine/qclib/progslib.h b/engine/qclib/progslib.h index 5aaf9bd3e..1a9259eea 100644 --- a/engine/qclib/progslib.h +++ b/engine/qclib/progslib.h @@ -256,7 +256,7 @@ typedef union eval_s #define PR_SaveEnts(pf, buf, size, maxsize, mode) (*pf->save_ents) (pf, buf, size, maxsize, mode) #define EDICT_NUM(pf, num) (*pf->EDICT_NUM) (pf, num) -#define NUM_FOR_EDICT(pf, e) (*pf->NUM_FOR_EDICT) (pf, e) +#define NUM_FOR_EDICT(pf, e) (*pf->NUM_FOR_EDICT) (pf, (struct edict_s*)(e)) #define SetGlobalEdict(pf, ed, ofs) (*pf->SetGlobalEdict) (pf, ed, ofs) #define PR_VarString(pf,first) (*pf->VarString) (pf,first) diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index 8aee71658..6bd08e441 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -318,6 +318,7 @@ typedef struct QCC_type_s unsigned int size; pbool typedefed:1; pbool vargs:1; + pbool vargcount:1; char *name; char *aname; } QCC_type_t; @@ -330,6 +331,7 @@ typedef struct temp_s { #ifdef WRITEASM struct QCC_def_s *lastfunc; #endif + int laststatement; struct temp_s *next; int used; unsigned int size; @@ -347,6 +349,7 @@ typedef struct QCC_def_s gofs_t ofs; struct QCC_def_s *scope; // function the var was defined in, or NULL struct QCC_def_s *deftail; // arrays and structs create multiple globaldef objects providing different types at the different parts of the single object (struct), or alternative names (vectors). this allows us to correctly set the const type based upon how its initialised. + struct QCC_def_s *generatedfor; int initialized; // 1 when a declaration included "= immediate" int constant; // 1 says we can use the value over and over again @@ -445,8 +448,10 @@ typedef struct char *value; char params[MAXCONSTANTPARAMS][MAXCONSTANTPARAMLENGTH]; int numparams; - pbool used; - pbool inside; + pbool used:1; + pbool inside:1; + pbool evil:1; + pbool varg:1; int namelen; } CompilerConstant_t; @@ -629,6 +634,7 @@ enum { WARN_UNDEFNOTDEFINED, WARN_PRECOMPILERMESSAGE, WARN_TOOMANYPARAMETERSFORFUNC, + WARN_TOOMANYPARAMETERSVARARGS, WARN_STRINGTOOLONG, WARN_BADTARGET, WARN_BADPRAGMA, @@ -696,7 +702,6 @@ enum { ERR_TOOMANYCASES, ERR_TOOMANYLABELS, ERR_TOOMANYOPENFILES, - ERR_TOOMANYPARAMETERSVARARGS, ERR_TOOMANYTOTALPARAMETERS, //these are probably yours, or qcc being fussy. @@ -835,6 +840,7 @@ void QCC_PR_PrintDefs (void); void QCC_PR_SkipToSemicolon (void); +extern char *pr_parm_argcount_name; #define MAX_EXTRA_PARMS 128 #ifdef MAX_EXTRA_PARMS extern char pr_parm_names[MAX_PARMS+MAX_EXTRA_PARMS][MAX_NAME]; @@ -862,8 +868,8 @@ extern QCC_string_t s_file; // filename for function definition extern QCC_def_t def_ret, def_parms[MAX_PARMS]; -void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, char *arrayname); -void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, char *arrayname); +void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, QCC_def_t *thearray, char *arrayname); +void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, QCC_def_t *thearray, char *arrayname); void QCC_PR_EmitClassFromFunction(QCC_def_t *scope, QCC_type_t *basetype); void PostCompile(void); diff --git a/engine/qclib/qcc_cmdlib.c b/engine/qclib/qcc_cmdlib.c index 9953d12ad..02ffb4058 100644 --- a/engine/qclib/qcc_cmdlib.c +++ b/engine/qclib/qcc_cmdlib.c @@ -886,11 +886,11 @@ static char *decodeUTF(int type, unsigned char *inputf, unsigned int inbytes, in { case UTF16LE: w = 2; - maxperchar = 3; + maxperchar = 4; break; case UTF16BE: w = 2; - maxperchar = 3; + maxperchar = 4; break; case UTF32LE: w = 4; @@ -910,14 +910,25 @@ static char *decodeUTF(int type, unsigned char *inputf, unsigned int inbytes, in { switch(type) { - default: case UTF16LE: - inc = *inputf++; - inc|= (*inputf++)<<8; - break; case UTF16BE: - inc = (*inputf++)<<8; - inc|= *inputf++; + inc = inputf[type==UTF16BE]; + inc|= inputf[type==UTF16LE]<<8; + inputf += 2; + //handle surrogates + if (inc >= 0xd800u && inc < 0xdc00u && i+1 < chars) + { + unsigned int l; + + l = inputf[type==UTF16BE]; + l|= inputf[type==UTF16LE]<<8; + if (l >= 0xdc00u && l < 0xe000u) + { + inputf+=2; + inc = ((inc & 0x3ffu)<<10) | (l & 0x3ffu) + 0x10000; + i++; + } + } break; case UTF32LE: inc = *inputf++; diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index d6dc4fe3f..a2e67945e 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -146,6 +146,7 @@ QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign, p QCC_def_t *QCC_PR_GenerateFunctionCall (QCC_def_t *newself, QCC_def_t *func, QCC_def_t *arglist[], QCC_type_t *argtypelist[], int argcount); void QCC_Marshal_Locals(int firststatement, int laststatement); QCC_def_t *QCC_PR_ParseArrayPointer (QCC_def_t *d, pbool allowarrayassign, pbool makestructpointers); +QCC_def_t *QCC_LoadFromArray(QCC_def_t *base, QCC_def_t *index, QCC_type_t *t, pbool preserve); QCC_ref_t *QCC_DefToRef(QCC_ref_t *ref, QCC_def_t *def); //ref is a buffer to write into, to avoid excessive allocs QCC_def_t *QCC_RefToDef(QCC_ref_t *ref, pbool freetemps); @@ -1301,6 +1302,27 @@ static int QCC_ShouldConvert(QCC_def_t *var, etype_t wanted) /*impossible*/ return -1; } +QCC_def_t *QCC_SupplyConversionForAssignment(QCC_def_t *to, QCC_def_t *from, etype_t wanted, pbool fatal) +{ + extern char *basictypenames[]; + int o; + + o = QCC_ShouldConvert(from, wanted); + + if (o == 0) //type already matches + return from; + if (flag_typeexplicit) + QCC_PR_ParseErrorPrintDef(ERR_TYPEMISMATCH, from, "Implicit type mismatch on assignment to %s. Needed %s, got %s.", to->name, basictypenames[wanted], basictypenames[from->type->type]); + if (o < 0) + { + if (fatal && wanted != ev_variant && from->type->type != ev_variant) + QCC_PR_ParseErrorPrintDef(ERR_TYPEMISMATCH, from, "Implicit type mismatch on assignment to %s. Needed %s, got %s.", to->name, basictypenames[wanted], basictypenames[from->type->type]); + else + return from; + } + + return QCC_PR_Statement(&pr_opcodes[o], from, NULL, NULL); //conversion return value +} QCC_def_t *QCC_SupplyConversion(QCC_def_t *var, etype_t wanted, pbool fatal) { extern char *basictypenames[]; @@ -1419,6 +1441,8 @@ static QCC_def_t *QCC_GetTemp(QCC_type_t *type) numtemps+=type->size; } + t->laststatement = numstatements; + var_c->s_file = s_file; var_c->s_line = pr_source_line; @@ -1784,6 +1808,42 @@ int QCC_PR_FindSourceForTemp(QCC_def_t *tempdef, int op, pbool *need_lock) return st; } + +int QCC_PR_FindSourceForAssignedOffset(int ofs, int firstst) +{ + int st = -1; + for (st = numstatements-1; st>=firstst; st--) + { + if (statements[st].c == ofs && OpAssignsToC(statements[st].op)) + return st; + if (statements[st].b == ofs && OpAssignsToB(statements[st].op)) + return st; + } + return -1; +} + +pbool QCC_Temp_Describe(QCC_def_t *def, char *buffer, int buffersize) +{ + QCC_dstatement_t *s; + int st; + temp_t *t = def->temp; + if (!t) + return false; + if (t->lastfunc != pr_scope) + return false; + st = QCC_PR_FindSourceForAssignedOffset(def->ofs, t->laststatement); + if (st == -1) + return false; + s = &statements[st]; + switch(s->op) + { + default: + _snprintf(buffer, buffersize, "%s %s %s", QCC_VarAtOffset(s->a, 1), pr_opcodes[s->op].name, QCC_VarAtOffset(s->b, 1)); + break; + } + return true; +} + QCC_dstatement_t *QCC_PR_SimpleStatement( int op, int var_a, int var_b, int var_c, int force); QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t *var_b, QCC_dstatement_t **outstatement, unsigned int flags) @@ -3502,6 +3562,12 @@ QCC_def_t *QCC_PR_GenerateFunctionCall (QCC_def_t *newself, QCC_def_t *func, QCC } } + if (func->type->vargcount) + { + QCC_def_t *va_passcount = QCC_PR_GetDef(type_float, "__va_count", NULL, true, 0, 0); + QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(argcount), va_passcount, NULL, 0)); + } + //if the return value was in use, save it off now, so that it doesn't get clobbered if (def_ret.temp->used) { @@ -3729,6 +3795,25 @@ QCC_def_t *QCC_PR_ParseFunctionCall (QCC_ref_t *funcref) //warning, the func cou QCC_PR_Expect(")"); return d; } + if (!strcmp(func->name, "va_arg") || !strcmp(func->name, "...")) //second for compat with gmqcc + { + QCC_def_t *va_list; + QCC_def_t *idx; + QCC_type_t *type; + va_list = QCC_PR_GetDef(type_vector, "__va_list", pr_scope, false, 0, 0); + idx = QCC_PR_Expression (TOP_PRIORITY, EXPR_DISALLOW_COMMA); + idx = QCC_PR_Statement(&pr_opcodes[OP_MUL_F], idx, QCC_MakeFloatConst(3), NULL); + QCC_PR_Expect(","); + type = QCC_PR_ParseType(false, false); + QCC_PR_Expect(")"); + if (!va_list || !va_list->arraysize) + QCC_PR_ParseError (ERR_TYPEMISMATCHPARM, "va_arg() intrinsic only works inside varadic functions"); + + if (!func->initialized) + func->initialized = 3; + func->references++; + return QCC_LoadFromArray(va_list, idx, type, false); + } if (!strcmp(func->name, "random")) { QCC_def_t *old = NULL; @@ -4175,7 +4260,7 @@ QCC_def_t *QCC_PR_ParseFunctionCall (QCC_ref_t *funcref) //warning, the func cou { char genfunc[2048]; sprintf(genfunc, "spawnfunc_%s", rettype->name); - func = QCC_PR_GetDef(type_function, genfunc, NULL, true, 0, false); + func = QCC_PR_GetDef(type_function, genfunc, NULL, true, 0, GDF_CONST); func->references++; QCC_FreeTemp(QCC_PR_GenerateFunctionCall(NULL, func, NULL, NULL, 0)); @@ -4267,11 +4352,15 @@ QCC_def_t *QCC_PR_ParseFunctionCall (QCC_ref_t *funcref) //warning, the func cou else p = t->params[arg].type; - if (extraparms && arg >= MAX_PARMS) - QCC_PR_ParseErrorPrintDef (ERR_TOOMANYPARAMETERSVARARGS, func, "More than %i parameters on varargs function", MAX_PARMS); - else if (arg >= MAX_PARMS+MAX_EXTRA_PARMS) + if (arg >= MAX_PARMS+MAX_EXTRA_PARMS) QCC_PR_ParseErrorPrintDef (ERR_TOOMANYTOTALPARAMETERS, func, "More than %i parameters", MAX_PARMS+MAX_EXTRA_PARMS); - if (!extraparms && arg >= t->num_parms && !p) + else if (extraparms && arg >= MAX_PARMS && !t->vargcount) + { + //vararg builtins cannot accept more than 8 args. they can't tell if they got more, and wouldn't know where to read them. + QCC_PR_ParseWarning (WARN_TOOMANYPARAMETERSVARARGS, "More than %i parameters on varargs function", MAX_PARMS); + QCC_PR_ParsePrintDef(WARN_TOOMANYPARAMETERSVARARGS, func); + } + else if (!extraparms && arg >= t->num_parms && !p) { QCC_PR_ParseWarning (WARN_TOOMANYPARAMETERSFORFUNC, "too many parameters"); QCC_PR_ParsePrintDef(WARN_TOOMANYPARAMETERSFORFUNC, func); @@ -4359,7 +4448,10 @@ QCC_def_t *QCC_PR_ParseFunctionCall (QCC_ref_t *funcref) //warning, the func cou QCC_PR_ParsePrintDef(WARN_LAXCAST, func); } else - QCC_PR_ParseErrorPrintDef (ERR_TYPEMISMATCHPARM, func, "type mismatch on parm %i: %s should be %s", arg+1, TypeName(e->type, typebuf1, sizeof(typebuf1)), TypeName(p, typebuf2, sizeof(typebuf2))); + { + QCC_PR_ParseWarning (ERR_TYPEMISMATCHPARM, "type mismatch on parm %i: %s should be %s", arg+1, TypeName(e->type, typebuf1, sizeof(typebuf1)), TypeName(p, typebuf2, sizeof(typebuf2))); + QCC_PR_ParsePrintDef(ERR_TYPEMISMATCHPARM, func); + } } } p = e->type; @@ -4983,7 +5075,9 @@ static QCC_ref_t *QCC_PR_ParseField(QCC_ref_t *refbuf, QCC_ref_t *lhs) if (field->cast->type == ev_field || field->cast->type == ev_variant) { //fields are generally always readonly. that refers to the field def itself, rather than products of said field. - lhs = QCC_PR_BuildRef(refbuf, REF_FIELD, QCC_RefToDef(lhs, true), QCC_RefToDef(field, true), (field->cast->type == ev_field)?field->cast->aux_type:type_variant, lhs->readonly); + //entities, like 'world' might also be consts. just ignore that fact. the def itself is not assigned, but the fields of said def. + //the engine may have a problem with this, but the qcc has no way to referenced locations as readonly separately from the def itself. + lhs = QCC_PR_BuildRef(refbuf, REF_FIELD, QCC_RefToDef(lhs, true), QCC_RefToDef(field, true), (field->cast->type == ev_field)?field->cast->aux_type:type_variant, false); } else { @@ -5402,6 +5496,7 @@ QCC_ref_t *QCC_PR_ParseRefValue (QCC_ref_t *refbuf, QCC_type_t *assumeclass, pbo (!strcmp(name, "randomv")) || (!strcmp(name, "sizeof")) || (!strcmp(name, "entnum")) || + (!strcmp(name, "va_arg")) || (!strcmp(name, "_"))) //intrinsics, any old function with no args will do. { d = QCC_PR_GetDef (type_function, name, NULL, true, 0, false); @@ -5505,7 +5600,10 @@ QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags) qcc_usefulstatement=true; e = QCC_PR_Term (0); if (e->constant) + { QCC_PR_ParseWarning(WARN_ASSIGNMENTTOCONSTANT, "Assignment to constant %s", e->name); + QCC_PR_ParsePrintDef(WARN_ASSIGNMENTTOCONSTANT, e); + } if (e->temp) QCC_PR_ParseWarning(WARN_ASSIGNMENTTOCONSTANT, "Hey! That's a temp! ++ operators cannot work on temps!"); switch (e->type->type) @@ -5527,7 +5625,10 @@ QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags) qcc_usefulstatement=true; e = QCC_PR_Term (0); if (e->constant) + { QCC_PR_ParseWarning(WARN_ASSIGNMENTTOCONSTANT, "Assignment to constant %s", e->name); + QCC_PR_ParsePrintDef(WARN_ASSIGNMENTTOCONSTANT, e); + } if (e->temp) QCC_PR_ParseWarning(WARN_ASSIGNMENTTOCONSTANT, "Hey! That's a temp! -- operators cannot work on temps!"); switch (e->type->type) @@ -5957,7 +6058,7 @@ void QCC_StoreToArray(QCC_def_t *base, QCC_def_t *index, QCC_def_t *source, QCC_ else { base->references++; - funcretr = QCC_PR_GetDef(NULL, qcva("ArraySet*%s", base->name), NULL, false, 0, false); + funcretr = QCC_PR_GetDef(NULL, qcva("ArraySet*%s", base->name), base->scope, false, 0, GDF_CONST|(base->scope?GDF_STATIC:0)); if (!funcretr) { QCC_type_t *arraysetfunc = qccHunkAlloc(sizeof(*arraysetfunc)); @@ -5970,7 +6071,8 @@ void QCC_StoreToArray(QCC_def_t *base, QCC_def_t *index, QCC_def_t *source, QCC_ arraysetfunc->name = "ArraySet"; fparms[0].type = type_float; fparms[1].type = base->type; - funcretr = QCC_PR_GetDef(arraysetfunc, qcva("ArraySet*%s", base->name), NULL, true, 0, false); + funcretr = QCC_PR_GetDef(arraysetfunc, qcva("ArraySet*%s", base->name), base->scope, true, 0, GDF_CONST|(base->scope?GDF_STATIC:0)); + funcretr->generatedfor = base; } if (source->type->type != t->type) @@ -6061,10 +6163,11 @@ QCC_def_t *QCC_LoadFromArray(QCC_def_t *base, QCC_def_t *index, QCC_type_t *t, p flags = preserve?STFL_PRESERVEA:0; index = QCC_PR_StatementFlags(&pr_opcodes[OP_CONV_ITOF], index, NULL, NULL, preserve?STFL_PRESERVEA:0); } - else if (index->type->type != ev_float) + else { flags = preserve?STFL_PRESERVEA|STFL_PRESERVEB:0; - QCC_PR_ParseErrorPrintDef(ERR_TYPEMISMATCH, base, "array index is not a single numeric value"); + if (index->type->type != ev_float) + QCC_PR_ParseErrorPrintDef(ERR_TYPEMISMATCH, base, "array index is not a single numeric value"); } /*hexen2 format has opcodes to read arrays (but has no way to write)*/ @@ -6083,6 +6186,7 @@ QCC_def_t *QCC_LoadFromArray(QCC_def_t *base, QCC_def_t *index, QCC_type_t *t, p //hexen2 uses element indicies. we internally use words. //words means you can pack vectors into structs without the offset needing to be a multiple of 3. //as its floats, I'm going to try using 0/0.33/0.66 just for the luls + //FIXME: we may very well have a *3 already, dividing by 3 again is crazy. index = QCC_PR_StatementFlags(&pr_opcodes[OP_DIV_F], index, QCC_MakeFloatConst(3), NULL, flags&STFL_PRESERVEA); flags &= ~STFL_PRESERVEB; base = QCC_PR_StatementFlags(&pr_opcodes[OP_FETCH_GBL_V], base, index, NULL, flags); //get pointer to precise def. @@ -6111,7 +6215,7 @@ QCC_def_t *QCC_LoadFromArray(QCC_def_t *base, QCC_def_t *index, QCC_type_t *t, p base->references++; - funcretr = QCC_PR_GetDef(NULL, qcva("ArrayGet*%s", base->name), NULL, false, 0, false); + funcretr = QCC_PR_GetDef(NULL, qcva("ArrayGet*%s", base->name), base->scope, false, 0, GDF_CONST|(base->scope?GDF_STATIC:0)); if (!funcretr) { QCC_type_t *ftype = qccHunkAlloc(sizeof(*ftype)); @@ -6123,7 +6227,10 @@ QCC_def_t *QCC_LoadFromArray(QCC_def_t *base, QCC_def_t *index, QCC_type_t *t, p ftype->num_parms = 1; ftype->name = "ArrayGet"; fparms[0].type = type_float; - funcretr = QCC_PR_GetDef(ftype, qcva("ArrayGet*%s", base->name), NULL, true, 0, false); + funcretr = QCC_PR_GetDef(ftype, qcva("ArrayGet*%s", base->name), base->scope, true, 0, GDF_CONST|(base->scope?GDF_STATIC:0)); + funcretr->generatedfor = base; + if (!funcretr->constant) + printf("not constant?\n"); } itmp = index->temp; @@ -6134,6 +6241,7 @@ QCC_def_t *QCC_LoadFromArray(QCC_def_t *base, QCC_def_t *index, QCC_type_t *t, p if (base->type->type == ev_vector) { + //FIXME: we may very well have a *3 already, dividing by 3 again is crazy. args[0] = QCC_PR_Statement(&pr_opcodes[OP_DIV_F], QCC_SupplyConversion(index, ev_float, true), QCC_MakeFloatConst(3), NULL); base = QCC_PR_GenerateFunctionCall(NULL, funcretr, args, &type_float, 1); base->type = t; @@ -6287,7 +6395,12 @@ QCC_def_t *QCC_StoreToRef(QCC_ref_t *dest, QCC_def_t *source, pbool readable, pb QCC_ref_t ptrref; QCC_type_t *t = source->type; if (dest->readonly) + { QCC_PR_ParseWarning(WARN_ASSIGNMENTTOCONSTANT, "Assignment to constant %s", dest->base->name); + QCC_PR_ParsePrintDef(WARN_ASSIGNMENTTOCONSTANT, dest->base); + if (dest->index) + QCC_PR_ParsePrintDef(WARN_ASSIGNMENTTOCONSTANT, dest->index); + } if (source->type->type == ev_integer && source->constant && !G_INT(source->ofs)) { @@ -6577,13 +6690,10 @@ QCC_opcode_t *QCC_PR_ChooseOpcode(QCC_def_t *lhs, QCC_def_t *rhs, QCC_opcode_t * op = oldop; else { - if (flag_laxcasts) - { - op = oldop; - QCC_PR_ParseWarning(WARN_LAXCAST, "type mismatch for %s (%s and %s)", oldop->name, lhs->type->name, rhs->type->name); - } - else - QCC_PR_ParseError (ERR_TYPEMISMATCH, "type mismatch for %s (%s and %s)", oldop->name, lhs->type->name, rhs->type->name); + op = oldop; + QCC_PR_ParseWarning(flag_laxcasts?WARN_LAXCAST:ERR_TYPEMISMATCH, "type mismatch for %s (%s and %s)", oldop->name, lhs->type->name, rhs->type->name); + QCC_PR_ParsePrintDef(flag_laxcasts?WARN_LAXCAST:ERR_TYPEMISMATCH, lhs); + QCC_PR_ParsePrintDef(flag_laxcasts?WARN_LAXCAST:ERR_TYPEMISMATCH, rhs); } } else @@ -6737,9 +6847,14 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) if (ops) { if (lhsr->postinc) - QCC_PR_ParseError(ERR_INTERNAL, "Assignment to lvalue"); + QCC_PR_ParseError(ERR_INTERNAL, "Assignment to post-inc result"); if (lhsr->readonly) + { QCC_PR_ParseWarning(WARN_ASSIGNMENTTOCONSTANT, "Assignment to lvalue"); + QCC_PR_ParsePrintDef(WARN_ASSIGNMENTTOCONSTANT, lhsr->base); + if (lhsr->index) + QCC_PR_ParsePrintDef(WARN_ASSIGNMENTTOCONSTANT, lhsr->index); + } rhsr = QCC_PR_RefExpression (&rhsbuf, priority, exprflags | EXPR_DISALLOW_ARRAYASSIGN); @@ -6785,7 +6900,7 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) //convert so we don't have issues with: i = (int)(float)(i+f) //this will also catch things like vec *= vec; which would be trying to store a float into a vector. - rhsd = QCC_SupplyConversion(rhsd, lhsr->cast->type, true); + rhsd = QCC_SupplyConversionForAssignment(lhsr->base, rhsd, lhsr->cast->type, true); } else { @@ -6799,7 +6914,7 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) } } else - rhsd = QCC_SupplyConversion(rhsd, lhsr->cast->type, true); + rhsd = QCC_SupplyConversionForAssignment(lhsr->base, rhsd, lhsr->cast->type, true); } rhsd = QCC_StoreToRef(lhsr, rhsd, true, false); //FIXME: this should not always be true, but we don't know if the caller actually needs it qcc_usefulstatement = true; @@ -8993,8 +9108,8 @@ QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_type_t *type) return f; } - if (type->num_parms < 0) - QCC_PR_ParseError (ERR_FUNCTIONWITHVARGS, "QC function with variable arguments and function body"); +// if (type->vargs) +// QCC_PR_ParseError (ERR_FUNCTIONWITHVARGS, "QC function with variable arguments and function body"); f->builtin = 0; // @@ -9041,6 +9156,49 @@ QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_type_t *type) } } + if (type->vargcount) + { + if (!pr_parm_argcount_name) + QCC_Error(ERR_INTERNAL, "I forgot what the va_count argument is meant to be called"); + else + { + QCC_def_t *va_passcount = QCC_PR_GetDef(type_float, "__va_count", NULL, true, 0, 0); + QCC_def_t *va_count = QCC_PR_GetDef(type_float, pr_parm_argcount_name, pr_scope, true, 0, 0); + QCC_PR_SimpleStatement(OP_SUB_F, va_passcount->ofs, QCC_MakeFloatConst(type->num_parms)->ofs, va_count->ofs, false); + } + } + + if (type->vargs) + { + int i; + int maxvacount = 24; + QCC_def_t *a; + pbool opcodeextensions = QCC_OPCodeValid(&pr_opcodes[OP_FETCH_GBL_F]) || QCC_OPCodeValid(&pr_opcodes[OP_LOADA_F]); //if we have opcode extensions, we can use those instead of via a function. this allows to use proper locals for the vargs. + QCC_def_t *va_list; + va_list = QCC_PR_GetDef(type_vector, "__va_list", pr_scope, true, maxvacount, opcodeextensions?0:GDF_STATIC); + + for (i = 0; i < maxvacount; i++) + { + QCC_ref_t varef; + u = i + type->num_parms; + if (u >= MAX_PARMS) + { + if (!extra_parms[u - MAX_PARMS]) + { + e2 = (QCC_def_t *) qccHunkAlloc (sizeof(QCC_def_t)); + e2->name = "extra parm"; + e2->ofs = QCC_GetFreeGlobalOffsetSpace(3); + extra_parms[u - MAX_PARMS] = e2; + } + a = extra_parms[u - MAX_PARMS]; + } + else + a = &def_parms[u]; + a->type = type_vector; + QCC_StoreToRef(QCC_PR_BuildRef(&varef, REF_ARRAY, va_list, QCC_MakeIntConst(i*3), type_vector, false), a, false, false); + } + } + QCC_RemapLockedTemps(-1, -1); /*if (pr_classtype) @@ -9317,11 +9475,11 @@ QCC_def_t *QCC_PR_EmitArrayGetVector(QCC_def_t *array) return func; } -void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, char *arrayname) +void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, QCC_def_t *thearray, char *arrayname) { QCC_def_t *vectortrick; QCC_dfunction_t *df; - QCC_def_t *def, *index; + QCC_def_t *index; QCC_dstatement_t *st; QCC_def_t *eq; @@ -9335,15 +9493,14 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, char *arrayname) fasttrackpossible = NULL; s_file = scope->s_file; - def = QCC_PR_GetDef(NULL, arrayname, NULL, false, 0, false); - if (def->type->type == ev_vector) - numslots = def->arraysize; + if (thearray->type->type == ev_vector) + numslots = thearray->arraysize; else - numslots = def->arraysize*def->type->size; + numslots = thearray->arraysize*thearray->type->size; - if (numslots >= 15 && def->type->type != ev_vector) - vectortrick = QCC_PR_EmitArrayGetVector(def); + if (numslots >= 15 && thearray->type->type != ev_vector) + vectortrick = QCC_PR_EmitArrayGetVector(thearray); else vectortrick = NULL; @@ -9355,7 +9512,8 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, char *arrayname) df = &functions[numfunctions]; numfunctions++; - df->s_file = 0; + pr_source_line = thearray->s_line; //thankfully these functions are emitted after compilation. + df->s_file = thearray->s_file; df->s_name = QCC_CopyString(scope->name); df->first_statement = numstatements; df->parm_size[0] = 1; @@ -9371,10 +9529,10 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, char *arrayname) //fetch_gbl takes: (float size, variant array[]), float index, variant pos //note that the array size is coded into the globals, one index before the array. - if (def->type->type == ev_vector) - QCC_PR_Statement3(&pr_opcodes[OP_FETCH_GBL_V], def, index, &def_ret, true); + if (thearray->type->type == ev_vector) + QCC_PR_Statement3(&pr_opcodes[OP_FETCH_GBL_V], thearray, index, &def_ret, true); else - QCC_PR_Statement3(&pr_opcodes[OP_FETCH_GBL_F], def, index, &def_ret, true); + QCC_PR_Statement3(&pr_opcodes[OP_FETCH_GBL_F], thearray, index, &def_ret, true); QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_RETURN], &def_ret, NULL, NULL)); @@ -9390,8 +9548,8 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, char *arrayname) //we need to work out which part, x/y/z that it's stored in. //0,1,2 = i - ((int)i/3 *) 3; - div3 = QCC_PR_GetDef(type_float, "div3___", def, true, 0, false); - intdiv3 = QCC_PR_GetDef(type_float, "intdiv3___", def, true, 0, false); + div3 = QCC_PR_GetDef(type_float, "div3___", thearray, true, 0, false); + intdiv3 = QCC_PR_GetDef(type_float, "intdiv3___", thearray, true, 0, false); eq = QCC_PR_Statement(pr_opcodes+OP_GE_F, index, QCC_MakeFloatConst((float)numslots), NULL); //escape clause - should call some sort of error function instead.. that'd rule! QCC_FreeTemp(QCC_PR_Statement(pr_opcodes+OP_IFNOT_I, eq, 0, &st)); @@ -9439,7 +9597,7 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, char *arrayname) else { QCC_PR_Statement3(pr_opcodes+OP_BITAND_F, index, index, index, false); - QCC_PR_ArrayRecurseDivideRegular(def, index, 0, numslots); + QCC_PR_ArrayRecurseDivideRegular(thearray, index, 0, numslots); } QCC_PR_Statement(pr_opcodes+OP_RETURN, QCC_MakeFloatConst(0), 0, NULL); @@ -9498,10 +9656,10 @@ void QCC_PR_ArraySetRecurseDivide(QCC_def_t *array, QCC_def_t *index, QCC_def_t } } -void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, char *arrayname) +void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, QCC_def_t *thearray, char *arrayname) { QCC_dfunction_t *df; - QCC_def_t *def, *index, *value; + QCC_def_t *index, *value; QCC_def_t *fasttrackpossible; int numslots; @@ -9512,13 +9670,12 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, char *arrayname) fasttrackpossible = NULL; s_file = scope->s_file; - def = QCC_PR_GetDef(NULL, arrayname, NULL, false, 0, false); pr_scope = scope; - if (def->type->type == ev_vector) - numslots = def->arraysize; + if (thearray->type->type == ev_vector) + numslots = thearray->arraysize; else - numslots = def->arraysize*def->type->size; + numslots = thearray->arraysize*thearray->type->size; if (numfunctions >= MAX_FUNCTIONS) QCC_Error(ERR_INTERNAL, "Too many function defs"); @@ -9526,15 +9683,16 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, char *arrayname) df = &functions[numfunctions]; numfunctions++; - df->s_file = 0; + pr_source_line = thearray->s_line; //thankfully these functions are emitted after compilation. + df->s_file = thearray->s_file; df->s_name = QCC_CopyString(scope->name); df->first_statement = numstatements; df->parm_size[0] = 1; - df->parm_size[1] = def->type->size; + df->parm_size[1] = thearray->type->size; df->numparms = 2; locals_start = locals_end = FIRST_LOCAL; - index = QCC_PR_GetDef(type_float, "indexs___", def, true, 0, false); - value = QCC_PR_GetDef(def->type, "value___", def, true, 0, false); + index = QCC_PR_GetDef(type_float, "indexs___", pr_scope, true, 0, false); + value = QCC_PR_GetDef(thearray->type, "value___", pr_scope, true, 0, false); G_FUNCTION(scope->ofs) = df - functions; @@ -9546,11 +9704,11 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, char *arrayname) //note that the array size is coded into the globals, one index before the array. QCC_PR_Statement3(&pr_opcodes[OP_CONV_FTOI], index, NULL, index, true); //address stuff is integer based, but standard qc (which this accelerates in supported engines) only supports floats - QCC_PR_SimpleStatement (OP_BOUNDCHECK, index->ofs, ((int*)qcc_pr_globals)[def->ofs-1]+1, 0, true);//annoy the programmer. :p - if (def->type->type == ev_vector)//shift it upwards for larger types - QCC_PR_Statement3(&pr_opcodes[OP_MUL_I], index, QCC_MakeIntConst(def->type->size), index, true); - QCC_PR_Statement3(&pr_opcodes[OP_GLOBALADDRESS], def, index, index, true); //comes with built in add - if (def->type->type == ev_vector) + QCC_PR_SimpleStatement (OP_BOUNDCHECK, index->ofs, ((int*)qcc_pr_globals)[thearray->ofs-1]+1, 0, true);//annoy the programmer. :p + if (thearray->type->type == ev_vector)//shift it upwards for larger types + QCC_PR_Statement3(&pr_opcodes[OP_MUL_I], index, QCC_MakeIntConst(thearray->type->size), index, true); + QCC_PR_Statement3(&pr_opcodes[OP_GLOBALADDRESS], thearray, index, index, true); //comes with built in add + if (thearray->type->type == ev_vector) QCC_PR_Statement3(&pr_opcodes[OP_STOREP_V], value, index, NULL, true); //*b = a else QCC_PR_Statement3(&pr_opcodes[OP_STOREP_F], value, index, NULL, true); @@ -9561,7 +9719,7 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, char *arrayname) } QCC_PR_Statement3(pr_opcodes+OP_BITAND_F, index, index, index, false); - QCC_PR_ArraySetRecurseDivide(def, index, value, 0, numslots); + QCC_PR_ArraySetRecurseDivide(thearray, index, value, 0, numslots); QCC_PR_Statement(pr_opcodes+OP_DONE, 0, 0, NULL); @@ -9730,8 +9888,8 @@ QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, char *name, QCC_def_t *scope, int a { if (!pHash_Get(&globalstable, "end_sys_fields")) first->references++; //anything above needs to be left in, and so warning about not using it is just going to pee people off. - if (!arraysize && first->type->type != ev_field) - first->constant = false; +// if (!arraysize && first->type->type != ev_field) +// first->constant = false; if (scope) pHash_Add(&localstable, first->name, first, qccHunkAlloc(sizeof(bucket_t))); else @@ -9948,9 +10106,9 @@ QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, char *name, QCC_def_t *scope, pbool if (scope && qccwarningaction[WARN_SAMENAMEASGLOBAL]) { def = QCC_PR_GetDef(NULL, name, NULL, false, arraysize, false); - if (def) - { - QCC_PR_ParseWarning(WARN_SAMENAMEASGLOBAL, "Local \"%s\" hides global with same name", name); + if (def && def->type->type == type->type) + { //allow type differences. this means that arguments called 'min' or 'mins' are accepted with the 'min' builtin or the 'mins' field in existance. + QCC_PR_ParseWarning(WARN_SAMENAMEASGLOBAL, "Local \"%s\" hides global with same name and type", name); QCC_PR_ParsePrintDef(WARN_SAMENAMEASGLOBAL, def); } } diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 972351151..607dd27f7 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -97,7 +97,7 @@ QCC_def_t def_ret, def_parms[MAX_PARMS]; //QCC_def_t *def_for_type[9] = {&def_void, &def_string, &def_float, &def_vector, &def_entity, &def_field, &def_function, &def_pointer, &def_integer}; -void QCC_PR_LexWhitespace (void); +void QCC_PR_LexWhitespace (pbool inhibitpreprocessor); @@ -747,7 +747,7 @@ pbool QCC_PR_Precompiler(void) while(1) { - QCC_PR_LexWhitespace(); + QCC_PR_LexWhitespace(false); if (!QCC_PR_SimpleGetToken()) { if (!*pr_file_p) @@ -1488,7 +1488,7 @@ void QCC_PR_LexString (void) if (len >= sizeof(pr_immediate_string)-1) QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_immediate_string)-1); - QCC_PR_LexWhitespace(); + QCC_PR_LexWhitespace(false); if (*pr_file_p == '\"') //have annother go { pr_file_p++; @@ -1835,11 +1835,11 @@ void QCC_PR_LexVector (void) } pr_token_type = tt_immediate; pr_immediate_type = type_vector; - QCC_PR_LexWhitespace (); + QCC_PR_LexWhitespace (false); for (i=0 ; i<3 ; i++) { pr_immediate.vector[i] = QCC_PR_LexFloat (); - QCC_PR_LexWhitespace (); + QCC_PR_LexWhitespace (false); if (*pr_file_p == '\'' && i == 1) { @@ -1920,7 +1920,7 @@ void QCC_PR_LexPunctuation (void) PR_LexWhitespace ============== */ -void QCC_PR_LexWhitespace (void) +void QCC_PR_LexWhitespace (pbool inhibitpreprocessor) { int c; @@ -1932,7 +1932,8 @@ void QCC_PR_LexWhitespace (void) if (c=='\n') { pr_file_p++; - QCC_PR_NewLine (false); + if (!inhibitpreprocessor) + QCC_PR_NewLine (false); if (!pr_file_p) return; } @@ -1950,7 +1951,8 @@ void QCC_PR_LexWhitespace (void) if (*pr_file_p == '\n') pr_file_p++; //don't break on eof. - QCC_PR_NewLine(false); + if (!inhibitpreprocessor) + QCC_PR_NewLine(false); continue; } @@ -1962,7 +1964,8 @@ void QCC_PR_LexWhitespace (void) { if (pr_file_p[0]=='\n') { - QCC_PR_NewLine(true); + if (!inhibitpreprocessor) + QCC_PR_NewLine(true); } if (pr_file_p[1] == 0) { @@ -2274,6 +2277,7 @@ CompilerConstant_t *QCC_PR_DefineName(char *name) cnst->used = false; cnst->numparams = 0; + cnst->evil = false; strcpy(cnst->name, name); cnst->namelen = strlen(name); cnst->value = cnst->name + strlen(cnst->name); @@ -2323,27 +2327,43 @@ void QCC_PR_ConditionCompilation(void) if (*pr_file_p == '(') { - s = pr_file_p+1; - while(*pr_file_p++) + pr_file_p++; + while(qcc_iswhitesameline(*pr_file_p)) + pr_file_p++; + s = pr_file_p; + for (;;) { - if (*pr_file_p == ',') + if (*pr_file_p == ',' || *pr_file_p == ')') { + int nl; + nl = pr_file_p-s; + while(qcc_iswhitesameline(s[nl])) + nl--; if (cnst->numparams >= MAXCONSTANTPARAMS) QCC_PR_ParseError(ERR_MACROTOOMANYPARMS, "May not have more than %i parameters to a macro", MAXCONSTANTPARAMS); - strncpy(cnst->params[cnst->numparams], s, pr_file_p-s); - cnst->params[cnst->numparams][pr_file_p-s] = '\0'; - cnst->numparams++; - pr_file_p++; + if (nl >= MAXCONSTANTPARAMLENGTH) + QCC_PR_ParseError(ERR_MACROTOOMANYPARMS, "parameter name is too long (max %i)", MAXCONSTANTPARAMLENGTH); + if (nl == 3 && s[0] == '.' && s[1] == '.' && s[2] == '.') + { + cnst->varg = true; + if (*pr_file_p != ')') + QCC_PR_ParseError(ERR_MACROTOOMANYPARMS, "varadic argument must be last"); + } + else + { + memcpy(cnst->params[cnst->numparams], s, nl); + cnst->params[cnst->numparams][nl] = '\0'; + cnst->numparams++; + } + if (*pr_file_p++ == ')') + break; + while(qcc_iswhitesameline(*pr_file_p)) + pr_file_p++; s = pr_file_p; } - if (*pr_file_p == ')') + if(!*pr_file_p++) { - if (cnst->numparams >= MAXCONSTANTPARAMS) - QCC_PR_ParseError(ERR_MACROTOOMANYPARMS, "May not have more than %i parameters to a macro", MAXCONSTANTPARAMS); - strncpy(cnst->params[cnst->numparams], s, pr_file_p-s); - cnst->params[cnst->numparams][pr_file_p-s] = '\0'; - cnst->numparams++; - pr_file_p++; + QCC_PR_ParseError(ERR_EXPECTED, "missing ) in macro parameter list", MAXCONSTANTPARAMS); break; } } @@ -2402,8 +2422,10 @@ so if present, the preceeding \\\n and following \\\n must become an actual \n i ; if (*exploitcheck == '#') { - QCC_PR_ParseWarning(WARN_EVILPREPROCESSOR, "preprocessor directive within preprocessor macro %s", cnst->name); *d++ = '\n'; + if (!cnst->evil) + QCC_PR_ParseWarning(WARN_EVILPREPROCESSOR, "preprocessor directive within preprocessor macro %s", cnst->name); + cnst->evil = true; preprocessorhack = true; } else if (preprocessorhack) @@ -2417,9 +2439,28 @@ so if present, the preceeding \\\n and following \\\n must become an actual \n i { break; } - - if (!quote && s[0]=='/'&&(s[1]=='/'||s[1]=='*')) - break; + if (!quote && s[0]=='/'&&s[1]=='/') + break; //c++ style comments can just be ignored + if (!quote && s[0]=='/'&&s[1]=='*') + { //multi-line c style comments become part of the define itself. this also negates the need for \ at the end of lines. + //although we don't bother embedding. + s+=2; + for(;;) + { + if (!s[0]) + { + QCC_PR_ParseWarning(WARN_DUPLICATEPRECOMPILER, "EOF inside quote in define %s", cnst->name); + break; + } + if (s[0]=='*'&&s[1]=='/') + { + s+=2; + break; + } + s++; + } + continue; + } if (*s == '\"') quote=!quote; @@ -2542,8 +2583,7 @@ int QCC_PR_CheckCompConst(void) int plevel=0; pr_file_p++; - while(*pr_file_p == ' ' || *pr_file_p == '\t') - pr_file_p++; + QCC_PR_LexWhitespace(false); start = pr_file_p; while(1) { @@ -2558,25 +2598,27 @@ int QCC_PR_CheckCompConst(void) plevel++; else if (!plevel && (*pr_file_p == ',' || *pr_file_p == ')')) { - paramoffset[param++] = start; - start = pr_file_p+1; - if (*pr_file_p == ')') + if (*pr_file_p == ',' && c->varg && param >= c->numparams) + ; //skip extra trailing , arguments if we're varging. + else { + paramoffset[param++] = start; + start = pr_file_p+1; + if (*pr_file_p == ')') + { + *pr_file_p = '\0'; + pr_file_p++; + break; + } *pr_file_p = '\0'; pr_file_p++; - break; + QCC_PR_LexWhitespace(false); + start = pr_file_p; + // move back by one char because we move forward by one at the end of the loop + pr_file_p--; + if (param == MAXCONSTANTPARAMS || param > c->numparams) + QCC_PR_ParseError(ERR_TOOMANYPARAMS, "Too many parameters in macro call"); } - *pr_file_p = '\0'; - pr_file_p++; - while(*pr_file_p == ' ' || *pr_file_p == '\t') - { - pr_file_p++; - start++; - } - // move back by one char because we move forward by one at the end of the loop - pr_file_p--; - if (param == MAXCONSTANTPARAMS) - QCC_PR_ParseError(ERR_TOOMANYPARAMS, "Too many parameters in macro call"); } else if (*pr_file_p == ')' ) plevel--; else if(*pr_file_p == '\n') @@ -2601,12 +2643,13 @@ int QCC_PR_CheckCompConst(void) { whitestart = bufferlen; starttok = pr_file_p; - while(qcc_iswhite(*pr_file_p)) //copy across whitespace + /*while(qcc_iswhite(*pr_file_p)) //copy across whitespace { if (!*pr_file_p) break; pr_file_p++; - } + }*/ + QCC_PR_LexWhitespace(true); if (starttok != pr_file_p) { QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, starttok, pr_file_p - starttok); @@ -2653,7 +2696,8 @@ int QCC_PR_CheckCompConst(void) { QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, "#", 1); QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, qcc_token, strlen(qcc_token)); - //QCC_PR_ParseWarning(0, "Stringification ignored"); + if (!c->evil) + QCC_PR_ParseWarning(0, "'#' is not followed by a macro parameter in %s", c->name); } continue; //already did this one } @@ -2663,7 +2707,7 @@ int QCC_PR_CheckCompConst(void) if (!pr_file_p) break; - for (p = 0; p < param; p++) + for (p = 0; p < c->numparams; p++) { if (!STRCMP(qcc_token, c->params[p])) { @@ -2671,7 +2715,9 @@ int QCC_PR_CheckCompConst(void) break; } } - if (p == param) + if (c->varg && !STRCMP(qcc_token, "__VA_ARGS__")) + QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, paramoffset[c->numparams], strlen(paramoffset[c->numparams])); + else if (p == c->numparams) QCC_PR_ExpandStrCat(&buffer, &bufferlen, &buffermax, qcc_token, strlen(qcc_token)); } @@ -2863,7 +2909,7 @@ void QCC_PR_Lex (void) return; } - QCC_PR_LexWhitespace (); + QCC_PR_LexWhitespace (false); pr_token_line_last = pr_token_line; pr_token_line = pr_source_line; @@ -2975,18 +3021,26 @@ void QCC_PR_Lex (void) //============================================================================= - +pbool QCC_Temp_Describe(QCC_def_t *def, char *buffer, int buffersize); void QCC_PR_ParsePrintDef (int type, QCC_def_t *def) { if (!qccwarningaction[type]) return; if (def->s_file) { - char buffer[512]; - if (flag_msvcstyle) - printf ("%s(%i) : %s %s is defined here\n", strings + def->s_file, def->s_line, TypeName(def->type, buffer, sizeof(buffer)), def->name); + char tybuffer[512]; + char tmbuffer[512]; + if (QCC_Temp_Describe(def, tmbuffer, sizeof(tmbuffer))) + { + printf ("%s:%i: (%s)(%s)\n", strings + def->s_file, def->s_line, TypeName(def->type, tybuffer, sizeof(tybuffer)), tmbuffer); + } else - printf ("%s:%i: %s %s is defined here\n", strings + def->s_file, def->s_line, TypeName(def->type, buffer, sizeof(buffer)), def->name); + { + if (flag_msvcstyle) + printf ("%s(%i) : %s %s is defined here\n", strings + def->s_file, def->s_line, TypeName(def->type, tybuffer, sizeof(tybuffer)), def->name); + else + printf ("%s:%i: %s %s is defined here\n", strings + def->s_file, def->s_line, TypeName(def->type, tybuffer, sizeof(tybuffer)), def->name); + } } } void *errorscope; @@ -3418,6 +3472,8 @@ int typecmp(QCC_type_t *a, QCC_type_t *b) return 1; if (a->vargs != b->vargs) return 1; + if (a->vargcount != b->vargcount) + return 1; if (a->size != b->size) return 1; @@ -3461,6 +3517,9 @@ int typecmp_lax(QCC_type_t *a, QCC_type_t *b) else if (a->size != b->size) return 1; + if (a->vargcount != b->vargcount) + return 1; + t = a->num_parms; minargs = t; t = b->num_parms; @@ -3714,6 +3773,7 @@ char pr_parm_names[MAX_PARMS+MAX_EXTRA_PARMS][MAX_NAME]; #else char pr_parm_names[MAX_PARMS][MAX_NAME]; #endif +char *pr_parm_argcount_name; int recursivefunctiontype; @@ -3734,6 +3794,8 @@ QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype) ftype->aux_type = returntype; // return type ftype->num_parms = 0; + if (definenames) + pr_parm_argcount_name = NULL; if (!QCC_PR_CheckToken (")")) { @@ -3788,7 +3850,22 @@ QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype) numparms++; } while (QCC_PR_CheckToken (",")); - QCC_PR_Expect (")"); + if (ftype->vargs) + { + if (!QCC_PR_CheckToken (")")) + { + name = QCC_PR_ParseName(); + if (definenames) + { + pr_parm_argcount_name = qccHunkAlloc(strlen(name)+1); + strcpy(pr_parm_argcount_name, name); + } + ftype->vargcount = true; + QCC_PR_Expect (")"); + } + } + else + QCC_PR_Expect (")"); } ftype->num_parms = numparms; ftype->params = qccHunkAlloc(sizeof(*ftype->params) * numparms); @@ -3812,6 +3889,7 @@ QCC_type_t *QCC_PR_ParseFunctionTypeReacc (int newtype, QCC_type_t *returntype) ftype->aux_type = returntype; // return type ftype->num_parms = 0; + pr_parm_argcount_name = NULL; if (!QCC_PR_CheckToken (")")) { diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c index bd562b9ab..02fc860df 100644 --- a/engine/qclib/qccmain.c +++ b/engine/qclib/qccmain.c @@ -23,7 +23,7 @@ pbool qcc_nopragmaoptimise; extern unsigned int locals_marshalled; pbool QCC_PR_SimpleGetToken (void); -void QCC_PR_LexWhitespace (void); +void QCC_PR_LexWhitespace (pbool inhibitpreprocessor); void *FS_ReadToMem(char *fname, void *membuf, int *len); void FS_CloseFromMem(void *mem); @@ -722,7 +722,7 @@ pbool QCC_WriteData (int crc) else { if (numpr_globals >= 32768) //not much of a different format. Rewrite output to get it working on original executors? - printf("An enhanced QCVM will be required (FTE/QF/KK)\n"); + printf("Globals exceeds 32k - an enhanced QCVM will be required\n"); else printf("Progs should run on any QuakeC VM\n"); break; @@ -1872,7 +1872,7 @@ int QCC_PR_FinishCompilation (void) // check to make sure all functions prototyped have code for (d=pr.def_head.next ; d ; d=d->next) { - if (d->type->type == ev_function && !d->scope)// function parms are ok + if (d->type->type == ev_function && d->constant)// function parms are ok { // f = G_FUNCTION(d->ofs); // if (!f || (!f->code && !f->builtin) ) @@ -1880,18 +1880,19 @@ int QCC_PR_FinishCompilation (void) { if (!strncmp(d->name, "ArrayGet*", 9)) { - QCC_PR_EmitArrayGetFunction(d, d->name+9); + QCC_PR_EmitArrayGetFunction(d, d->generatedfor, d->name+9); pr_scope = NULL; continue; } if (!strncmp(d->name, "ArraySet*", 9)) { - QCC_PR_EmitArraySetFunction(d, d->name+9); + QCC_PR_EmitArraySetFunction(d, d->generatedfor, d->name+9); pr_scope = NULL; continue; } if (!strncmp(d->name, "spawnfunc_", 10)) { + //not all of these will have a class defined, as some will be regular spawn functions, so don't error on that t = QCC_TypeForName(d->name+10); if (t) { @@ -3203,7 +3204,7 @@ void QCC_main (int argc, char **argv) //as part of the quake engine numpr_globals=0; Hash_InitTable(&globalstable, MAX_REGS/2, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS/2))); - Hash_InitTable(&localstable, MAX_REGS/2, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS/2))); + Hash_InitTable(&localstable, 128, qccHunkAlloc(Hash_BytesForBuckets(128))); Hash_InitTable(&floatconstdefstable, MAX_REGS/2+1, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS/2+1))); Hash_InitTable(&stringconstdefstable, MAX_REGS/2, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS/2))); Hash_InitTable(&stringconstdefstable_trans, 1000, qccHunkAlloc(Hash_BytesForBuckets(1000))); @@ -3380,7 +3381,7 @@ newstyle: } pr_file_p = qccmsrc; - QCC_PR_LexWhitespace(); + QCC_PR_LexWhitespace(false); qccmsrc = pr_file_p; s = qccmsrc; diff --git a/engine/server/net_preparse.c b/engine/server/net_preparse.c index dbd9ec273..4ed2bd808 100644 --- a/engine/server/net_preparse.c +++ b/engine/server/net_preparse.c @@ -578,6 +578,7 @@ static int multicasttype; static int requireextension; static qboolean ignoreprotocol; static int te_515sevilhackworkaround; +qboolean ssqc_deprecated_warned; #define svc_setfrags 14 #define svc_updatecolors 17 @@ -761,17 +762,19 @@ void NPP_NQFlush(void) default: if (te_515sevilhackworkaround) { - /*shift the data up by two bytes, but don't care about the first byte*/ - memmove(buffer+3, buffer+1, bufferlen-1); + if (sv.csqcdebug) + { + /*shift the data up by two bytes, but don't care about the first byte*/ + memmove(buffer+3, buffer+1, bufferlen-1); + /*add a length in the 2nd/3rd bytes, if needed*/ + buffer[1] = (bufferlen-1); + buffer[2] = (bufferlen-1) >> 8; + + bufferlen += 2; + } /*replace the svc itself*/ buffer[0] = svcfte_cgamepacket; - - /*add a length in the 2nd/3rd bytes*/ - buffer[1] = (bufferlen-1); - buffer[2] = (bufferlen-1) >> 8; - - bufferlen += 2; } break; case TENQ_EXPLOSION2: //happens with rogue. @@ -985,6 +988,9 @@ void NPP_NQWriteByte(int dest, qbyte data) //replacement write func (nq to qw) protocollen = 3; ignoreprotocol = true; break; + case svcfte_cgamepacket: + protocollen = sizeof(buffer); + break; default: Con_DPrintf("NQWriteByte: bad protocol %i\n", (int)data); protocollen = sizeof(buffer); @@ -1131,8 +1137,14 @@ void NPP_NQWriteByte(int dest, qbyte data) //replacement write func (nq to qw) else { te_515sevilhackworkaround = true; - Con_Printf("NQWriteByte: unknown tempentity %i\n", data); - PR_StackTrace(svprogfuncs); + if (!ssqc_deprecated_warned) + { + ssqc_deprecated_warned = true; + Con_Printf("NQWriteByte: invalid tempentity %i. Future errors will be dprinted. You may need to enable sv_csqcdebug.\n", data); + PR_StackTrace(svprogfuncs); + } + else + Con_DPrintf("NQWriteByte: unknown tempentity %i\n", data); } break; } @@ -1844,6 +1856,9 @@ void NPP_QWWriteByte(int dest, qbyte data) //replacement write func (nq to qw) case svc_setpause: protocollen = 2; break; + case svcfte_cgamepacket: + protocollen = sizeof(buffer); + break; default: Con_DPrintf("QWWriteByte: bad protocol %i\n", (int)data); protocollen = sizeof(buffer); diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index b8f36eb14..2d46badd9 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -96,6 +96,7 @@ char cvargroup_progs[] = "Progs variables"; evalc_t evalc_idealpitch, evalc_pitch_speed; +qboolean ssqc_deprecated_warned; int pr_teamfield; unsigned int h2infoplaque[2]; /*hexen2 stat*/ @@ -1342,6 +1343,8 @@ void Q_InitProgs(void) progsnum_t prnum, oldprnum=-1; int d1, d2; + ssqc_deprecated_warned = false; + QC_Clear(); Q_SetProgsParms(false); @@ -8659,48 +8662,6 @@ static void QCBUILTIN PF_ChangePic(pubprogfuncs_t *prinst, struct globalvars_s * } } - - - - -int SV_TagForName(int modelindex, char *tagname) -{ - model_t *model = SVPR_GetCModel(&sv.world, modelindex); - if (!model) - return 0; - - return Mod_TagNumForName(model, tagname); -} - -static void QCBUILTIN PF_setattachment(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) -{ - edict_t *e = G_EDICT(prinst, OFS_PARM0); - edict_t *tagentity = G_EDICT(prinst, OFS_PARM1); - char *tagname = PR_GetStringOfs(prinst, OFS_PARM2); - - model_t *model; - - int tagidx; - - tagidx = 0; - - if (tagentity != (edict_t*)sv.world.edicts && tagname && tagname[0]) - { - model = SVPR_GetCModel(&sv.world, tagentity->v->modelindex); - if (model) - { - tagidx = Mod_TagNumForName(model, tagname); - if (tagidx == 0) - Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", NUM_FOR_EDICT(prinst, e), NUM_FOR_EDICT(prinst, tagentity), tagname, tagname, NUM_FOR_EDICT(prinst, tagentity), model->name); - } - else - Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): Couldn't load model\n", NUM_FOR_EDICT(prinst, e), NUM_FOR_EDICT(prinst, tagentity), tagname); - } - - e->xv->tag_entity = EDICT_TO_PROG(prinst,tagentity); - e->xv->tag_index = tagidx; -} - //the first implementation of this function was (float type, float num, string name) //it is now float num, float type, .field //EXT_CSQC_1 @@ -8949,21 +8910,6 @@ qboolean SV_RunFullQCMovement(client_t *client, usercmd_t *ucmd) return false; } -qbyte qcpvs[(MAX_MAP_LEAFS+7)/8]; -//#240 float(vector viewpos, entity viewee) checkpvs (FTE_QC_CHECKPVS) -//note: this requires a correctly setorigined entity. -static void QCBUILTIN PF_checkpvs(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) -{ - float *viewpos = G_VECTOR(OFS_PARM0); - edict_t *ent = G_EDICT(prinst, OFS_PARM1); - - //FIXME: Make all alternatives of FatPVS not recalulate the pvs. - //and yeah, this is overkill what with the whole fat thing and all. - sv.world.worldmodel->funcs.FatPVS(sv.world.worldmodel, viewpos, qcpvs, sizeof(qcpvs), false); - - G_FLOAT(OFS_RETURN) = sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &((wedict_t*)ent)->pvsinfo, qcpvs); -} - //entity(string match [, float matchnum]) matchclient = #241; static void QCBUILTIN PF_matchclient(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -9776,7 +9722,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"putentityfieldstring",PF_putentityfieldstring,0,0, 0, 500, "float(float fieldnum, entity ent, string s)"},//DP_QC_ENTITYDATA {"WritePicture", PF_WritePicture, 0, 0, 0, 501, "void(float to, string s, float sz)"},//DP_SV_WRITEPICTURE {"ReadPicture", PF_Fixme, 0, 0, 0, 501, "string()"},//DP_SV_WRITEPICTURE -// {"boxparticles", PF_Fixme, 0, 0, 0, 502, "void(float effectindex, entity own, vector org_from, vector org_to, vector dir_from, vector dir_to, float countmultiplier, float flags)"}, + {"boxparticles", PF_Fixme, 0, 0, 0, 502, "void(float effectindex, entity own, vector org_from, vector org_to, vector dir_from, vector dir_to, float countmultiplier, optional float flags)"}, {"whichpack", PF_whichpack, 0, 0, 0, 503, D("string(string filename, optional float makereferenced)", "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.")},//DP_QC_WHICHPACK {"getentity", PF_Fixme, 0, 0, 0, 504, "__variant(float entnum, float fieldnum)"},//DP_CSQC_QUERYRENDERENTITY // {"undefined", PF_Fixme, 0, 0, 0, 505, ""}, @@ -10419,6 +10365,7 @@ void PR_DumpPlatform_f(void) {"CSQC_Parse_StuffCmd", "noref void(string msg)", CS, "Gives the CSQC a chance to intercept stuffcmds. Use the tokenize builtin to parse the message. Unrecognised commands would normally be localcmded, but its probably better to drop unrecognised stuffcmds completely."}, {"CSQC_Parse_CenterPrint", "noref float(string msg)", CS, "Gives the CSQC a chance to intercept centerprints. Return true if you wish the engine to otherwise ignore the centerprint."}, {"CSQC_Parse_Print", "noref void(string printmsg, float printlvl)", CS, "Gives the CSQC a chance to intercept sprint/bprint builtin calls. CSQC should filter by the client's current msg setting and then pass the message on to the print command, or handle them itself."}, + {"CSQC_Parse_Event", "noref void()", CS, "Called when the client receives an SVC_CGAMEPACKET. The csqc should read the data or call the error builtin if it does not recognise the message."}, {"CSQC_InputEvent", "noref float(float evtype, float scanx, float chary, float devid)", CS, "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."}, {"CSQC_Input_Frame", "noref void()", CS, "Called just before each time clientcommandframe is updated. You can edit the input_* globals in order to apply your own player inputs within csqc, which may allow you a convienient way to pass certain info to ssqc."}, {"CSQC_ConsoleCommand", "noref float(string cmd)", CS, "Called if the user uses any console command registed via registercommand."}, @@ -10428,7 +10375,7 @@ void PR_DumpPlatform_f(void) {"CSQC_Event_Sound", "noref float(float entnum, float channel, float soundname, float vol, float attenuation, vector pos, float pitchmod)", CS}, // {"CSQC_ServerSound", "//void()", CS}, {"CSQC_LoadResource", "noref float(string resname, string restype)", CS, "Called each time some resource is being loaded. CSQC can invoke various draw calls to provide a loading screen, until WorldLoaded is called."}, - {"CSQC_Parse_TempEntity", "noref float()", CS, "Please don't use this."}, + {"CSQC_Parse_TempEntity", "noref float()", CS, "Please don't use this. Use CSQC_Parse_Event and multicasts instead."}, {"GameCommand", "noref void(string cmdtext)", CS|MENU}, @@ -10447,7 +10394,7 @@ void PR_DumpPlatform_f(void) {"FONT_DEFAULT", "const float", CS|MENU, NULL, 0}, {"TRUE", "const float", ALL, NULL, 1}, - {"FALSE", "const float", ALL, NULL, 0}, + {"FALSE", "const float", ALL, "File not found...", 0}, {"MOVETYPE_NONE", "const float", QW|NQ|CS, NULL, MOVETYPE_NONE}, {"MOVETYPE_WALK", "const float", QW|NQ|CS, NULL, MOVETYPE_WALK}, @@ -10460,7 +10407,7 @@ void PR_DumpPlatform_f(void) {"MOVETYPE_BOUNCE", "const float", QW|NQ|CS, NULL, MOVETYPE_BOUNCE}, {"MOVETYPE_BOUNCEMISSILE", "const float", QW|NQ|CS, NULL, MOVETYPE_BOUNCEMISSILE}, {"MOVETYPE_FOLLOW", "const float", QW|NQ|CS, NULL, MOVETYPE_FOLLOW}, - {"MOVETYPE_WALLWALK", "const float", QW|NQ|CS, NULL, MOVETYPE_WALLWALK}, + {"MOVETYPE_WALLWALK", "const float", QW|NQ|CS, "Players using this movetype will be able to orient themselves to walls, and then run up them.", MOVETYPE_WALLWALK}, {"MOVETYPE_PHYSICS", "const float", QW|NQ|CS, NULL, MOVETYPE_PHYSICS}, {"SOLID_NOT", "const float", QW|NQ|CS, NULL, SOLID_NOT}, @@ -10493,16 +10440,19 @@ void PR_DumpPlatform_f(void) {"CONTENT_SKY", "const float", QW|NQ|CS, NULL, Q1CONTENTS_SKY}, {"CONTENT_LADDER", "const float", QW|NQ|CS, NULL, Q1CONTENTS_LADDER}, - {"CHAN_AUTO", "const float", QW|NQ|CS, NULL, CHAN_AUTO}, + {"CHAN_AUTO", "const float", QW|NQ|CS, "The automatic channel, play as many sounds on this channel as you want, and they'll all play, however the other channels will replace each other.", CHAN_AUTO}, {"CHAN_WEAPON", "const float", QW|NQ|CS, NULL, CHAN_WEAPON}, {"CHAN_VOICE", "const float", QW|NQ|CS, NULL, CHAN_VOICE}, {"CHAN_ITEM", "const float", QW|NQ|CS, NULL, CHAN_ITEM}, {"CHAN_BODY", "const float", QW|NQ|CS, NULL, CHAN_BODY}, - {"ATTN_NONE", "const float", QW|NQ|CS, NULL, ATTN_NONE}, - {"ATTN_NORM", "const float", QW|NQ|CS, NULL, ATTN_NORM}, - {"ATTN_IDLE", "const float", QW|NQ|CS, NULL, 2}, //including these for completeness, despite them being defined by the gamecode rather than the engine api. - {"ATTN_STATIC", "const float", QW|NQ|CS, NULL, 3}, + {"ATTN_NONE", "const float", QW|NQ|CS, "Sounds with this attenuation can be heard throughout the map", ATTN_NONE}, + {"ATTN_NORM", "const float", QW|NQ|CS, "Standard attenuation", ATTN_NORM}, + {"ATTN_IDLE", "const float", QW|NQ|CS, "Extra attenuation so that sounds don't travel too far.", 2}, //including these for completeness, despite them being defined by the gamecode rather than the engine api. + {"ATTN_STATIC", "const float", QW|NQ|CS, "Even more attenuation to avoid torches drowing out everything else throughout the map.", 3}, + + //not putting other svcs here, qc shouldn't otherwise need to generate svcs directly. + {"SVC_CGAMEPACKET", "const float", QW|NQ, "Direct ssqc->csqc message. Must only be multicast. The data triggers a CSQC_Parse_Event call in the csqc for the csqc to read the contents. The server *may* insert length information for clients connected via proxies which are not able to cope with custom csqc payloads.", svcfte_cgamepacket}, {"MSG_BROADCAST", "const float", QW|NQ, NULL, MSG_BROADCAST}, {"MSG_ONE", "const float", QW|NQ, NULL, MSG_ONE}, @@ -10544,9 +10494,9 @@ void PR_DumpPlatform_f(void) {"INFOKEY_P_PROTOCOL", "const string", QW|NQ, "The network protocol the client is using to connect to the server.", 0, "\"protocol\""}, {"INFOKEY_P_MUTED", "const string", CS, "0: we can see the result of the player's say/say_team commands. 1: we see no say/say_team messages from this player. Use the ignore command to toggle this value.", 0, "\"ignored\""}, {"INFOKEY_P_VOIP_MUTED","const string", CS, "0: we can hear this player when they speak (assuming voip is generally enabled). 1: we ignore everything this player says. Use cl_voip_mute to change the values.", 0, "\"vignored\""}, - {"INFOKEY_P_ENTERTIME", "const string", CS, NULL, 0, "\"entertime\""}, - {"INFOKEY_P_FRAGS", "const string", CS, NULL, 0, "\"frags\""}, - {"INFOKEY_P_PACKETLOSS","const string", CS, NULL, 0, "\"pl\""}, + {"INFOKEY_P_ENTERTIME", "const string", CS, "Reads the timestamp at which the player entered the game, in terms of csqc's time global.", 0, "\"entertime\""}, + {"INFOKEY_P_FRAGS", "const string", CS, "Reads a player's frag count.", 0, "\"frags\""}, + {"INFOKEY_P_PACKETLOSS","const string", CS, "Reads a player's packetloss, as a percentage.", 0, "\"pl\""}, {"INFOKEY_P_VOIPSPEAKING","const string", CS, "Boolean value that says whether the given player is currently sending voice information.", 0, "\"voipspeaking\""}, {"INFOKEY_P_VOIPLOUDNESS","const string", CS, "Only valid for the local player. Gives a value between 0 and 1 to indicate to the user how loud their mic is.", 0, "\"voiploudness\""}, @@ -10572,10 +10522,11 @@ void PR_DumpPlatform_f(void) {"MOVE_NOMONSTERS", "const float", QW|NQ|CS, NULL, MOVE_NOMONSTERS}, {"MOVE_MISSILE", "const float", QW|NQ|CS, NULL, MOVE_MISSILE}, {"MOVE_HITMODEL", "const float", QW|NQ|CS, "Traces will impact the actual mesh of the model instead of merely their bounding box. Should generally only be used for tracelines. Note that this flag is unreliable as an object can animate through projectiles. The bounding box MUST be set to completely encompass the entity or those extra areas will be non-solid (leaving a hole for things to go through).", MOVE_HITMODEL}, - {"MOVE_TRIGGERS", "const float", QW|NQ|CS, NULL, MOVE_TRIGGERS}, - {"MOVE_EVERYTHING", "const float", QW|NQ|CS, NULL, MOVE_EVERYTHING}, + {"MOVE_TRIGGERS", "const float", QW|NQ|CS, "This trace type will impact only triggers. It will ignore non-solid entities.", MOVE_TRIGGERS}, + {"MOVE_EVERYTHING", "const float", QW|NQ|CS, "This type of trace will hit solids and triggers alike. Even non-solid entities.", MOVE_EVERYTHING}, {"MOVE_LAGGED", "const float", QW|NQ, "Will use antilag based upon the player's latency. Traces will be performed against old positions for entities instead of their current origin.", MOVE_LAGGED}, {"MOVE_ENTCHAIN", "const float", QW|NQ|CS, "Returns a list of entities impacted via the trace_ent.chain field", MOVE_ENTCHAIN}, + {"MOVE_ONLYENT", "const float", QW|NQ|CS, "Traces that use this trace type will collide against *only* the entity specified, and will ignore all owner/solid/dimension etc fields, they will still adhere to contents though.", MOVE_ONLYENT}, {"EF_BRIGHTFIELD", "const float", QW|NQ|CS, NULL, EF_BRIGHTFIELD}, {"EF_MUZZLEFLASH", "const float", NQ|CS, NULL, EF_MUZZLEFLASH}, @@ -10610,7 +10561,7 @@ void PR_DumpPlatform_f(void) // {"EV_FUNCTION", "const float", QW|NQ, NULL, ev_function}, // {"EV_POINTER", "const float", QW|NQ, NULL, ev_pointer}, {"EV_INTEGER", "const float", QW|NQ, NULL, ev_integer}, -// {"EV_INTEGER", "const float", QW|NQ, NULL, ev_variant}, +// {"EV_VARIANT", "const float", QW|NQ, NULL, ev_variant}, // {"EV_STRUCT", "const float", QW|NQ, NULL, ev_struct}, // {"EV_UNION", "const float", QW|NQ, NULL, ev_union}, @@ -10639,21 +10590,21 @@ void PR_DumpPlatform_f(void) {"VF_SIZE", "const float", CS, NULL, VF_SIZE}, {"VF_SIZE_X", "const float", CS, NULL, VF_SIZE_X}, {"VF_SIZE_Y", "const float", CS, NULL, VF_SIZE_Y}, - {"VF_VIEWPORT", "const float", CS, NULL, VF_VIEWPORT}, + {"VF_VIEWPORT", "const float", CS, "vector+vector. Two argument shortcut for VF_MIN and VF_SIZE", VF_VIEWPORT}, {"VF_FOV", "const float", CS, "sets both fovx and fovy. consider using afov instead.", VF_FOV}, {"VF_FOVX", "const float", CS, "horizontal field of view. does not consider aspect at all.", VF_FOVX}, {"VF_FOVY", "const float", CS, "vertical field of view. does not consider aspect at all.", VF_FOVY}, - {"VF_ORIGIN", "const float", CS, NULL, VF_ORIGIN}, + {"VF_ORIGIN", "const float", CS, "The origin of the view. Not of the player.", VF_ORIGIN}, {"VF_ORIGIN_X", "const float", CS, NULL, VF_ORIGIN_X}, {"VF_ORIGIN_Y", "const float", CS, NULL, VF_ORIGIN_Y}, {"VF_ORIGIN_Z", "const float", CS, NULL, VF_ORIGIN_Z}, - {"VF_ANGLES", "const float", CS, NULL, VF_ANGLES}, + {"VF_ANGLES", "const float", CS, "The angles the view will be drawn at. Not the angle the client reports to the server.", VF_ANGLES}, {"VF_ANGLES_X", "const float", CS, NULL, VF_ANGLES_X}, {"VF_ANGLES_Y", "const float", CS, NULL, VF_ANGLES_Y}, {"VF_ANGLES_Z", "const float", CS, NULL, VF_ANGLES_Z}, - {"VF_DRAWWORLD", "const float", CS, NULL, VF_DRAWWORLD}, - {"VF_DRAWENGINESBAR", "const float", CS, NULL, VF_ENGINESBAR}, - {"VF_DRAWCROSSHAIR", "const float", CS, NULL, VF_DRAWCROSSHAIR}, + {"VF_DRAWWORLD", "const float", CS, "boolean. If set to 1, the engine will draw the world and static/persistant rtlights. If 0, the world will be skipped and everything will be fullbright.", VF_DRAWWORLD}, + {"VF_DRAWENGINESBAR", "const float", CS, "boolean. If set to 1, the sbar will be drawn, and viewsize will be honoured automatically.", VF_ENGINESBAR}, + {"VF_DRAWCROSSHAIR", "const float", CS, "boolean. If set to 1, the engine will draw its default crosshair.", VF_DRAWCROSSHAIR}, {"VF_CL_VIEWANGLES", "const float", CS, NULL, VF_CL_VIEWANGLES_V}, {"VF_CL_VIEWANGLES_X", "const float", CS, NULL, VF_CL_VIEWANGLES_X}, diff --git a/engine/server/progdefs.h b/engine/server/progdefs.h index 523dd451d..d0a7a0b63 100644 --- a/engine/server/progdefs.h +++ b/engine/server/progdefs.h @@ -200,10 +200,12 @@ and the extension fields are added on the end and can have extra vm-specific stu comfieldfloat(fatness,NULL)/*FTE_PEXT_FATNESS*/\ comfieldfloat(alpha,NULL)/*DP_ENT_ALPHA*/\ comfieldentity(tag_entity,NULL)\ + comfieldfloat(tag_index,NULL)\ comfieldfloat(skeletonindex,NULL) /*FTE_CSQC_SKELETONOBJECTS*/\ comfieldvector(colormod,NULL)\ comfieldvector(glowmod,NULL)\ comfieldvector(gravitydir,NULL)\ + comfieldfunction(camera_transform,".vector(vector org, vector ang)", NULL)\ comfieldfloat(pmove_flags,NULL)/*EXT_CSQC_1*/\ comfieldfloat(friction,NULL)/*DP_...PHYSICS*/\ comfieldfloat(erp,NULL)/*DP_...PHYSICS*/\ @@ -229,7 +231,6 @@ and the extension fields are added on the end and can have extra vm-specific stu comfieldfloat(button7,NULL)\ comfieldfloat(button8,NULL)\ comfieldfloat(viewzoom,NULL)/*DP_VIEWZOOM*/\ - comfieldfloat(tag_index,NULL)\ comfieldfloat(glow_size,NULL)\ comfieldfloat(glow_color,NULL)\ comfieldfloat(glow_trail,NULL)\ diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 42e877f04..f698f32fb 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -260,7 +260,7 @@ void SVNQ_CreateBaseline (void) if (!svent->baseline.modelindex) svent->baseline.modelindex = playermodel; } - svent->baseline.modelindex&=255; + svent->baseline.modelindex&=255; //FIXME } } @@ -598,6 +598,83 @@ void SV_UpdateMaxPlayers(int newmax) sv.allocated_client_slots = svs.allocated_client_slots; } +static void SV_SetupNetworkBuffers(qboolean bigcoords) +{ + int i; + + //determine basic primitive sizes. + if (bigcoords) + { + svs.netprim.coordsize = 4; + svs.netprim.anglesize = 2; + } + else + { + svs.netprim.coordsize = 2; + svs.netprim.anglesize = 1; + } + + //FIXME: this should be part of sv_new_f or something instead, so that any angles sent by clients won't be invalid + for (i = 0; i < svs.allocated_client_slots; i++) + { + svs.clients[i].datagram.prim = svs.netprim; + svs.clients[i].netchan.message.prim = svs.netprim; + } + + // + sv.datagram.maxsize = sizeof(sv.datagram_buf); + sv.datagram.data = sv.datagram_buf; + sv.datagram.allowoverflow = true; + sv.datagram.prim = svs.netprim; + + sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf); + sv.reliable_datagram.data = sv.reliable_datagram_buf; + sv.reliable_datagram.prim = svs.netprim; + + sv.multicast.maxsize = sizeof(sv.multicast_buf); + sv.multicast.data = sv.multicast_buf; + sv.multicast.prim = svs.netprim; + +#ifdef NQPROT + sv.nqdatagram.maxsize = sizeof(sv.nqdatagram_buf); + sv.nqdatagram.data = sv.nqdatagram_buf; + sv.nqdatagram.allowoverflow = true; + sv.nqdatagram.prim = svs.netprim; + + sv.nqreliable_datagram.maxsize = sizeof(sv.nqreliable_datagram_buf); + sv.nqreliable_datagram.data = sv.nqreliable_datagram_buf; + sv.nqreliable_datagram.prim = svs.netprim; + + sv.nqmulticast.maxsize = sizeof(sv.nqmulticast_buf); + sv.nqmulticast.data = sv.nqmulticast_buf; + sv.nqmulticast.prim = svs.netprim; +#endif + +#ifdef Q2SERVER + sv.q2datagram.maxsize = sizeof(sv.q2datagram_buf); + sv.q2datagram.data = sv.q2datagram_buf; + sv.q2datagram.allowoverflow = true; + sv.q2datagram.prim = svs.netprim; + + sv.q2reliable_datagram.maxsize = sizeof(sv.q2reliable_datagram_buf); + sv.q2reliable_datagram.data = sv.q2reliable_datagram_buf; + sv.q2reliable_datagram.prim = svs.netprim; + + sv.q2multicast.maxsize = sizeof(sv.q2multicast_buf); + sv.q2multicast.data = sv.q2multicast_buf; + sv.q2multicast.prim = svs.netprim; +#endif + + sv.master.maxsize = sizeof(sv.master_buf); + sv.master.data = sv.master_buf; + sv.master.prim = msg_nullnetprim; + + sv.signon.maxsize = sizeof(sv.signon_buffers[0]); + sv.signon.data = sv.signon_buffers[0]; + sv.signon.prim = svs.netprim; + sv.num_signon_buffers = 1; +} + /* ================ SV_SpawnServer @@ -677,21 +754,8 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us T_FreeStrings(); } - if (sv_bigcoords.value) - { - svs.netprim.coordsize = 4; - svs.netprim.anglesize = 2; - } - else - { - svs.netprim.coordsize = 2; - svs.netprim.anglesize = 1; - } - for (i = 0; i < svs.allocated_client_slots; i++) { - svs.clients[i].datagram.prim = svs.netprim; - svs.clients[i].netchan.message.prim = svs.netprim; svs.clients[i].nextservertimeupdate = 0; if (!svs.clients[i].state) //bots with the net_preparse module. svs.clients[i].userinfo[0] = '\0'; //clear the userinfo to clear the name @@ -732,57 +796,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us // wipe the entire per-level structure memset (&sv, 0, sizeof(sv)); - sv.datagram.maxsize = sizeof(sv.datagram_buf); - sv.datagram.data = sv.datagram_buf; - sv.datagram.allowoverflow = true; - sv.datagram.prim = svs.netprim; - - sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf); - sv.reliable_datagram.data = sv.reliable_datagram_buf; - sv.reliable_datagram.prim = svs.netprim; - - sv.multicast.maxsize = sizeof(sv.multicast_buf); - sv.multicast.data = sv.multicast_buf; - sv.multicast.prim = svs.netprim; - -#ifdef NQPROT - sv.nqdatagram.maxsize = sizeof(sv.nqdatagram_buf); - sv.nqdatagram.data = sv.nqdatagram_buf; - sv.nqdatagram.allowoverflow = true; - sv.nqdatagram.prim = svs.netprim; - - sv.nqreliable_datagram.maxsize = sizeof(sv.nqreliable_datagram_buf); - sv.nqreliable_datagram.data = sv.nqreliable_datagram_buf; - sv.nqreliable_datagram.prim = svs.netprim; - - sv.nqmulticast.maxsize = sizeof(sv.nqmulticast_buf); - sv.nqmulticast.data = sv.nqmulticast_buf; - sv.nqmulticast.prim = svs.netprim; -#endif - -#ifdef Q2SERVER - sv.q2datagram.maxsize = sizeof(sv.q2datagram_buf); - sv.q2datagram.data = sv.q2datagram_buf; - sv.q2datagram.allowoverflow = true; - sv.q2datagram.prim = svs.netprim; - - sv.q2reliable_datagram.maxsize = sizeof(sv.q2reliable_datagram_buf); - sv.q2reliable_datagram.data = sv.q2reliable_datagram_buf; - sv.q2reliable_datagram.prim = svs.netprim; - - sv.q2multicast.maxsize = sizeof(sv.q2multicast_buf); - sv.q2multicast.data = sv.q2multicast_buf; - sv.q2multicast.prim = svs.netprim; -#endif - - sv.master.maxsize = sizeof(sv.master_buf); - sv.master.data = sv.master_buf; - sv.master.prim = msg_nullnetprim; - - sv.signon.maxsize = sizeof(sv.signon_buffers[0]); - sv.signon.data = sv.signon_buffers[0]; - sv.signon.prim = svs.netprim; - sv.num_signon_buffers = 1; + SV_SetupNetworkBuffers(sv_bigcoords.ival); if (allow_download_refpackages.ival) FS_ReferenceControl(1, 1); @@ -1084,7 +1098,8 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us switch (svs.gametype) { - case GT_MAX: + default: + SV_Error("bad gametype"); break; case GT_Q1QVM: case GT_PROGS: @@ -1146,8 +1161,8 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us #endif } break; - case GT_QUAKE2: #ifdef Q2SERVER + case GT_QUAKE2: SV_UpdateMaxPlayers(svq2_maxclients); for (i=0 ; is.number = i+1; svs.clients[i].q2edict = q2ent; } -#endif break; - case GT_QUAKE3: +#endif #ifdef Q3SERVER + case GT_QUAKE3: SV_UpdateMaxPlayers(32); -#endif break; - case GT_HALFLIFE: +#endif #ifdef HLSERVER + case GT_HALFLIFE: SVHL_SetupGame(); -#endif + SV_UpdateMaxPlayers(32); break; +#endif } //fixme: is this right? @@ -1271,7 +1287,6 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us if (progstype == PROG_QW) // run the frame start qc function to let progs check cvars SV_ProgStartFrame (); //prydon gate seems to fail because of this allowance - } // load and spawn all other entities @@ -1336,24 +1351,23 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us switch(svs.gametype) { - case GT_MAX: + default: break; case GT_Q1QVM: case GT_PROGS: sv.world.edict_size = PR_LoadEnts(svprogfuncs, file?file :sv.world.worldmodel->entities, spawnflagmask); break; - case GT_QUAKE2: #ifdef Q2SERVER + case GT_QUAKE2: ge->SpawnEntities(sv.name, file?file :sv.world.worldmodel->entities, startspot?startspot:""); -#endif break; +#endif case GT_QUAKE3: break; - case GT_HALFLIFE: #ifdef HLSERVER - SVHL_SpawnEntities(file?file :sv.world.worldmodel->entities)); + case GT_HALFLIFE: + SVHL_SpawnEntities(file?file :sv.world.worldmodel->entities); break; #endif - break; } #ifndef SERVERONLY @@ -1462,6 +1476,33 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us SCR_ImageName(server); #endif + /*world is now spawned. switch to big coords if there are entities outside the bounds of the map*/ + if (!*sv_bigcoords.string && svprogfuncs) + { + float extent = 0, ne; + //fixme: go off bsp extents instead? + for(i = 1; i < sv.world.num_edicts; i++) + { + ent = EDICT_NUM(svprogfuncs, i); + for (j = 0; j < 3; j++) + { + ne = fabs(ent->v->origin[j]); + if (extent < ne) + extent = ne; + } + } + if (extent > (1u<<15)/8) + { + if (sv.num_signon_buffers > 1 || sv.signon.cursize) + Con_Printf("Cannot auto-enable extended coords as the init buffer was used\n"); + else + { + Con_Printf("Switching to extended coord sizes\n"); + SV_SetupNetworkBuffers(true); + } + } + } + /*DP_BOTCLIENT bots should move over to the new map too*/ if (svs.gametype == GT_PROGS || svs.gametype == GT_Q1QVM) { diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index c0a54a06c..b4cc0707e 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -1709,8 +1709,13 @@ void SV_ClientProtocolExtensionsChanged(client_t *client) int i; int maxpacketentities; extern cvar_t pr_maxedicts; - client->maxmodels = 256; + //some gamecode can't cope with some extensions for some reasons... and I'm too lazy to fix the code to cope. + if (svs.gametype == GT_HALFLIFE) + client->fteprotocolextensions2 &= ~PEXT2_REPLACEMENTDELTAS; + + // + client->maxmodels = 256; if (client->fteprotocolextensions & PEXT_256PACKETENTITIES) maxpacketentities = MAX_EXTENDED_PACKET_ENTITIES; else @@ -5034,7 +5039,7 @@ void SV_Init (quakeparms_t *parms) #ifdef SVRANKING Rank_RegisterCommands(); #endif - Cbuf_AddText("alias restart \"map .\"\nalias newgame \"map start\"\n", RESTRICT_LOCAL); + Cbuf_AddText("alias restart \"map .\"\nalias startmap_sp \"map start\"\n", RESTRICT_LOCAL); #ifndef SERVERONLY if (isDedicated) diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index b45c88045..3bd3847fd 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -257,6 +257,60 @@ static void ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce out[i] = 0; } +static void WPhys_PortalTransform(world_t *w, wedict_t *ent, wedict_t *portal, vec3_t org, vec3_t move) +{ + int oself = *w->g.self; + void *pr_globals = PR_globals(w->progs, PR_CURRENT); + + *w->g.self = EDICT_TO_PROG(w->progs, portal); + //transform origin+velocity etc + VectorCopy(org, G_VECTOR(OFS_PARM0)); + VectorAngles(ent->v->angles, vup, G_VECTOR(OFS_PARM1)); + VectorCopy(ent->v->velocity, w->g.v_forward); + VectorCopy(move, w->g.v_right); + VectorCopy(ent->xv->gravitydir, w->g.v_up); + if (!DotProduct(w->g.v_up, w->g.v_up)) + w->g.v_up[2] = -1; + + PR_ExecuteProgram (w->progs, portal->xv->camera_transform); + + VectorCopy(G_VECTOR(OFS_RETURN), org); +// VectorCopy(w->g.v_forward, ent->v->velocity); + VectorCopy(w->g.v_right, move); +// VectorCopy(w->g.v_up, ent->xv->gravitydir); + + + //transform the angles too + VectorCopy(org, G_VECTOR(OFS_PARM0)); + if (ent->entnum <= svs.allocated_client_slots) + { + VectorCopy(ent->v->v_angle, ent->v->angles); + ent->v->fixangle = true; + } + else + ent->v->angles[0] *= -1; + VectorAngles(ent->v->angles, vup, G_VECTOR(OFS_PARM1)); + AngleVectors(ent->v->angles, w->g.v_forward, w->g.v_right, w->g.v_up); + PR_ExecuteProgram (w->progs, portal->xv->camera_transform); + VectorAngles(w->g.v_forward, w->g.v_up, ent->v->angles); + if (ent->entnum <= svs.allocated_client_slots) + ent->v->angles[0] *= -1; + + /* + avelocity is horribly dependant upon eular angles. trying to treat it as a matrix is folly. + if (DotProduct(ent->v->avelocity, ent->v->avelocity)) + { + ent->v->avelocity[0] *= -1; + AngleVectors(ent->v->avelocity, w->g.v_forward, w->g.v_right, w->g.v_up); + PR_ExecuteProgram (w->progs, portal->xv->camera_transform); + VectorAngles(w->g.v_forward, w->g.v_up, ent->v->avelocity); + ent->v->avelocity[0] *= -1; + } + */ + + *w->g.self = oself; +} + /* @@ -285,6 +339,7 @@ static int WPhys_FlyMove (world_t *w, wedict_t *ent, const vec3_t gravitydir, fl vec3_t end; float time_left; int blocked; + wedict_t *impact; vec3_t diff; numbumps = 4; @@ -301,7 +356,26 @@ static int WPhys_FlyMove (world_t *w, wedict_t *ent, const vec3_t gravitydir, fl for (i=0 ; i<3 ; i++) end[i] = ent->v->origin[i] + time_left * ent->v->velocity[i]; - trace = World_Move (w, ent->v->origin, ent->v->mins, ent->v->maxs, end, false, (wedict_t*)ent); + trace = World_Move (w, ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, (wedict_t*)ent); + + impact = trace.ent; + if (impact && impact->v->solid == SOLID_PORTAL) + { + vec3_t move; + vec3_t from; + float firstfrac = trace.fraction; +Con_Printf("Player hit portal %i\n", impact->entnum); + VectorCopy(trace.endpos, from); //just in case + VectorSubtract(end, trace.endpos, move); + WPhys_PortalTransform(w, ent, impact, trace.endpos, move); + VectorAdd(trace.endpos, move, end); + trace = World_Move (w, from, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, (wedict_t*)ent); + trace.fraction = firstfrac + (1-firstfrac)*trace.fraction; + + //if we follow the portal, then we need to fix up some velocities. + if (trace.fraction > 0) + VectorCopy (ent->v->velocity, primal_velocity); + } if (trace.startsolid) { // entity is trapped in another solid @@ -463,6 +537,7 @@ static trace_t WPhys_PushEntity (world_t *w, wedict_t *ent, vec3_t push, unsigne { trace_t trace; vec3_t end; + wedict_t *impact; VectorAdd (ent->v->origin, push, end); @@ -470,12 +545,28 @@ static trace_t WPhys_PushEntity (world_t *w, wedict_t *ent, vec3_t push, unsigne traceflags |= MOVE_LAGGED; if (ent->v->movetype == MOVETYPE_FLYMISSILE) - trace = World_Move (w, ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_MISSILE|traceflags, (wedict_t*)ent); + traceflags |= MOVE_MISSILE; else if (ent->v->solid == SOLID_TRIGGER || ent->v->solid == SOLID_NOT) // only clip against bmodels - trace = World_Move (w, ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NOMONSTERS|traceflags, (wedict_t*)ent); + traceflags |= MOVE_NOMONSTERS; else - trace = World_Move (w, ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL|traceflags, (wedict_t*)ent); + traceflags |= MOVE_NORMAL; + + trace = World_Move (w, ent->v->origin, ent->v->mins, ent->v->maxs, end, traceflags, (wedict_t*)ent); + + impact = trace.ent; + if (impact && impact->v->solid == SOLID_PORTAL) + { + vec3_t move; + vec3_t from; + float firstfrac = trace.fraction; + VectorCopy(trace.endpos, from); //just in case + VectorSubtract(end, trace.endpos, move); + WPhys_PortalTransform(w, ent, impact, from, move); + VectorAdd(from, move, end); + trace = World_Move (w, from, ent->v->mins, ent->v->maxs, end, traceflags, (wedict_t*)ent); + trace.fraction = firstfrac + (1-firstfrac)*trace.fraction; + } /*hexen2's movetype_swim does not allow swimming entities to move out of water. this implementation is quite hacky, but matches hexen2 well enough*/ if (ent->v->movetype == MOVETYPE_H2SWIM) diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 59b3e2f3c..2c7b914d9 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -7368,6 +7368,7 @@ void SV_ClientThink (void) VectorCopy (sv_player->v->v_angle, v_angle); // VectorAdd (sv_player->v->v_angle, sv_player->v->punchangle, v_angle); + //FIXME: gravitydir stuff, the roll value gets destroyed for intents angles[ROLL] = V_CalcRoll (sv_player->v->angles, sv_player->v->velocity)*4; if (!sv_player->v->fixangle) { diff --git a/engine/server/svhl_game.c b/engine/server/svhl_game.c index 8c218aafc..d28dda731 100644 --- a/engine/server/svhl_game.c +++ b/engine/server/svhl_game.c @@ -23,15 +23,21 @@ I think globals.maxentities is the hard cap, rather than current max like in q1. //I hope you're c99 and have a __func__ #endif -#define ignore(s) Con_Printf("Fixme: " s "\n") +extern cvar_t temp1; +#define ignore(s) Con_DPrintf("Fixme: " s "\n") #define notimpl(l) Con_Printf("halflife sv builtin not implemented on line %i\n", l) #define notimpf(f) Con_Printf("halflife sv builtin %s not implemented\n", f) +#define bi_begin() if (temp1.ival)Con_Printf("enter %s\n", __func__) +#define bi_end() if (temp1.ival)Con_Printf("leave %s\n", __func__) +#define bi_trace() bi_begin(); bi_end() dllhandle_t *hlgamecode; SVHL_Globals_t SVHL_Globals; SVHL_GameFuncs_t SVHL_GameFuncs; +static zonegroup_t hlmapmemgroup; //flushed at end-of-map. + #define MAX_HL_EDICTS 2048 hledict_t *SVHL_Edict; int SVHL_NumActiveEnts; @@ -44,13 +50,18 @@ int lastusermessage; string_t QDECL GHL_AllocString(char *string) { char *news; - news = Hunk_Alloc(strlen(string)+1); + bi_begin(); + if (!string) + return 0; + news = ZG_Malloc(&hlmapmemgroup, strlen(string)+1); memcpy(news, string, strlen(string)+1); + bi_end(); return news - SVHL_Globals.stringbase; } int QDECL GHL_PrecacheModel(char *name) { int i; + bi_trace(); if (name[0] <= ' ') { @@ -98,6 +109,7 @@ int QDECL GHL_PrecacheModel(char *name) int QDECL GHL_PrecacheSound(char *name) { int i; + bi_trace(); if (name[0] <= ' ') { @@ -144,6 +156,7 @@ void QDECL GHL_SetModel(hledict_t *ed, char *modelname) { model_t *mod; int mdlidx = GHL_PrecacheModel(modelname); + bi_trace(); ed->v.modelindex = mdlidx; ed->v.model = sv.strings.model_precache[mdlidx] - SVHL_Globals.stringbase; @@ -159,18 +172,21 @@ void QDECL GHL_SetModel(hledict_t *ed, char *modelname) unk QDECL GHL_ModelIndex(unk){notimpf(__func__);} int QDECL GHL_ModelFrames(int midx) { + bi_trace(); //returns the number of frames(sequences I assume) this model has ignore("ModelFrames"); return 1; } void QDECL GHL_SetSize(hledict_t *ed, float *mins, float *maxs) { + bi_trace(); VectorCopy(mins, ed->v.mins); VectorCopy(maxs, ed->v.maxs); SVHL_LinkEdict(ed, false); } void QDECL GHL_ChangeLevel(char *nextmap, char *startspot) { + bi_trace(); Cbuf_AddText(va("changelevel %s %s@%f@%f@%f\n", nextmap, startspot, SVHL_Globals.landmark[0], SVHL_Globals.landmark[1], SVHL_Globals.landmark[2]), RESTRICT_PROGS); } unk QDECL GHL_GetSpawnParms(unk){notimpf(__func__);} @@ -178,15 +194,21 @@ unk QDECL GHL_SaveSpawnParms(unk){notimpf(__func__);} float QDECL GHL_VecToYaw(float *inv) { vec3_t outa; + bi_trace(); VectorAngles(inv, NULL, outa); return outa[1]; } void QDECL GHL_VecToAngles(float *inv, float *outa) { + bi_trace(); VectorAngles(inv, NULL, outa); } -unk QDECL GHL_MoveToOrigin(unk){notimpf(__func__);} +void QDECL GHL_MoveToOrigin(hledict_t *ent, vec3_t dest, float dist, int moveflags) +{ + bi_trace(); + ignore("GHL_MoveToOrigin"); +} unk QDECL GHL_ChangeYaw(unk){notimpf(__func__);} unk QDECL GHL_ChangePitch(unk){notimpf(__func__);} hledict_t *QDECL GHL_FindEntityByString(hledict_t *last, char *field, char *value) @@ -195,6 +217,7 @@ hledict_t *QDECL GHL_FindEntityByString(hledict_t *last, char *field, char *valu int i; int ofs; string_t str; + bi_trace(); if (!strcmp(field, "targetname")) ofs = (char*)&((hledict_t *)NULL)->v.targetname - (char*)NULL; else if (!strcmp(field, "classname")) @@ -227,6 +250,8 @@ hledict_t *QDECL GHL_FindEntityInSphere(hledict_t *last, float *org, float radiu vec3_t eorg; hledict_t *ent; + bi_trace(); + radius = radius*radius; if (last) @@ -260,6 +285,8 @@ hledict_t *QDECL GHL_FindClientInPVS(hledict_t *ed) vec3_t ofs; hledict_t *other; + bi_trace(); + //fixme: we need to track some state //a different client should be returned each call _per ent_ (so it can be used once per frame) @@ -297,10 +324,12 @@ hledict_t *QDECL GHL_FindClientInPVS(hledict_t *ed) unk QDECL GHL_EntitiesInPVS(unk){notimpf(__func__);} void QDECL GHL_MakeVectors(float *angles) { + bi_trace(); AngleVectors(angles, SVHL_Globals.v_forward, SVHL_Globals.v_right, SVHL_Globals.v_up); } void QDECL GHL_AngleVectors(float *angles, float *forward, float *right, float *up) { + bi_trace(); AngleVectors(angles, forward, right, up); } @@ -310,6 +339,7 @@ hledict_t *QDECL GHL_CreateEntity(void) { int i; static int spawnnumber; + bi_trace(); spawnnumber++; for (i = sv.allocated_client_slots; i < SVHL_NumActiveEnts; i++) @@ -338,6 +368,7 @@ hledict_t *QDECL GHL_CreateEntity(void) } void QDECL GHL_RemoveEntity(hledict_t *ed) { + bi_trace(); SVHL_UnlinkEdict(ed); ed->isfree = true; ed->freetime = sv.time+2; @@ -346,6 +377,7 @@ hledict_t *QDECL GHL_CreateNamedEntity(string_t name) { void (QDECL *spawnfunc)(hlentvars_t *evars); hledict_t *ed; + bi_trace(); ed = GHL_CreateEntity(); if (!ed) return NULL; @@ -358,41 +390,50 @@ hledict_t *QDECL GHL_CreateNamedEntity(string_t name) } void *QDECL GHL_PvAllocEntPrivateData(hledict_t *ed, long quant) { + bi_trace(); if (!ed) return NULL; - ed->moddata = Z_Malloc(quant); + ed->moddata = ZG_Malloc(&hlmapmemgroup, quant); return ed->moddata; } unk QDECL GHL_PvEntPrivateData(unk) { + bi_trace(); notimpf(__func__); } unk QDECL GHL_FreeEntPrivateData(unk) { + bi_trace(); notimpf(__func__); } unk QDECL GHL_GetVarsOfEnt(unk) { + bi_trace(); notimpf(__func__); } hledict_t *QDECL GHL_PEntityOfEntOffset(int ednum) { + bi_trace(); return (hledict_t *)(ednum + (char*)SVHL_Edict); } int QDECL GHL_EntOffsetOfPEntity(hledict_t *ed) { + bi_trace(); return (char*)ed - (char*)SVHL_Edict; } int QDECL GHL_IndexOfEdict(hledict_t *ed) { + bi_trace(); return ed - SVHL_Edict; } hledict_t *QDECL GHL_PEntityOfEntIndex(int idx) { + bi_trace(); return &SVHL_Edict[idx]; } unk QDECL GHL_FindEntityByVars(unk) { + bi_trace(); notimpf(__func__); } @@ -405,6 +446,7 @@ int QDECL GHL_DropToFloor(hledict_t *ed) vec3_t top; vec3_t bottom; trace_t tr; + bi_trace(); VectorCopy(ed->v.origin, top); VectorCopy(ed->v.origin, bottom); top[2] += 1; @@ -415,25 +457,30 @@ int QDECL GHL_DropToFloor(hledict_t *ed) } int QDECL GHL_WalkMove(hledict_t *ed, float yaw, float dist, int mode) { + bi_trace(); ignore("walkmove"); return 1; } void QDECL GHL_SetOrigin(hledict_t *ed, float *neworg) { + bi_trace(); VectorCopy(neworg, ed->v.origin); SVHL_LinkEdict(ed, false); } void QDECL GHL_EmitSound(hledict_t *ed, int chan, char *soundname, float vol, float atten, int flags, int pitch) { + bi_trace(); SV_StartSound(ed-SVHL_Edict, ed->v.origin, ~0, chan, soundname, vol*255, atten, pitch); } void QDECL GHL_EmitAmbientSound(hledict_t *ed, float *org, char *soundname, float vol, float atten, unsigned int flags, int pitch) { + bi_trace(); SV_StartSound(0, org, ~0, 0, soundname, vol*255, atten, 0); } void QDECL GHL_TraceLine(float *start, float *end, int flags, hledict_t *ignore, hltraceresult_t *result) { trace_t t; + bi_trace(); t = SVHL_Move(start, vec3_origin, vec3_origin, end, flags, 0, ignore); @@ -455,6 +502,7 @@ unk QDECL GHL_TraceMonsterHull(unk){notimpf(__func__);} void QDECL GHL_TraceHull(float *start, float *end, int flags, int hullnum, hledict_t *ignore, hltraceresult_t *result) { trace_t t; + bi_trace(); t = SVHL_Move(start, sv.world.worldmodel->hulls[hullnum].clip_mins, sv.world.worldmodel->hulls[hullnum].clip_maxs, end, flags, 0, ignore); @@ -473,6 +521,7 @@ unk QDECL GHL_TraceModel(unk){notimpf(__func__);} char *QDECL GHL_TraceTexture(hledict_t *againstent, vec3_t start, vec3_t end) { trace_t tr; + bi_trace(); sv.world.worldmodel->funcs.NativeTrace(sv.world.worldmodel, 0, 0, NULL, start, end, vec3_origin, vec3_origin, MASK_WORLDSOLID, &tr); return tr.surface->name; } @@ -480,25 +529,30 @@ unk QDECL GHL_TraceSphere(unk){notimpf(__func__);} unk QDECL GHL_GetAimVector(unk){notimpf(__func__);} void QDECL GHL_ServerCommand(char *cmd) { + bi_trace(); Cbuf_AddText(cmd, RESTRICT_PROGS); } void QDECL GHL_ServerExecute(void) { + bi_trace(); Cbuf_ExecuteLevel(RESTRICT_PROGS); } unk QDECL GHL_ClientCommand(unk){notimpf(__func__);} unk QDECL GHL_ParticleEffect(unk){notimpf(__func__);} void QDECL GHL_LightStyle(int stylenum, char *stylestr) { + bi_trace(); PF_applylightstyle(stylenum, stylestr, 7); } int QDECL GHL_DecalIndex(char *decalname) { + bi_trace(); Con_Printf("Fixme: precache decal %s\n", decalname); return 0; } int QDECL GHL_PointContents(float *org) { + bi_trace(); return Q1CONTENTS_EMPTY; } @@ -507,6 +561,8 @@ vec3_t svhl_messageorigin; hledict_t *svhl_messageent; void QDECL GHL_MessageBegin(int dest, int type, float *org, hledict_t *ent) { + bi_trace(); + svhl_messagedest = dest; if (org) VectorCopy(org, svhl_messageorigin); @@ -528,6 +584,8 @@ void QDECL GHL_MessageEnd(unk) unsigned short len; client_t *cl; + bi_trace(); + if (!sv.multicast.cursize) { Con_Printf("MessageEnd called without MessageBegin\n"); @@ -570,35 +628,43 @@ void QDECL GHL_MessageEnd(unk) } void QDECL GHL_WriteByte(int value) { + bi_trace(); MSG_WriteByte(&sv.multicast, value); } void QDECL GHL_WriteChar(int value) { + bi_trace(); MSG_WriteChar(&sv.multicast, value); } void QDECL GHL_WriteShort(int value) { + bi_trace(); MSG_WriteShort(&sv.multicast, value); } void QDECL GHL_WriteLong(int value) { + bi_trace(); MSG_WriteLong(&sv.multicast, value); } void QDECL GHL_WriteAngle(float value) { + bi_trace(); MSG_WriteAngle8(&sv.multicast, value); } void QDECL GHL_WriteCoord(float value) { coorddata i = MSG_ToCoord(value, 2); + bi_trace(); SZ_Write (&sv.multicast, (void*)&i, 2); } void QDECL GHL_WriteString(char *string) { + bi_trace(); MSG_WriteString(&sv.multicast, string); } void QDECL GHL_WriteEntity(int entnum) { + bi_trace(); MSG_WriteEntity(&sv.multicast, entnum); } @@ -608,6 +674,11 @@ void QDECL GHL_AlertMessage(int level, char *fmt, ...) va_list argptr; char string[1024]; + bi_trace(); + + if (level == 2 && !developer.ival) + return; + va_start (argptr, fmt); vsnprintf (string,sizeof(string)-1, fmt,argptr); va_end (argptr); @@ -616,11 +687,13 @@ void QDECL GHL_AlertMessage(int level, char *fmt, ...) } void QDECL GHL_EngineFprintf(FILE *f, char *fmt, ...) { + bi_trace(); SV_Error("Halflife gamecode tried to use EngineFprintf\n"); } unk QDECL GHL_SzFromIndex(unk){notimpf(__func__);} void *QDECL GHL_GetModelPtr(hledict_t *ed) { + bi_trace(); #ifdef SERVERONLY return NULL; #else @@ -633,6 +706,7 @@ void *QDECL GHL_GetModelPtr(hledict_t *ed) } int QDECL GHL_RegUserMsg(char *msgname, int msgsize) { + bi_trace(); //we use 1 as the code to choose others. if (lastusermessage <= 1) return -1; @@ -660,44 +734,53 @@ unk QDECL GHL_GetBonePosition(unk){notimpf(__func__);} hlintptr_t QDECL GHL_FunctionFromName(char *name) { + bi_trace(); return (hlintptr_t)Sys_GetAddressForName(hlgamecode, name); } char *QDECL GHL_NameForFunction(hlintptr_t function) { + bi_trace(); return Sys_GetNameForAddress(hlgamecode, (void*)function); } unk QDECL GHL_ClientPrintf(unk) { + bi_trace(); // SV_ClientPrintf( notimpf(__func__); } void QDECL GHL_ServerPrint(char *msg) { + bi_trace(); Con_Printf("%s", msg); } char *QDECL GHL_Cmd_Args(void) { + bi_trace(); return Cmd_Args(); } char *QDECL GHL_Cmd_Argv(int arg) { + bi_trace(); return Cmd_Argv(arg); } int QDECL GHL_Cmd_Argc(unk) { + bi_trace(); return Cmd_Argc(); } unk QDECL GHL_GetAttachment(unk){notimpf(__func__);} void QDECL GHL_CRC32_Init(hlcrc_t *crc) { unsigned short crc16 = *crc; + bi_trace(); QCRC_Init(&crc16); *crc = crc16; } void QDECL GHL_CRC32_ProcessBuffer(hlcrc_t *crc, qbyte *p, int len) { unsigned short crc16 = *crc; + bi_trace(); while(len-->0) { QCRC_ProcessByte(&crc16, *p++); @@ -707,20 +790,24 @@ void QDECL GHL_CRC32_ProcessBuffer(hlcrc_t *crc, qbyte *p, int len) void QDECL GHL_CRC32_ProcessByte(hlcrc_t *crc, qbyte b) { unsigned short crc16 = *crc; + bi_trace(); QCRC_ProcessByte(&crc16, b); *crc = crc16; } hlcrc_t QDECL GHL_CRC32_Final(hlcrc_t crc) { unsigned short crc16 = crc; + bi_trace(); return QCRC_Value(crc16); } long QDECL GHL_RandomLong(long minv, long maxv) { + bi_trace(); return minv + frandom()*(maxv-minv); } float QDECL GHL_RandomFloat(float minv, float maxv) { + bi_trace(); return minv + frandom()*(maxv-minv); } unk QDECL GHL_SetView(unk){notimpf(__func__);} @@ -730,6 +817,7 @@ void *QDECL GHL_LoadFileForMe(char *name, int *size_out) { int fsize; void *fptr; + bi_trace(); fsize = FS_LoadFile(name, &fptr); if (size_out) *size_out = fsize; @@ -739,6 +827,7 @@ void *QDECL GHL_LoadFileForMe(char *name, int *size_out) } void QDECL GHL_FreeFile(void *fptr) { + bi_trace(); FS_FreeFile(fptr); } unk QDECL GHL_EndSection(unk){notimpf(__func__);} @@ -747,6 +836,8 @@ int QDECL GHL_CompareFileTime(char *fname1, char *fname2, int *result) { flocation_t loc1, loc2; struct stat stat1, stat2; + bi_trace(); + //results: //1 = f1 is newer //0 = equal age @@ -771,6 +862,7 @@ int QDECL GHL_CompareFileTime(char *fname1, char *fname2, int *result) void QDECL GHL_GetGameDir(char *gamedir) { extern char gamedirfile[]; + bi_trace(); //warning: the output buffer size is not specified! Q_strncpyz(gamedir, gamedirfile, MAX_QPATH); } @@ -778,16 +870,19 @@ unk QDECL GHL_Cvar_RegisterVariable(unk){notimpf(__func__);} unk QDECL GHL_FadeClientVolume(unk){notimpf(__func__);} unk QDECL GHL_SetClientMaxspeed(unk) { + bi_trace(); notimpf(__func__); } unk QDECL GHL_CreateFakeClient(unk){notimpf(__func__);} unk QDECL GHL_RunPlayerMove(unk){notimpf(__func__);} int QDECL GHL_NumberOfEntities(void) { + bi_trace(); return 0; } char *QDECL GHL_GetInfoKeyBuffer(hledict_t *ed) { + bi_trace(); if (!ed) return svs.info; @@ -795,6 +890,7 @@ char *QDECL GHL_GetInfoKeyBuffer(hledict_t *ed) } char *QDECL GHL_InfoKeyValue(char *infostr, char *key) { + bi_trace(); return Info_ValueForKey(infostr, key); } unk QDECL GHL_SetKeyValue(unk){notimpf(__func__);} @@ -805,6 +901,7 @@ unk QDECL GHL_PrecacheGeneric(unk){notimpf(__func__);} int QDECL GHL_GetPlayerUserId(hledict_t *ed) { unsigned int clnum = (ed - SVHL_Edict) - 1; + bi_trace(); if (clnum >= sv.allocated_client_slots) return -1; return svs.clients[clnum].userid; @@ -813,6 +910,7 @@ unk QDECL GHL_BuildSoundMsg(unk){notimpf(__func__);} int QDECL GHL_IsDedicatedServer(void) { + bi_trace(); #ifdef SERVERONLY return 1; #else @@ -834,6 +932,7 @@ void SVHL_FreeCvars(void) { cvar_t *nc; hlcvar_t *n; + //forget all while (hlcvar_malloced) { @@ -860,8 +959,8 @@ void SVHL_FreeCvar(hlcvar_t *var) { cvar_t *nc; hlcvar_t **ref; - //unlink (free if it was malloced) + //unlink (free if it was malloced) ref = &hlcvar_malloced; while (*ref) { @@ -898,6 +997,7 @@ hlcvar_t *QDECL GHL_CVarGetPointer(char *varname) { cvar_t *var; hlcvar_t *hlvar; + bi_trace(); var = Cvar_Get(varname, "", 0, "HalfLife"); if (!var) { @@ -920,6 +1020,7 @@ hlcvar_t *QDECL GHL_CVarGetPointer(char *varname) void QDECL GHL_CVarRegister(hlcvar_t *hlvar) { cvar_t *var; + bi_trace(); var = Cvar_Get(hlvar->name, hlvar->string, 0, "HalfLife"); if (!var) { @@ -938,6 +1039,7 @@ void QDECL GHL_CVarRegister(hlcvar_t *hlvar) float QDECL GHL_CVarGetFloat(char *vname) { cvar_t *var = Cvar_FindVar(vname); + bi_trace(); if (var) return var->value; Con_Printf("cvar %s does not exist\n", vname); @@ -946,6 +1048,7 @@ float QDECL GHL_CVarGetFloat(char *vname) char *QDECL GHL_CVarGetString(char *vname) { cvar_t *var = Cvar_FindVar(vname); + bi_trace(); if (var) return var->string; Con_Printf("cvar %s does not exist\n", vname); @@ -954,6 +1057,7 @@ char *QDECL GHL_CVarGetString(char *vname) void QDECL GHL_CVarSetFloat(char *vname, float value) { cvar_t *var = Cvar_FindVar(vname); + bi_trace(); if (var) Cvar_SetValue(var, value); else @@ -962,6 +1066,7 @@ void QDECL GHL_CVarSetFloat(char *vname, float value) void QDECL GHL_CVarSetString(char *vname, char *value) { cvar_t *var = Cvar_FindVar(vname); + bi_trace(); if (var) Cvar_Set(var, value); else @@ -971,15 +1076,22 @@ void QDECL GHL_CVarSetString(char *vname, char *value) unk QDECL GHL_GetPlayerWONId(unk){notimpf(__func__);} unk QDECL GHL_Info_RemoveKey(unk){notimpf(__func__);} unk QDECL GHL_GetPhysicsKeyValue(unk){notimpf(__func__);} -unk QDECL GHL_SetPhysicsKeyValue(unk){notimpf(__func__);} +void QDECL GHL_SetPhysicsKeyValue(hledict_t *ent, char *key, char *value) +{ + bi_begin(); + notimpf(__func__); + bi_end(); +} unk QDECL GHL_GetPhysicsInfoString(unk){notimpf(__func__);} unsigned short QDECL GHL_PrecacheEvent(int eventtype, char *eventname) { + bi_trace(); Con_Printf("Fixme: GHL_PrecacheEvent: %s\n", eventname); return 0; } void QDECL GHL_PlaybackEvent(int flags, hledict_t *ent, unsigned short eventidx, float delay, float *origin, float *angles, float f1, float f2, int i1, int i2, int b1, int b2) { + bi_trace(); ignore("GHL_PlaybackEvent not implemented"); } unk QDECL GHL_SetFatPVS(unk){notimpf(__func__);} @@ -991,6 +1103,7 @@ unk QDECL GHL_DeltaAddEncoder(unk){notimpf(__func__);} unk QDECL GHL_GetCurrentPlayer(unk){notimpf(__func__);} int QDECL GHL_CanSkipPlayer(hledict_t *playerent) { + bi_trace(); return false; // notimpf(__func__); } @@ -1006,9 +1119,17 @@ unk QDECL GHL_AddServerCommand(unk){notimpf(__func__);} unk QDECL GHL_Voice_GetClientListening(unk){notimpf(__func__);} qboolean QDECL GHL_Voice_SetClientListening(int listener, int sender, int shouldlisten) { + bi_trace(); return false; } -unk QDECL GHL_GetPlayerAuthId(unk){notimpf(__func__);} +char *QDECL GHL_GetPlayerAuthId(hledict_t *playered) +{ + unsigned int clnum = (playered - SVHL_Edict) - 1; + bi_trace(); + if (clnum >= sv.allocated_client_slots) + return NULL; + return svs.clients[clnum].guid; +} unk QDECL GHL_SequenceGet(unk){notimpf(__func__);} unk QDECL GHL_SequencePickSentence(unk){notimpf(__func__);} unk QDECL GHL_GetFileSize(unk){notimpf(__func__);} @@ -1234,7 +1355,8 @@ void SV_ReadLibListDotGam(void) int SVHL_InitGame(void) { char *gamedll; - char *path; + void *iterator; + char path[MAX_OSPATH]; char fullname[MAX_OSPATH]; void (WINAPI *GiveFnptrsToDll) (funcs, globals); int (QDECL *GetEntityAPI)(SVHL_GameFuncs_t *pFunctionTable, int apivers); @@ -1256,37 +1378,33 @@ int SVHL_InitGame(void) if (hlgamecode) { - SVHL_Edict = Hunk_Alloc(sizeof(*SVHL_Edict) * MAX_HL_EDICTS); + ZG_FreeGroup(&hlmapmemgroup); + + SVHL_Edict = ZG_Malloc(&hlmapmemgroup, sizeof(*SVHL_Edict) * MAX_HL_EDICTS); SVHL_Globals.maxentities = MAX_HL_EDICTS; //I think this is correct return 1; } - hlgamecode = NULL;//Sys_LoadLibrary("C:/Incoming/d/Half-Life/sdks/hlsdk-2.3-p3/hlsdk-2.3-p3/multiplayer/dlls/debugmp/mp.dll", hlgamefuncs); - if (!hlgamecode) + gamedll = Info_ValueForKey(svs.info, "*gamedll"); + iterator = NULL; + while(COM_IteratePaths(&iterator, path, sizeof(path))) { - gamedll = Info_ValueForKey(svs.info, "*gamedll"); - path = NULL; - while((path = COM_NextPath (path))) - { - if (!path) - return 0; // couldn't find one anywhere - snprintf (fullname, sizeof(fullname), "%s/%s", path, gamedll); - hlgamecode = Sys_LoadLibrary(fullname, hlgamefuncs); - if (hlgamecode) - break; - } + snprintf (fullname, sizeof(fullname), "%s%s", path, gamedll); + hlgamecode = Sys_LoadLibrary(fullname, hlgamefuncs); + if (hlgamecode) + break; } if (!hlgamecode) return 0; - SVHL_Edict = Hunk_Alloc(sizeof(*SVHL_Edict) * MAX_HL_EDICTS); + SVHL_Edict = ZG_Malloc(&hlmapmemgroup, sizeof(*SVHL_Edict) * MAX_HL_EDICTS); SVHL_Globals.maxentities = MAX_HL_EDICTS; //I think this is correct GiveFnptrsToDll(&SVHL_Builtins, &SVHL_Globals); if (!GetEntityAPI(&SVHL_GameFuncs, HALFLIFE_API_VERSION)) { - Con_Printf(CON_ERROR "Error: %s is incompatible (FTE is %i)\n", fullname, HALFLIFE_API_VERSION); + Con_Printf(CON_ERROR "Error: %s is incompatible (FTE is compiled for %i)\n", fullname, HALFLIFE_API_VERSION); if (GetEntityAPI(&SVHL_GameFuncs, 138)) Con_Printf(CON_ERROR "mod is 138\n"); Sys_CloseLibrary(hlgamecode); @@ -1294,7 +1412,9 @@ int SVHL_InitGame(void) return 0; } + bi_begin(); SVHL_GameFuncs.GameDLLInit(); + bi_end(); return 1; } @@ -1321,7 +1441,7 @@ void SVHL_SpawnEntities(char *entstring) int i; //initialise globals - SVHL_Globals.stringbase = ""; + SVHL_Globals.stringbase = ""; //uninitialised strings are considered empty and not crashy. this ensures that is true. SVHL_Globals.maxclients = svs.allocated_client_slots; SVHL_Globals.deathmatch = deathmatch.value; SVHL_Globals.coop = coop.value; @@ -1330,6 +1450,7 @@ void SVHL_SpawnEntities(char *entstring) SVHL_NumActiveEnts = 0; + sv.allocated_client_slots = 0; //touch world. world = GHL_CreateNamedEntity(GHL_AllocString("worldspawn")); @@ -1337,7 +1458,6 @@ void SVHL_SpawnEntities(char *entstring) GHL_SetModel(world, sv.modelname); //spawn player ents - sv.allocated_client_slots = 0; for (i = 0; i < SVHL_Globals.maxclients; i++) { sv.allocated_client_slots++; @@ -1428,7 +1548,9 @@ void SVHL_SpawnEntities(char *entstring) SVHL_GameFuncs.DispatchSpawn(ed); } + bi_begin(); SVHL_GameFuncs.ServerActivate(SVHL_Edict, SVHL_NumActiveEnts, sv.allocated_client_slots); + bi_end(); } void SVHL_ShutdownGame(void) @@ -1443,6 +1565,8 @@ void SVHL_ShutdownGame(void) memset(&SVHL_Globals, 0, sizeof(SVHL_Globals)); memset(&SVHL_GameFuncs, 0, sizeof(SVHL_GameFuncs)); memset(&SVHL_GameFuncsEx, 0, sizeof(SVHL_GameFuncsEx)); + + ZG_FreeGroup(&hlmapmemgroup); } qboolean HLSV_ClientCommand(client_t *client) @@ -1450,20 +1574,24 @@ qboolean HLSV_ClientCommand(client_t *client) hledict_t *ed = &SVHL_Edict[client - svs.clients + 1]; if (!hlgamecode) return false; + bi_begin(); SVHL_GameFuncs.ClientCommand(ed); + bi_end(); return true; } qboolean SVHL_ClientConnect(client_t *client, netadr_t adr, char rejectmessage[128]) { + qboolean result; char ipadr[256]; - NET_AdrToString(ipadr, sizeof(ipadr), adr); + NET_AdrToString(ipadr, sizeof(ipadr), &adr); strcpy(rejectmessage, "Rejected by gamecode"); - if (!SVHL_GameFuncs.ClientConnect(&SVHL_Edict[client-svs.clients+1], client->name, ipadr, rejectmessage)) - return false; + bi_begin(); + result = SVHL_GameFuncs.ClientConnect(&SVHL_Edict[client-svs.clients+1], client->name, ipadr, rejectmessage); + bi_end(); - return true; + return result; } void SVHL_BuildStats(client_t *client, int *si, float *sf, char **ss) @@ -1480,17 +1608,21 @@ void SVHL_PutClientInServer(client_t *client) { hledict_t *ed = &SVHL_Edict[client - svs.clients + 1]; ed->isfree = false; + bi_begin(); SVHL_GameFuncs.ClientPutInServer(&SVHL_Edict[client-svs.clients+1]); + bi_end(); } void SVHL_DropClient(client_t *drop) { hledict_t *ed = &SVHL_Edict[drop - svs.clients + 1]; + bi_begin(); SVHL_GameFuncs.ClientDisconnect(&SVHL_Edict[drop-svs.clients+1]); + bi_end(); ed->isfree = true; } -void SVHL_RunCmdR(hledict_t *ed, usercmd_t *ucmd) +static void SVHL_RunCmdR(hledict_t *ed, usercmd_t *ucmd) { int i; hledict_t *other; @@ -1690,6 +1822,8 @@ void SVHL_RunCmd(client_t *cl, usercmd_t *ucmd) ed->v.angles[1] = SHORT2ANGLE(ucmd->angles[1]); ed->v.angles[2] = SHORT2ANGLE(ucmd->angles[2]); + + bi_begin(); SVHL_GameFuncs.PlayerPreThink(ed); SVHL_RunCmdR(ed, ucmd); @@ -1700,6 +1834,8 @@ void SVHL_RunCmd(client_t *cl, usercmd_t *ucmd) } SVHL_GameFuncs.PlayerPostThink(ed); + + bi_end(); } @@ -1755,6 +1891,8 @@ void SVHL_Snapshot_Build(client_t *client, packet_entities_t *pack, qbyte *pvs, s->frame = e->v.sequence1; s->effects = e->v.effects; s->skinnum = e->v.skin; + s->scale = 16; + s->trans = 255; VectorCopy(e->v.angles, s->angles); VectorCopy(e->v.origin, s->origin); } diff --git a/engine/server/svhl_gcapi.h b/engine/server/svhl_gcapi.h index 31c8ec530..054d18bb3 100644 --- a/engine/server/svhl_gcapi.h +++ b/engine/server/svhl_gcapi.h @@ -413,7 +413,7 @@ typedef struct unk (QDECL *SaveSpawnParms)(unk); float (QDECL *VecToYaw)(float *inv); void (QDECL *VecToAngles)(float *inv, float *outa); - unk (QDECL *MoveToOrigin)(unk); + void (QDECL *MoveToOrigin)(hledict_t *ent, vec3_t dest, float dist, int moveflags); unk (QDECL *ChangeYaw)(unk); unk (QDECL *ChangePitch)(unk); hledict_t *(QDECL *FindEntityByString)(hledict_t *last, char *field, char *value); @@ -524,7 +524,7 @@ typedef struct unk (QDECL *GetPlayerWONId)(unk); unk (QDECL *Info_RemoveKey)(unk); unk (QDECL *GetPhysicsKeyValue)(unk); - unk (QDECL *SetPhysicsKeyValue)(unk); + void (QDECL *SetPhysicsKeyValue)(hledict_t *ent, char *key, char *value); unk (QDECL *GetPhysicsInfoString)(unk); unsigned short (QDECL *PrecacheEvent)(int eventtype, char *eventname); void (QDECL *PlaybackEvent)(int flags, hledict_t *ent, unsigned short eventidx, float delay, float *origin, float *angles, float f1, float f2, int i1, int i2, int b1, int b2); @@ -549,7 +549,7 @@ typedef struct unk (QDECL *Voice_GetClientListening)(unk); qboolean (QDECL *Voice_SetClientListening)(int listener, int sender, int shouldlisten); //140 - unk (QDECL *GetPlayerAuthId)(unk); + char *(QDECL *GetPlayerAuthId)(hledict_t *playerent); unk (QDECL *SequenceGet)(unk); unk (QDECL *SequencePickSentence)(unk); unk (QDECL *GetFileSize)(unk); diff --git a/engine/server/svhl_phys.c b/engine/server/svhl_phys.c index 4f8a1e65c..0753f74ca 100644 --- a/engine/server/svhl_phys.c +++ b/engine/server/svhl_phys.c @@ -648,6 +648,7 @@ SV_Push ============ */ +#define MAX_PUSHED_ENTITIES 1024 qboolean SVHL_Push (hledict_t *pusher, vec3_t move, vec3_t amove) { int i, e; @@ -655,8 +656,8 @@ qboolean SVHL_Push (hledict_t *pusher, vec3_t move, vec3_t amove) vec3_t mins, maxs; vec3_t pushorig; int num_moved; - hledict_t *moved_edict[MAX_EDICTS]; - vec3_t moved_from[MAX_EDICTS]; + hledict_t *moved_edict[MAX_PUSHED_ENTITIES]; + vec3_t moved_from[MAX_PUSHED_ENTITIES]; float oldsolid; if (amove[0] || amove[1] || amove[2]) @@ -715,45 +716,48 @@ qboolean SVHL_Push (hledict_t *pusher, vec3_t move, vec3_t amove) continue; } - VectorCopy (check->v.origin, moved_from[num_moved]); - moved_edict[num_moved] = check; - num_moved++; - -// check->v.flags = (int)check->v.flags & ~FL_ONGROUND; - - // try moving the contacted entity - VectorAdd (check->v.origin, move, check->v.origin); - block = SVHL_TestEntityPosition (check); - if (!block) - { // pushed ok - SVHL_LinkEdict (check, false); - continue; - } - - // if it is ok to leave in the old position, do it - VectorSubtract (check->v.origin, move, check->v.origin); - block = SVHL_TestEntityPosition (check); - if (!block) + if (num_moved < MAX_PUSHED_ENTITIES) { - //if leaving it where it was, allow it to drop to the floor again (useful for plats that move downward) - check->v.flags = (int)check->v.flags & ~FL_ONGROUND; + VectorCopy (check->v.origin, moved_from[num_moved]); + moved_edict[num_moved] = check; + num_moved++; - num_moved--; - continue; - } + // check->v.flags = (int)check->v.flags & ~FL_ONGROUND; - // if it is still inside the pusher, block - if (check->v.mins[0] == check->v.maxs[0]) - { - SVHL_LinkEdict (check, false); - continue; - } - if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) - { // corpse - check->v.mins[0] = check->v.mins[1] = 0; - VectorCopy (check->v.mins, check->v.maxs); - SVHL_LinkEdict (check, false); - continue; + // try moving the contacted entity + VectorAdd (check->v.origin, move, check->v.origin); + block = SVHL_TestEntityPosition (check); + if (!block) + { // pushed ok + SVHL_LinkEdict (check, false); + continue; + } + + // if it is ok to leave in the old position, do it + VectorSubtract (check->v.origin, move, check->v.origin); + block = SVHL_TestEntityPosition (check); + if (!block) + { + //if leaving it where it was, allow it to drop to the floor again (useful for plats that move downward) + check->v.flags = (int)check->v.flags & ~FL_ONGROUND; + + num_moved--; + continue; + } + + // if it is still inside the pusher, block + if (check->v.mins[0] == check->v.maxs[0]) + { + SVHL_LinkEdict (check, false); + continue; + } + if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) + { // corpse + check->v.mins[0] = check->v.mins[1] = 0; + VectorCopy (check->v.mins, check->v.maxs); + SVHL_LinkEdict (check, false); + continue; + } } VectorCopy (pushorig, pusher->v.origin); diff --git a/engine/server/svmodel.c b/engine/server/svmodel.c index 6c5625e85..5a4613e63 100644 --- a/engine/server/svmodel.c +++ b/engine/server/svmodel.c @@ -37,7 +37,7 @@ qboolean Mod_LoadQ3Model (model_t *mod, void *buffer); qboolean Mod_LoadZymoticModel (model_t *mod, void *buffer); qboolean Mod_LoadDarkPlacesModel(model_t *mod, void *buffer); -qbyte mod_novis[MAX_MAP_LEAFS/8]; +qbyte mod_novis[(MAX_MAP_LEAFS+7)/8]; #define MAX_MOD_KNOWN 512 model_t mod_known[MAX_MOD_KNOWN]; @@ -323,7 +323,7 @@ qbyte *Mod_DecompressVis (qbyte *in, model_t *model, qbyte *decompressed) qbyte *Mod_LeafPVS (mleaf_t *leaf, model_t *model, qbyte *buffer) { - static qbyte decompressed[MAX_MAP_LEAFS/8]; + static qbyte decompressed[(MAX_MAP_LEAFS+7)/8]; if (leaf == model->leafs) return mod_novis; diff --git a/engine/server/world.c b/engine/server/world.c index 4dab692d9..c01d1462e 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -1019,7 +1019,7 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v int mdlidx = ent->v->modelindex; // get the clipping hull - if (ent->v->solid == SOLID_BSP && mdlidx) + if ((ent->v->solid == SOLID_BSP || ent->v->solid == SOLID_PORTAL) && mdlidx) { model = w->Get_CModel(w, mdlidx); if (!model || (model->type != mod_brush && model->type != mod_heightmap)) @@ -1040,7 +1040,13 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v } // trace a line through the apropriate clipping hull - if (ent->v->solid != SOLID_BSP) + if (ent->v->solid == SOLID_PORTAL) + { + //solid_portal cares only about origins and as such has no mins/max + TransformedTrace(model, 0, ent->v->frame, start, end, vec3_origin, vec3_origin, &trace, eorg, ent->v->angles, hitcontentsmask); + hitmodel = false; + } + else if (ent->v->solid != SOLID_BSP) { ent->v->angles[0]*=-1; //carmack made bsp models rotate wrongly. TransformedTrace(model, hullnum, ent->v->frame, start, end, mins, maxs, &trace, eorg, ent->v->angles, hitcontentsmask); @@ -1533,6 +1539,9 @@ static void World_ClipToLinks (world_t *w, areanode_t *node, moveclip_t *clip) else trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->hitcontentsmask); + if (trace.startsolid && touch->v->solid == SOLID_PORTAL) + continue; + if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) {