From 45bafbf3745af5c0ff4132e4bbbc5a2ff03df59e Mon Sep 17 00:00:00 2001 From: Spoike Date: Wed, 17 Sep 2014 03:04:08 +0000 Subject: [PATCH] fix issue with more submodels than the precache model limit. bump model precache limit. move some of the weird hexen2 features into a HEXEN2 define, which will be disabled by the QUAKETC define. preliminary attempt at capsule collision support. only capsule/q3bsp support, no capsule/box, box/capsule, or capsule/capsule support, yet. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4753 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/cl_cg.c | 35 ++- engine/client/cl_demo.c | 4 +- engine/client/cl_ents.c | 38 ++- engine/client/cl_main.c | 3 +- engine/client/cl_parse.c | 24 +- engine/client/cl_pred.c | 5 +- engine/client/cl_screen.c | 2 +- engine/client/cl_tent.c | 1 - engine/client/client.h | 10 +- engine/client/m_items.c | 7 +- engine/client/m_single.c | 2 +- engine/client/menu.c | 3 +- engine/client/p_script.c | 2 +- engine/client/pr_csqc.c | 21 +- engine/client/r_part.c | 4 +- engine/client/r_surf.c | 6 +- engine/client/render.h | 2 + engine/client/renderer.c | 10 +- engine/client/sbar.c | 13 +- engine/client/skin.c | 8 +- engine/client/snd_dma.c | 2 +- engine/client/view.c | 45 ++- engine/client/zqtp.c | 4 +- engine/common/bothdefs.h | 19 +- engine/common/bspfile.h | 10 +- engine/common/com_mesh.c | 82 ++++- engine/common/common.c | 20 +- engine/common/gl_q2bsp.c | 244 +++++++++------ engine/common/pmove.c | 2 +- engine/common/pmove.h | 1 + engine/common/pmovetst.c | 4 +- engine/common/pr_bgcmd.c | 23 +- engine/common/pr_common.h | 3 +- engine/common/q1bsp.c | 5 +- engine/common/translate.c | 4 +- engine/common/world.h | 2 + engine/d3d/d3d11_backend.c | 6 + engine/d3d/d3d_backend.c | 6 + engine/gl/gl_alias.c | 8 +- engine/gl/gl_heightmap.c | 6 +- engine/gl/gl_model.h | 5 +- engine/gl/gl_rmain.c | 6 + engine/gl/ltface.c | 2 +- engine/qclib/execloop.h | 369 ++++++++++------------- engine/qclib/pr_exec.c | 48 ++- engine/server/net_preparse.c | 9 +- engine/server/pr_cmds.c | 568 ++++++++++++++++++----------------- engine/server/pr_lua.c | 1 - engine/server/pr_q1qvm.c | 6 +- engine/server/progs.h | 1 + engine/server/savegame.c | 22 +- engine/server/server.h | 11 +- engine/server/sv_ccmds.c | 18 +- engine/server/sv_ents.c | 14 +- engine/server/sv_init.c | 61 +++- engine/server/sv_main.c | 11 +- engine/server/sv_phys.c | 13 +- engine/server/sv_send.c | 10 +- engine/server/sv_user.c | 4 +- engine/server/svhl_game.c | 1 + engine/server/svq2_game.c | 2 +- engine/server/svq3_game.c | 11 +- engine/server/world.c | 133 ++++---- 63 files changed, 1132 insertions(+), 890 deletions(-) diff --git a/engine/client/cl_cg.c b/engine/client/cl_cg.c index af06bfed9..cb9392974 100644 --- a/engine/client/cl_cg.c +++ b/engine/client/cl_cg.c @@ -577,8 +577,13 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con unsigned int pc; unsigned int modhandle = VM_LONG(arg[1]); model_t *mod; - if (modhandle >= MAX_MODELS) - mod = &box_model; + if (modhandle >= MAX_PRECACHE_MODELS) + { +// if (modhandle == MAX_PRECACHE_MODELS+1) +// mod = &capsule_model; +// else + mod = &box_model; + } else mod = cl.model_precache[modhandle+1]; if (mod && !mod->needload) @@ -597,7 +602,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con float *origin = VM_POINTER(arg[2]); float *angles = VM_POINTER(arg[3]); model_t *mod; - if (modhandle >= MAX_MODELS) + if (modhandle >= MAX_PRECACHE_MODELS) mod = &box_model; else mod = cl.model_precache[modhandle+1]; @@ -626,6 +631,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con } break; + case CG_CM_TRANSFORMEDCAPSULETRACE: case CG_CM_TRANSFORMEDBOXTRACE: // void trap_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end, // const vec3_t mins, const vec3_t maxs, @@ -643,7 +649,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con float *origin = VM_POINTER(arg[7]); float *angles = VM_POINTER(arg[8]); model_t *mod; - if (modhandle >= MAX_MODELS) + if (modhandle >= MAX_PRECACHE_MODELS) mod = &box_model; else mod = cl.model_precache[modhandle+1]; @@ -656,15 +662,15 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con origin = vec3_origin; if (!angles) angles = vec3_origin; - if (mod) -#ifndef CLIENTONLY - TransformedNativeTrace(mod, 0, 0, start, end, mins, maxs, brushmask, &tr, origin, angles); + if (mod && !mod->needload) +#if !defined(CLIENTONLY) || defined(CSQC_DAT) + World_TransformedTrace(mod, 0, 0, start, end, mins, maxs, fn==CG_CM_TRANSFORMEDCAPSULETRACE, &tr, origin, angles, brushmask); #else { #ifdef warningmsg -#pragma warningmsg("FIXME: G3 CGame requires TransformedNativeTrace!") +#pragma warningmsg("FIXME: G3 CGame requires World_TransformedTrace!") #endif - memset(&tr, 0, sizeof(tr)); + memset(&tr, 0, sizeof(tr)); tr.allsolid = tr.startsolid = true; tr.contents = 1; } @@ -685,6 +691,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con memcpy(&results->plane, &tr.plane, sizeof(cplane_t)); } break; + case CG_CM_CAPSULETRACE: case CG_CM_BOXTRACE: // void trap_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end, // const vec3_t mins, const vec3_t maxs, @@ -700,7 +707,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con unsigned int modhandle = VM_LONG(arg[5]); int brushmask = VM_LONG(arg[6]); model_t *mod; - if (modhandle >= MAX_MODELS) + if (modhandle >= MAX_PRECACHE_MODELS) mod = &box_model; else mod = cl.model_precache[modhandle+1]; @@ -709,7 +716,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con mins = vec3_origin; if (!maxs) maxs = vec3_origin; - mod->funcs.NativeTrace(mod, 0, 0, NULL, start, end, mins, maxs, brushmask, &tr); + mod->funcs.NativeTrace(mod, 0, 0, NULL, start, end, mins, maxs, fn==CG_CM_CAPSULETRACE, brushmask, &tr); results->allsolid = tr.allsolid; results->contents = tr.contents; results->fraction = tr.fraction; @@ -754,7 +761,11 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con case CG_CM_TEMPBOXMODEL: CM_TempBoxModel(VM_POINTER(arg[0]), VM_POINTER(arg[1])); - VM_LONG(ret) = MAX_MODELS; + VM_LONG(ret) = MAX_PRECACHE_MODELS; + break; + case CG_CM_TEMPCAPSULEMODEL: + CM_TempBoxModel(VM_POINTER(arg[0]), VM_POINTER(arg[1])); + VM_LONG(ret) = MAX_PRECACHE_MODELS+1; break; case CG_R_MODELBOUNDS: diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index a55c5b66e..cf9252508 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -1291,10 +1291,10 @@ void CL_Record_f (void) MSG_WriteByte (&buf, svc_spawnstatic); - for (j = 1; j < MAX_MODELS; j++) + for (j = 1; j < MAX_PRECACHE_MODELS; j++) if (ent->model == cl.model_precache[j]) break; - if (j == MAX_MODELS) + if (j == MAX_PRECACHE_MODELS) MSG_WriteByte (&buf, 0); else MSG_WriteByte (&buf, j); diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index a20ed392b..be2693b7c 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -1790,7 +1790,6 @@ void V_ClearEntity(entity_t *e) e->playerindex = -1; e->topcolour = TOP_DEFAULT; e->bottomcolour = BOTTOM_DEFAULT; - e->h2playerclass = 0; } entity_t *V_AddEntity(entity_t *in) { @@ -2478,10 +2477,29 @@ void CLQ1_AddVisibleBBoxes(void) } else { - VectorCopy(e->v->absmin, min); - VectorCopy(e->v->absmax, max); + if (e->v->solid == SOLID_BSP) + { + VectorCopy(e->v->absmin, min); + VectorCopy(e->v->absmax, max); + } + else + { + VectorAdd(e->v->origin, e->v->mins, min); + VectorAdd(e->v->origin, e->v->maxs, max); + } } - CLQ1_AddOrientedCube(s, min, max, NULL, (e->v->solid || e->v->movetype)?0.1:0, (e->v->movetype == MOVETYPE_STEP || e->v->movetype == MOVETYPE_TOSS || e->v->movetype == MOVETYPE_BOUNCE)?0.1:0, ((int)e->v->flags & (FL_ONGROUND | ((e->v->movetype == MOVETYPE_STEP)?FL_FLY:0)))?0.1:0, 1); + if (e->xv->geomtype == GEOMTYPE_CAPSULE) + { + float rad = ((e->v->maxs[0]-e->v->mins[0]) + (e->v->maxs[1]-e->v->mins[1]))/4.0; + float height = (e->v->maxs[2]-e->v->mins[2])/2; + float matrix[12] = {1,0,0,0,0,1,0,0,0,0,1,0}; + matrix[3] = e->v->origin[0]; + matrix[7] = e->v->origin[1]; + matrix[11] = e->v->origin[2] + (e->v->maxs[2]-height); + CLQ1_AddOrientedCylinder(s, rad*2, height*2, true, matrix, (e->v->solid || e->v->movetype)?0.1:0, (e->v->movetype == MOVETYPE_STEP || e->v->movetype == MOVETYPE_TOSS || e->v->movetype == MOVETYPE_BOUNCE)?0.1:0, ((int)e->v->flags & (FL_ONGROUND | ((e->v->movetype == MOVETYPE_STEP)?FL_FLY:0)))?0.1:0, 1); + } + else + CLQ1_AddOrientedCube(s, min, max, NULL, (e->v->solid || e->v->movetype)?0.1:0, (e->v->movetype == MOVETYPE_STEP || e->v->movetype == MOVETYPE_TOSS || e->v->movetype == MOVETYPE_BOUNCE)?0.1:0, ((int)e->v->flags & (FL_ONGROUND | ((e->v->movetype == MOVETYPE_STEP)?FL_FLY:0)))?0.1:0, 1); } } @@ -3276,7 +3294,9 @@ void CL_LinkPacketEntities (void) ent->customskin = 0; ent->topcolour = TOP_DEFAULT; ent->bottomcolour = BOTTOM_DEFAULT; +#ifdef HEXEN2 ent->h2playerclass = 0; +#endif ent->light_known = 0; ent->forcedshader = NULL; @@ -3593,12 +3613,15 @@ void CL_LinkPacketEntities (void) #ifdef warningmsg #pragma warningmsg("Replace this flag on load for hexen2 models") #endif +#ifdef HEXEN2 if (strncmp(model->name, "models/sflesh", 13)) +#endif { //hmm. hexen spider gibs... rad = 200; rad += r_lightflicker.value?((flicker + state->number)&31):0; } } +#ifdef HEXEN2 else if (modelflags & MFH2_FIREBALL) { rad = 120 - (r_lightflicker.value?(rand() % 20):10); @@ -3618,6 +3641,7 @@ void CL_LinkPacketEntities (void) dclr[2] = -dclr[2]; rad = 120 - (r_lightflicker.value?(rand() % 20):10); } +#endif if (rad) { @@ -3736,7 +3760,9 @@ void CL_LinkProjectiles (void) ent->playerindex = -1; ent->topcolour = TOP_DEFAULT; ent->bottomcolour = BOTTOM_DEFAULT; +#ifdef HEXEN2 ent->h2playerclass = 0; +#endif #ifdef PEXT_SCALE ent->scale = 1; #endif @@ -4457,7 +4483,9 @@ void CL_LinkPlayers (void) ent->playerindex = j; ent->topcolour = info->ttopcolor; ent->bottomcolour = info->tbottomcolor; +#ifdef HEXEN2 ent->h2playerclass = info->h2playerclass; +#endif #ifdef PEXT_SCALE ent->scale = state->scale; @@ -4617,7 +4645,7 @@ void CL_LinkViewModel(void) if (cl.intermission) return; - if (pv->stats[STAT_WEAPON] <= 0 || pv->stats[STAT_WEAPON] >= MAX_MODELS) + if (pv->stats[STAT_WEAPON] <= 0 || pv->stats[STAT_WEAPON] >= MAX_PRECACHE_MODELS) return; if (r_drawviewmodel.value > 0 && r_drawviewmodel.value < 1) diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 2190bb413..9850f05bc 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -1281,7 +1281,9 @@ void CL_ClearState (void) CL_ClearTEnts(); CL_ClearCustomTEnts(); Surf_ClearLightmaps(); +#ifdef HEXEN2 T_FreeInfoStrings(); +#endif SCR_ShowPic_Clear(false); if (cl.playerview[0].playernum == -1) @@ -2935,7 +2937,6 @@ void CLNQ_ConnectionlessPacket(void) return; case CCREP_REJECT: - connectinfo.trying = false; s = MSG_ReadString(); Con_Printf("Connect failed\n%s\n", s); return; diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 2113282bf..5380161f0 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -682,7 +682,7 @@ void CL_DownloadFinished(qdownload_t *dl) } } */ - for (i = 0; i < MAX_MODELS; i++) //go and load this model now. + for (i = 0; i < MAX_PRECACHE_MODELS; i++) //go and load this model now. { if (!strcmp(cl.model_name[i], filename)) { @@ -1134,7 +1134,7 @@ int CL_LoadModels(int stage, qboolean dontactuallyload) } else { - for (i=1 ; i= MAX_SOUNDS) + if (numsounds >= MAX_PRECACHE_SOUNDS) Host_EndGame ("Server sent too many sound_precache"); // if (strlen(str)>4) @@ -3626,7 +3626,7 @@ void CL_ParseModellist (qboolean lots) if (!str[0]) break; nummodels++; - if (nummodels>=MAX_MODELS) + if (nummodels>=MAX_PRECACHE_MODELS) Host_EndGame ("Server sent too many model_precache"); strcpy (cl.model_name[nummodels], str); @@ -4466,12 +4466,14 @@ void CL_ProcessUserInfo (int slot, player_info_t *player) */ player->model = NULL; +#ifdef HEXEN2 /*if we're running hexen2, they have to be some class...*/ player->h2playerclass = atoi(Info_ValueForKey (player->userinfo, "cl_playerclass")); if (player->h2playerclass > 5) player->h2playerclass = 5; if (player->h2playerclass < 1) player->h2playerclass = 1; +#endif player->colourised = TP_FindColours(player->name); @@ -5625,7 +5627,7 @@ void CL_ParsePrecache(void) switch(code & PC_TYPE) { case PC_MODEL: - if (i >= 1 && i < MAX_MODELS) + if (i >= 1 && i < MAX_PRECACHE_MODELS) { model_t *model; CL_CheckOrEnqueDownloadFile(s, s, 0); @@ -5638,12 +5640,12 @@ void CL_ParsePrecache(void) cl.model_precaches_added = true; } else - Con_Printf("svc_precache: model index %i outside range %i...%i\n", i, 1, MAX_MODELS); + Con_Printf("svc_precache: model index %i outside range %i...%i\n", i, 1, MAX_PRECACHE_MODELS); break; case PC_UNUSED: break; case PC_SOUND: - if (i >= 1 && i < MAX_SOUNDS) + if (i >= 1 && i < MAX_PRECACHE_SOUNDS) { sfx_t *sfx; if (S_HaveOutput()) @@ -5655,7 +5657,7 @@ void CL_ParsePrecache(void) Q_strncpyz (cl.sound_name[i], s, sizeof(cl.sound_name[i])); } else - Con_Printf("svc_precache: sound index %i outside range %i...%i\n", i, 1, MAX_SOUNDS); + Con_Printf("svc_precache: sound index %i outside range %i...%i\n", i, 1, MAX_PRECACHE_SOUNDS); break; case PC_PARTICLE: if (i >= 1 && i < MAX_SSPARTICLESPRE) diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 7e1b71c77..d169b61f1 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -170,7 +170,7 @@ q2trace_t VARGS CLQ2_PMTrace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end trace_t t; // check against world - cl.worldmodel->funcs.NativeTrace(cl.worldmodel, 0, 0, NULL, start, end, mins, maxs, MASK_PLAYERSOLID, &t); + cl.worldmodel->funcs.NativeTrace(cl.worldmodel, 0, 0, NULL, start, end, mins, maxs, false, MASK_PLAYERSOLID, &t); if (t.fraction < 1.0) t.ent = (struct edict_s *)1; @@ -406,6 +406,7 @@ void CL_PredictUsercmd (int pnum, int entnum, player_state_t *from, player_state movevars.bunnyspeedcap = cl.bunnyspeedcap; pmove.onladder = false; pmove.safeorigin_known = false; + pmove.capsule = false; //FIXME VectorCopy(from->szmins, pmove.player_mins); VectorCopy(from->szmaxs, pmove.player_maxs); @@ -666,7 +667,7 @@ static void CL_DecodeStateSize(unsigned short solid, int modelindex, vec3_t mins { if (solid == ES_SOLID_BSP) { - if (modelindex < MAX_MODELS && cl.model_precache[modelindex] && !cl.model_precache[modelindex]->needload) + if (modelindex < MAX_PRECACHE_MODELS && cl.model_precache[modelindex] && !cl.model_precache[modelindex]->needload) { VectorCopy(cl.model_precache[modelindex]->mins, mins); VectorCopy(cl.model_precache[modelindex]->maxs, maxs); diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index c0a3d3ffd..e91f4cb76 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -1094,7 +1094,7 @@ void SCR_CrosshairPosition(playerview_t *pview, float *x, float *y) memset(&tr, 0, sizeof(tr)); tr.fraction = 1; - cl.worldmodel->funcs.NativeTrace(cl.worldmodel, 0, 0, NULL, start, end, vec3_origin, vec3_origin, MASK_WORLDSOLID, &tr); + cl.worldmodel->funcs.NativeTrace(cl.worldmodel, 0, 0, NULL, start, end, vec3_origin, vec3_origin, false, MASK_WORLDSOLID, &tr); start[2]-=16; if (tr.fraction != 1) { diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 70159bc0c..4fc007210 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -3370,7 +3370,6 @@ entity_t *CL_NewTempEntity (void) ent->playerindex = -1; ent->topcolour = TOP_DEFAULT; ent->bottomcolour = BOTTOM_DEFAULT; - ent->h2playerclass = 0; #ifdef PEXT_SCALE ent->scale = 1; diff --git a/engine/client/client.h b/engine/client/client.h index b4b4c2f3c..d497f9f3a 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -175,7 +175,9 @@ typedef struct player_info_s struct model_s *model; // unsigned short vweapindex; +#ifdef HEXEN2 unsigned char h2playerclass; +#endif int prevcount; @@ -724,14 +726,14 @@ typedef struct // information that is static for the entire time connected to a server // char model_name_vwep[MAX_VWEP_MODELS][MAX_QPATH]; - char model_name[MAX_MODELS][MAX_QPATH]; - char sound_name[MAX_SOUNDS][MAX_QPATH]; + char model_name[MAX_PRECACHE_MODELS][MAX_QPATH]; + char sound_name[MAX_PRECACHE_SOUNDS][MAX_QPATH]; char *particle_ssname[MAX_SSPARTICLESPRE]; char image_name[Q2MAX_IMAGES][MAX_QPATH]; struct model_s *model_precache_vwep[MAX_VWEP_MODELS]; - struct model_s *model_precache[MAX_MODELS]; - struct sfx_s *sound_precache[MAX_SOUNDS]; + struct model_s *model_precache[MAX_PRECACHE_MODELS]; + struct sfx_s *sound_precache[MAX_PRECACHE_SOUNDS]; int particle_ssprecache[MAX_SSPARTICLESPRE]; //these are actually 1-based, so 0 can be used to lazy-init them. I cheat. char model_csqcname[MAX_CSMODELS][MAX_QPATH]; diff --git a/engine/client/m_items.c b/engine/client/m_items.c index a2ef2e643..b500d45f2 100644 --- a/engine/client/m_items.c +++ b/engine/client/m_items.c @@ -2034,15 +2034,16 @@ void M_Menu_Main_f (void) } else if (mgt == MGT_HEXEN2) { + p = R2D_SafeCachePic("gfx/menu/title0.lmp"); + if (!p) + return; + m_state = m_complex; Key_Dest_Add(kdm_menu); mainm = M_CreateMenu(0); mainm->key = MC_Main_Key; MC_AddPicture(mainm, 16, 0, 35, 176, "gfx/menu/hplaque.lmp"); - p = R2D_SafeCachePic("gfx/menu/title0.lmp"); - if (!p) - return; MC_AddCenterPicture(mainm, 0, 60, "gfx/menu/title0.lmp"); #ifndef CLIENTONLY diff --git a/engine/client/m_single.c b/engine/client/m_single.c index 125957996..5b4092522 100644 --- a/engine/client/m_single.c +++ b/engine/client/m_single.c @@ -3,7 +3,7 @@ #include "quakedef.h" #include "winquake.h" #include "shader.h" -#ifndef NOBUITINMENUS +#ifndef NOBUILTINMENUS #ifndef CLIENTONLY //============================================================================= /* LOAD/SAVE MENU */ diff --git a/engine/client/menu.c b/engine/client/menu.c index f84a028e3..a89567472 100644 --- a/engine/client/menu.c +++ b/engine/client/menu.c @@ -185,7 +185,7 @@ void M_PrintWhite (int cx, int cy, qbyte *str) void M_BuildTranslationTable(int top, int bottom, unsigned int *translationTable) { int j; - +#ifdef HEXEN2 int pc = Cvar_Get("cl_playerclass", "1", 0, "Hexen2")->value; if (h2playertranslations && pc) { @@ -207,6 +207,7 @@ void M_BuildTranslationTable(int top, int bottom, unsigned int *translationTable } } else +#endif { for(j=0;j<255;j++) { diff --git a/engine/client/p_script.c b/engine/client/p_script.c index 29c564de0..52384f96a 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -3739,7 +3739,7 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, VectorSubtract(org, t2, tangent); VectorAdd(org, t2, t2); - if (cl.worldmodel && cl.worldmodel->funcs.NativeTrace (cl.worldmodel, 0, 0, NULL, tangent, t2, vec3_origin, vec3_origin, MASK_WORLDSOLID, &tr)) + if (cl.worldmodel && cl.worldmodel->funcs.NativeTrace (cl.worldmodel, 0, 0, NULL, tangent, t2, vec3_origin, vec3_origin, false, MASK_WORLDSOLID, &tr)) { if (tr.fraction < dist) { diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 4849300e3..671197050 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -575,7 +575,7 @@ static model_t *CSQC_GetModelForIndex(int index) { if (index == 0) return NULL; - else if (index > 0 && index < MAX_MODELS) + else if (index > 0 && index < MAX_PRECACHE_MODELS) return cl.model_precache[index]; else if (index < 0 && index > -MAX_CSMODELS) { @@ -1899,7 +1899,7 @@ static int FindModel(const char *name, int *free) if (!strcmp(cl.model_csqcname[i], name)) return -i; } - for (i = 1; i < MAX_MODELS; i++) + for (i = 1; i < MAX_PRECACHE_MODELS; i++) { if (!strcmp(cl.model_name[i], name)) return i; @@ -1923,7 +1923,7 @@ static void csqc_setmodel(pubprogfuncs_t *prinst, csqcedict_t *ent, int modelind } else { - if (modelindex >= MAX_MODELS) + if (modelindex >= MAX_PRECACHE_MODELS) return; ent->v->model = PR_SetString(prinst, cl.model_name[modelindex]); model = cl.model_precache[modelindex]; @@ -1981,7 +1981,7 @@ static void QCBUILTIN PF_cs_PrecacheModel(pubprogfuncs_t *prinst, struct globalv return; } - for (i = 1; i < MAX_MODELS; i++) //Make sure that the server specified model is loaded.. + for (i = 1; i < MAX_PRECACHE_MODELS; i++) //Make sure that the server specified model is loaded.. { if (!*cl.model_name[i]) break; @@ -2531,6 +2531,7 @@ static void QCBUILTIN PF_cs_runplayerphysics (pubprogfuncs_t *prinst, struct glo pmove.cmd.upmove = csqcg.input_movevalues[2]; pmove.cmd.buttons = *csqcg.input_buttons; pmove.safeorigin_known = false; + pmove.capsule = false; //FIXME if (ent) { @@ -3853,8 +3854,8 @@ void CSQC_PlayerStateToCSQC(int pnum, player_state_t *srcp, csqcedict_t *ent) // ent->v->effects = srcp->effects; } -unsigned int deltaflags[MAX_MODELS]; -func_t deltafunction[MAX_MODELS]; +unsigned int deltaflags[MAX_PRECACHE_MODELS]; +func_t deltafunction[MAX_PRECACHE_MODELS]; typedef struct { @@ -3878,7 +3879,7 @@ qboolean CSQC_DeltaPlayer(int playernum, player_state_t *state) { func_t func; - if (!state || state->modelindex <= 0 || state->modelindex >= MAX_MODELS) + if (!state || state->modelindex <= 0 || state->modelindex >= MAX_PRECACHE_MODELS) { if (csqcdelta_playerents[playernum]) { @@ -4045,7 +4046,7 @@ static void QCBUILTIN PF_DeltaListen(pubprogfuncs_t *prinst, struct globalvars_s if (!strcmp(mname, "*")) { //yes, even things that are not allocated yet - for (i = 0; i < MAX_MODELS; i++) + for (i = 0; i < MAX_PRECACHE_MODELS; i++) { deltafunction[i] = func; deltaflags[i] = flags; @@ -4053,7 +4054,7 @@ static void QCBUILTIN PF_DeltaListen(pubprogfuncs_t *prinst, struct globalvars_s } else { - for (i = 1; i < MAX_MODELS; i++) + for (i = 1; i < MAX_PRECACHE_MODELS; i++) { if (!*cl.model_name[i]) break; @@ -5491,8 +5492,6 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks csqcentsize = PR_InitEnts(csqcprogs, pr_csqc_maxedicts.value); - ED_Alloc(csqcprogs); //we need a world entity. - //world edict becomes readonly worldent = (csqcedict_t *)EDICT_NUM(csqcprogs, 0); worldent->isfree = false; diff --git a/engine/client/r_part.c b/engine/client/r_part.c index 2005aad2c..694bca4d0 100644 --- a/engine/client/r_part.c +++ b/engine/client/r_part.c @@ -227,10 +227,10 @@ qboolean TraceLineN (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal) { AngleVectors(pe->angles, axis[0], axis[1], axis[2]); VectorNegate(axis[1], axis[1]); - pe->model->funcs.NativeTrace(pe->model, 0, 0, axis, ts, te, vec3_origin, vec3_origin, MASK_WORLDSOLID, &trace); + pe->model->funcs.NativeTrace(pe->model, 0, 0, axis, ts, te, vec3_origin, vec3_origin, false, MASK_WORLDSOLID, &trace); } else - pe->model->funcs.NativeTrace(pe->model, 0, 0, NULL, ts, te, vec3_origin, vec3_origin, MASK_WORLDSOLID, &trace); + pe->model->funcs.NativeTrace(pe->model, 0, 0, NULL, ts, te, vec3_origin, vec3_origin, false, MASK_WORLDSOLID, &trace); if (trace.fraction<1) { VectorSubtract(trace.endpos, ts, delta); diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 9fa9b8f1f..b9c325579 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -2224,12 +2224,12 @@ void Surf_GenBrushBatches(batch_t **batches, entity_t *ent) bef = BEF_PUSHDEPTH; if (ent->flags & RF_ADDITIVE) bef |= BEF_FORCEADDITIVE; - else if (ent->drawflags & DRF_TRANSLUCENT && r_wateralpha.value != 1) + else if ((ent->drawflags & DRF_TRANSLUCENT) && r_wateralpha.value != 1) { bef |= BEF_FORCETRANSPARENT; ent->shaderRGBAf[3] = r_wateralpha.value; } - else if (ent->flags & RF_TRANSLUCENT && cls.protocol != CP_QUAKE3) + else if ((ent->flags & RF_TRANSLUCENT) && cls.protocol != CP_QUAKE3) bef |= BEF_FORCETRANSPARENT; if (ent->flags & RF_NODEPTHTEST) bef |= BEF_FORCENODEPTH; @@ -2827,7 +2827,7 @@ void Surf_BuildLightmaps (void) r_oldviewcluster2 = -1; numlightmaps = 0; - for (j=1 ; jnumsubmodels)) sv.models[i] = Mod_FindName(sv.strings.model_precache[i]); @@ -1211,7 +1213,7 @@ TRACE(("dbg: R_ApplyRenderer: clearing world\n")); #ifdef Q2SERVER else if (svs.gametype == GT_QUAKE2) { - for (i = 0; i < MAX_MODELS; i++) + for (i = 0; i < MAX_PRECACHE_MODELS; i++) { if (sv.strings.configstring[Q2CS_MODELS+i] && *sv.strings.configstring[Q2CS_MODELS+i] && (!strcmp(sv.strings.configstring[Q2CS_MODELS+i] + strlen(sv.strings.configstring[Q2CS_MODELS+i]) - 4, ".bsp") || i-1 < sv.world.worldmodel->numsubmodels)) sv.models[i] = Mod_FindName(sv.strings.configstring[Q2CS_MODELS+i]); @@ -1276,7 +1278,7 @@ TRACE(("dbg: R_ApplyRenderer: starting on client state\n")); //FIXME: this code should not be here. call CL_LoadModels instead? that does csqc loading etc though. :s TRACE(("dbg: R_ApplyRenderer: reloading ALL models\n")); - for (i=1 ; iwidth < 13) sbar_hexen2 = true; +#endif sb_nums[0][10] = Sbar_PicFromWad ("num_minus"); sb_nums[1][10] = Sbar_PicFromWad ("anum_minus"); @@ -2065,6 +2069,7 @@ void Sbar_DrawScoreboard (void) } +#ifdef HEXEN2 static void Sbar_Hexen2DrawActiveStuff(playerview_t *pv) { int x = r_refdef.grect.x + r_refdef.grect.width; @@ -2368,7 +2373,7 @@ static void Sbar_Hexen2DrawMinimal(playerview_t *pv) Sbar_Hexen2DrawNum(38, y+18, pv->stats[STAT_HEALTH], 3); } - +#endif static void Sbar_DrawTeamStatus(playerview_t *pv) { @@ -2593,7 +2598,7 @@ void Sbar_Draw (playerview_t *pv) sb_updates++; - +#ifdef HEXEN2 if (sbar_hexen2) { //hexen2 hud @@ -2611,7 +2616,9 @@ void Sbar_Draw (playerview_t *pv) Sbar_Hexen2DrawActiveStuff(pv); } - else if (sbarfailed) //files failed to load. + else +#endif + if (sbarfailed) //files failed to load. { //fallback hud if (pv->stats[STAT_HEALTH] > 0) //when dead, show nothing diff --git a/engine/client/skin.c b/engine/client/skin.c index 0e2ea742b..0bafd5d82 100644 --- a/engine/client/skin.c +++ b/engine/client/skin.c @@ -467,15 +467,19 @@ void Skin_NextDownload (void) { *slash = 0; CL_CheckOrEnqueDownloadFile(va("players/%s/tris.md2", skinname), NULL, 0); - for (j = 0; j < MAX_MODELS; j++) + for (j = 1; j < MAX_PRECACHE_MODELS; j++) { if (cl.model_name[j][0] == '#') CL_CheckOrEnqueDownloadFile(va("players/%s/%s", skinname, cl.model_name[j]+1), NULL, 0); + if (!*cl.model_name[j]) + break; } - for (j = 0; j < MAX_SOUNDS; j++) + for (j = 1; j < MAX_PRECACHE_SOUNDS; j++) { if (cl.sound_name[j][0] == '*') CL_CheckOrEnqueDownloadFile(va("players/%s/%s", skinname, cl.sound_name[j]+1), NULL, 0); + if (!*cl.sound_name[j]) + break; } *slash = '/'; CL_CheckOrEnqueDownloadFile(va("players/%s.pcx", skinname), NULL, 0); diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 36421e618..c1d670dce 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -1758,7 +1758,7 @@ void S_DoRestart (void) S_StopAllSounds (true); - for (i=1 ; igravitydir, camorg); -// if (cl.worldmodel && cl.worldmodel->funcs.NativeTrace(cl.worldmodel, 0, 0, NULL, r_refdef.vieworg, camorg, vec3_origin, vec3_origin, MASK_WORLDSOLID, &tr)) - VectorCopy(camorg, r_refdef.vieworg); - - CL_EditExternalModels(0, NULL, 0); + VectorScale(axis[0], -chase_back.value, camdir); + VectorMA(camdir, -chase_up.value, pv->gravitydir, camdir); + len = VectorLength(camdir); + VectorMA(r_refdef.vieworg, (len+128)/len, camdir, camorg); //push it 128qu further + if (cl.worldmodel && cl.worldmodel->funcs.NativeTrace) + { + cl.worldmodel->funcs.NativeTrace(cl.worldmodel, 0, 0, NULL, r_refdef.vieworg, camorg, vec3_origin, vec3_origin, true, MASK_WORLDSOLID, &tr); + if (!tr.startsolid) + { + float extralen; + if (tr.fraction < 1) + { + //we found a plane, bisect it weirdly to push 4qu infront + float d1,d2, frac; + VectorMA(r_refdef.vieworg, 1, camdir, camorg); + d1 = DotProduct(r_refdef.vieworg, tr.plane.normal) - (tr.plane.dist+4); + d2 = DotProduct(camorg, tr.plane.normal) - (tr.plane.dist+4); + frac = d1 / (d1-d2); + frac = bound(0, frac, 1); + VectorMA(r_refdef.vieworg, frac, camdir, r_refdef.vieworg); + } + else + VectorMA(r_refdef.vieworg, 1, camdir, r_refdef.vieworg); + } + } } } @@ -1775,7 +1798,7 @@ void V_Init (void) Cvar_Register (&v_contrast, VIEWVARS); Cvar_Register (&v_brightness, VIEWVARS); -// Cvar_Register (&chase_active, VIEWVARS); -// Cvar_Register (&chase_back, VIEWVARS); -// Cvar_Register (&chase_up, VIEWVARS); + Cvar_Register (&chase_active, VIEWVARS); + Cvar_Register (&chase_back, VIEWVARS); + Cvar_Register (&chase_up, VIEWVARS); } diff --git a/engine/client/zqtp.c b/engine/client/zqtp.c index 6aa06dc46..54d5b5224 100644 --- a/engine/client/zqtp.c +++ b/engine/client/zqtp.c @@ -2479,7 +2479,7 @@ static item_t tp_items[] = { #define NUMITEMS (sizeof(tp_items) / sizeof(tp_items[0])) -static item_t *model2item[MAX_MODELS]; +static item_t *model2item[MAX_PRECACHE_MODELS]; static void TP_FindModelNumbers (void) { @@ -2487,7 +2487,7 @@ static void TP_FindModelNumbers (void) char *s; item_t *item; - for (i=0 ; ishader = shader; + t->numidx = 0; + t->numvert = 0; + t->firstidx = cl_numstrisidx; + t->firstvert = cl_numstrisvert; + t->flags = flags; + } + if (cl_numstrisvert + bonecount*2 > cl_maxstrisvert) + { + cl_maxstrisvert = cl_numstrisvert + bonecount*2; + + cl_strisvertv = BZ_Realloc(cl_strisvertv, sizeof(*cl_strisvertv)*cl_maxstrisvert); + cl_strisvertt = BZ_Realloc(cl_strisvertt, sizeof(vec2_t)*cl_maxstrisvert); + cl_strisvertc = BZ_Realloc(cl_strisvertc, sizeof(vec4_t)*cl_maxstrisvert); + } + if (cl_maxstrisidx < cl_numstrisidx+bonecount*2) + { + cl_maxstrisidx = cl_numstrisidx+bonecount*2; + cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx); + } + + first = cl_numstrisvert-t->firstvert; + for (i = 0; i < bonecount; i++) + { + //fixme: transform by model matrix + cl_strisvertv[cl_numstrisvert][0] = bonepose[i*12+3]; + cl_strisvertv[cl_numstrisvert][1] = bonepose[i*12+7]; + cl_strisvertv[cl_numstrisvert][2] = bonepose[i*12+11]; + cl_strisvertt[cl_numstrisvert][0] = 0; + cl_strisvertt[cl_numstrisvert][1] = 0; + cl_strisvertc[cl_numstrisvert][0] = (i < basebone)?0:1; + cl_strisvertc[cl_numstrisvert][1] = (i < basebone)?0:0; + cl_strisvertc[cl_numstrisvert][2] = (i < basebone)?1:0; + cl_strisvertc[cl_numstrisvert][3] = 1; + cl_numstrisvert++; + + p = bones[i].parent; + if (p < 0) + p = 0; + cl_strisidx[cl_numstrisidx++] = first+i; + cl_strisidx[cl_numstrisidx++] = first+p; + } + + t->numvert += bonecount; + t->numidx = cl_numstrisidx - t->firstidx; +#else PPL_RevertToKnownState(); BE_SelectEntity(currententity); qglColor3f(1, 0, 0); @@ -1529,8 +1591,8 @@ static void Alias_GLDrawSkeletalBones(galiasbone_t *bones, float *bonepose, int */ // mesh->numindexes = 0; //don't draw this mesh, as that would obscure the bones. :( } +#endif } -#endif //GLQUAKE #endif //!SERVERONLY #endif //SKELETALMODELS @@ -1723,7 +1785,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in meshcache.usebonepose = Alias_GetBoneInformation(inf, &e->framestate, meshcache.bonecachetype=SKEL_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, MAX_BONES); if (qrenderer == QR_OPENGL) { - Alias_GLDrawSkeletalBones(inf->ofsbones, (float *)meshcache.usebonepose, inf->numbones, e->framestate.g[0].endbone); + Alias_DrawSkeletalBones(inf->ofsbones, (float *)meshcache.usebonepose, inf->numbones, e->framestate.g[0].endbone); } #endif } @@ -2042,7 +2104,7 @@ qboolean Mod_Trace_Trisoup(vecV_t *posedata, index_t *indexes, int numindexes, v } //The whole reason why model loading is supported in the server. -qboolean Mod_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int contentsmask, trace_t *trace) +qboolean Mod_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contentsmask, trace_t *trace) { galiasinfo_t *mod = Mod_Extradata(model); galiasgroup_t *group; @@ -2592,6 +2654,7 @@ extern float r_avertexnormals[NUMVERTEXNORMALS][3]; static void Alias_LoadPose(vecV_t *verts, vec3_t *normals, vec3_t *svec, vec3_t *tvec, dtrivertx_t *pinframe, int *seamremaps, int mdltype) { int j; +#ifdef HEXEN2 if (mdltype == 2) { for (j = 0; j < galias->numverts; j++) @@ -2605,6 +2668,7 @@ static void Alias_LoadPose(vecV_t *verts, vec3_t *normals, vec3_t *svec, vec3_t } } else +#endif { for (j = 0; j < pq1inmodel->numverts; j++) { @@ -3062,7 +3126,6 @@ qboolean QDECL Mod_LoadQ1Model (model_t *mod, void *buffer, size_t fsize) int i, onseams; dstvert_t *pinstverts; dtriangle_t *pinq1triangles; - dh2triangle_t *pinh2triangles; int *seamremap; index_t *indexes; daliasskintype_t *skinstart; @@ -3072,7 +3135,10 @@ qboolean QDECL Mod_LoadQ1Model (model_t *mod, void *buffer, size_t fsize) unsigned int hdrsize; void *end; qboolean qtest = false; +#ifdef HEXEN2 + dh2triangle_t *pinh2triangles; qboolean rapo = false; +#endif loadmodel=mod; @@ -3088,11 +3154,13 @@ qboolean QDECL Mod_LoadQ1Model (model_t *mod, void *buffer, size_t fsize) hdrsize = (size_t)&((dmdl_t*)NULL)->flags; qtest = true; } +#ifdef HEXEN2 else if (version == 50) { hdrsize = sizeof(dmdl_t); rapo = true; } +#endif else if (version != ALIAS_VERSION) { Con_Printf (CON_ERROR "%s has wrong version number (%i should be %i)\n", @@ -3162,6 +3230,7 @@ qboolean QDECL Mod_LoadQ1Model (model_t *mod, void *buffer, size_t fsize) break; } +#ifdef HEXEN2 if (rapo) { /*each triangle can use one coord and one st, for each vert, that's a lot of combinations*/ @@ -3248,6 +3317,7 @@ qboolean QDECL Mod_LoadQ1Model (model_t *mod, void *buffer, size_t fsize) BZ_Free(seamremap); } else +#endif { /*onseam means +=skinwidth/2 verticies that are marked as onseam potentially generate two output verticies. @@ -7206,7 +7276,9 @@ qboolean QDECL Mod_LoadCompositeAnim(model_t *mod, void *buffer, size_t fsize) void Alias_Register(void) { Mod_RegisterModelFormatMagic(NULL, "Quake1 Model (mdl)", IDPOLYHEADER, Mod_LoadQ1Model); +#ifdef HEXEN2 Mod_RegisterModelFormatMagic(NULL, "Hexen2 Model (mdl)", RAPOLYHEADER, Mod_LoadQ1Model); +#endif #ifdef MD2MODELS Mod_RegisterModelFormatMagic(NULL, "Quake2 Model (md2)", MD2IDALIASHEADER, Mod_LoadQ2Model); #endif diff --git a/engine/common/common.c b/engine/common/common.c index 260cea3d5..1c97131af 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -96,25 +96,7 @@ cvar_t com_modname = CVARD("com_modname", "", "dpmaster information"); cvar_t com_parseutf8 = CVARD("com_parseutf8", "0", "Interpret console messages/playernames/etc as UTF-8. Requires special fonts. -1=iso 8859-1. 0=quakeascii(chat uses high chars). 1=utf8, revert to ascii on decode errors. 2=utf8 ignoring errors"); //1 parse. 2 parse, but stop parsing that string if a char was malformed. cvar_t com_highlightcolor = CVARD("com_highlightcolor", STRINGIFY(COLOR_RED), "ANSI colour to be used for highlighted text, used when com_parseutf8 is active."); cvar_t com_nogamedirnativecode = CVARFD("com_nogamedirnativecode", "1", CVAR_NOTFROMSERVER, FULLENGINENAME" blocks all downloads of files with a .dll or .so extension, however other engines (eg: ezquake and fodquake) do not - this omission can be used to trigger remote exploits in any engine (including "FULLENGINENAME"which is later run from the same gamedir.\nQuake2, Quake3(when debugging), and KTX typically run native gamecode from within gamedirs, so if you wish to run any of these games you will need to ensure this cvar is changed to 0, as well as ensure that you don't run unsafe clients.\n"); -#ifdef FTE_TARGET_WEB -cvar_t sys_platform = CVAR("sys_platform", "web"); -#elif defined(NACL) -cvar_t sys_platform = CVAR("sys_platform", "nacl"); -#elif defined(ANDROID) -cvar_t sys_platform = CVAR("sys_platform", "android"); -#elif defined(FTE_SDL) -cvar_t sys_platform = CVAR("sys_platform", "sdl"); -#elif defined(_WIN64) -cvar_t sys_platform = CVAR("sys_platform", "win64"); -#elif defined(_WIN32) -cvar_t sys_platform = CVAR("sys_platform", "win32"); -#elif defined(__linux__) -cvar_t sys_platform = CVAR("sys_platform", "linux"); -#elif defined(__APPLE__) -cvar_t sys_platform = CVAR("sys_platform", "mac"); -#else -cvar_t sys_platform = CVAR("sys_platform", ""); -#endif +cvar_t sys_platform = CVAR("sys_platform", PLATFORM); qboolean com_modified; // set true if using non-id files diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 1ba4699a4..7c3178349 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -54,7 +54,7 @@ qboolean Mod_LoadSurfedges (lump_t *l); void Mod_LoadLighting (lump_t *l); -static qboolean CM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int contents, trace_t *trace); +static qboolean CM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace); static unsigned int CM_NativeContents(struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs); static unsigned int Q2BSP_PointContents(model_t *mod, vec3_t axis[3], vec3_t p); static int CM_PointCluster (model_t *mod, vec3_t p); @@ -180,7 +180,12 @@ qbyte *ReadPCXPalette(qbyte *buf, int len, qbyte *out); extern model_t *loadmodel; extern qbyte *mod_base; - +#define capsuledist(dist,plane,mins,maxs) \ + case shape_iscapsule: \ + dist = DotProduct(trace_up, plane->normal); \ + dist = dist*(trace_capsulesize[(dist<0)?1:2]) - trace_capsulesize[0]; \ + dist = plane->dist - dist; \ + break; unsigned char d_q28to24table[1024]; @@ -4796,12 +4801,19 @@ static vec3_t trace_start, trace_end; static vec3_t trace_mins, trace_maxs; static vec3_t trace_extents; static vec3_t trace_absmins, trace_absmaxs; +static vec3_t trace_up; //capsule points upwards in this direction +static vec3_t trace_capsulesize; //radius, up, down static float trace_truefraction; static float trace_nearfraction; static trace_t trace_trace; static int trace_contents; -static qboolean trace_ispoint; // optimized case +static enum +{ + shape_isbox, + shape_iscapsule, + shape_ispoint +} trace_shape; // optimized case /* ================ @@ -4838,11 +4850,10 @@ static void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, side = brush->brushside+i; plane = side->plane; - // FIXME: special case for axial - - if (!trace_ispoint) - { // general box case - + switch(trace_shape) + { + default: + case shape_isbox: // general box case // push the plane out apropriately for mins/maxs // FIXME: use signbits into 8 way lookup for each mins/maxs @@ -4855,10 +4866,11 @@ static void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, } dist = DotProduct (ofs, plane->normal); dist = plane->dist - dist; - } - else - { // special point case + break; + capsuledist(dist,plane,mins,maxs) + case shape_ispoint: // special point case dist = plane->dist; + break; } d1 = DotProduct (p1, plane->normal) - dist; @@ -4953,12 +4965,13 @@ static void CM_ClipBoxToPlanes (vec3_t trmins, vec3_t trmaxs, vec3_t p1, vec3_t for (i=0 ; inormal); dist = plane->dist - dist; - } - else - { // special point case + break; + capsuledist(dist,plane,trmins,trmaxs) + case shape_ispoint: // special point case dist = plane->dist; + break; } d1 = DotProduct (p1, plane->normal) - dist; @@ -5187,11 +5201,11 @@ static void CM_ClipBoxToPatch (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, side = brush->brushside+i; plane = side->plane; - if (!trace_ispoint) - { // general box case - - // push the plane out apropriately for mins/maxs - + // push the plane out apropriately for mins/maxs + switch(trace_shape) + { + default: + case shape_isbox: // general box case // FIXME: use signbits into 8 way lookup for each mins/maxs for (j=0 ; j<3 ; j++) { @@ -5202,10 +5216,11 @@ static void CM_ClipBoxToPatch (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, } dist = DotProduct (ofs, plane->normal); dist = plane->dist - dist; - } - else - { // special point case + break; + capsuledist(dist,plane,mins,maxs) + case shape_ispoint: // special point case dist = plane->dist; + break; } d1 = DotProduct (p1, plane->normal) - dist; @@ -5290,22 +5305,29 @@ static void CM_TestBoxInBrush (vec3_t mins, vec3_t maxs, vec3_t p1, side = brush->brushside+i; plane = side->plane; - // FIXME: special case for axial - - // general box case - - // push the plane out apropriately for mins/maxs - - // FIXME: use signbits into 8 way lookup for each mins/maxs - for (j=0 ; j<3 ; j++) + switch(trace_shape) { - if (plane->normal[j] < 0) - ofs[j] = maxs[j]; - else - ofs[j] = mins[j]; + default: + case shape_isbox: // general box case + + // push the plane out apropriately for mins/maxs + + // FIXME: use signbits into 8 way lookup for each mins/maxs + for (j=0 ; j<3 ; j++) + { + if (plane->normal[j] < 0) + ofs[j] = maxs[j]; + else + ofs[j] = mins[j]; + } + dist = DotProduct (ofs, plane->normal); + dist = plane->dist - dist; + break; + capsuledist(dist,plane,mins,maxs) + case shape_ispoint: + dist = plane->dist; + break; } - dist = DotProduct (ofs, plane->normal); - dist = plane->dist - dist; d1 = DotProduct (p1, plane->normal) - dist; @@ -5339,21 +5361,31 @@ static void CM_TestBoxInPatch (vec3_t mins, vec3_t maxs, vec3_t p1, side = brush->brushside+i; plane = side->plane; - // general box case - - // push the plane out apropriately for mins/maxs - - // FIXME: use signbits into 8 way lookup for each mins/maxs - for (j=0 ; j<3 ; j++) + switch(trace_shape) { - if (plane->normal[j] < 0) - ofs[j] = maxs[j]; - else - ofs[j] = mins[j]; - } + default: + case shape_isbox: + // general box case - dist = DotProduct (ofs, plane->normal); - dist = plane->dist - dist; + // push the plane out apropriately for mins/maxs + + // FIXME: use signbits into 8 way lookup for each mins/maxs + for (j=0 ; j<3 ; j++) + { + if (plane->normal[j] < 0) + ofs[j] = maxs[j]; + else + ofs[j] = mins[j]; + } + + dist = DotProduct (ofs, plane->normal); + dist = plane->dist - dist; + break; + capsuledist(dist,plane,mins,maxs) + case shape_ispoint: + dist = plane->dist; + break; + } d1 = DotProduct (p1, plane->normal) - dist; @@ -5567,7 +5599,7 @@ static void CM_RecursiveHullCheck (model_t *mod, int num, float p1f, float p2f, { t1 = DotProduct (plane->normal, p1) - plane->dist; t2 = DotProduct (plane->normal, p2) - plane->dist; - if (trace_ispoint) + if (trace_shape == shape_ispoint) offset = 0; else offset = fabs(trace_extents[0]*plane->normal[0]) + @@ -5651,7 +5683,7 @@ CM_BoxTrace ================== */ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, - vec3_t mins, vec3_t maxs, + vec3_t mins, vec3_t maxs, qboolean capsule, int brushmask) { int i; @@ -5679,21 +5711,65 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, // build a bounding box of the entire move (for patches) ClearBounds (trace_absmins, trace_absmaxs); - VectorAdd (start, trace_mins, point); - AddPointToBounds (point, trace_absmins, trace_absmaxs); - VectorAdd (start, trace_maxs, point); - AddPointToBounds (point, trace_absmins, trace_absmaxs); - VectorAdd (end, trace_mins, point); - AddPointToBounds (point, trace_absmins, trace_absmaxs); - VectorAdd (end, trace_maxs, point); - AddPointToBounds (point, trace_absmins, trace_absmaxs); + //determine the type of trace that we're going to use, and the max extents + if (trace_mins[0] == 0 && trace_mins[1] == 0 && trace_mins[2] == 0 && trace_maxs[0] == 0 && trace_maxs[1] == 0 && trace_maxs[2] == 0) + { + trace_shape = shape_ispoint; + VectorSet (trace_extents, 1/32.0, 1/32.0, 1/32.0); + //acedemic + AddPointToBounds (start, trace_absmins, trace_absmaxs); + AddPointToBounds (end, trace_absmins, trace_absmaxs); + } + else if (capsule) + { + float ext; + trace_shape = shape_iscapsule; + //determine the capsule sizes + trace_capsulesize[0] = ((maxs[0]-mins[0]) + (maxs[1]-mins[1]))/4.0; + trace_capsulesize[1] = maxs[2]; + trace_capsulesize[2] = mins[2]; + ext = (trace_capsulesize[1] > -trace_capsulesize[2])?trace_capsulesize[1]:-trace_capsulesize[2]; + trace_capsulesize[1] -= trace_capsulesize[0]; + trace_capsulesize[2] += trace_capsulesize[0]; + trace_extents[0] = ext+1; + trace_extents[1] = ext+1; + trace_extents[2] = ext+1; + + //determine the total range + VectorSubtract (start, trace_extents, point); + AddPointToBounds (point, trace_absmins, trace_absmaxs); + VectorAdd (start, trace_extents, point); + AddPointToBounds (point, trace_absmins, trace_absmaxs); + VectorSubtract (end, trace_extents, point); + AddPointToBounds (point, trace_absmins, trace_absmaxs); + VectorAdd (end, trace_extents, point); + AddPointToBounds (point, trace_absmins, trace_absmaxs); + } + else + { + VectorAdd (start, trace_mins, point); + AddPointToBounds (point, trace_absmins, trace_absmaxs); + VectorAdd (start, trace_maxs, point); + AddPointToBounds (point, trace_absmins, trace_absmaxs); + VectorAdd (end, trace_mins, point); + AddPointToBounds (point, trace_absmins, trace_absmaxs); + VectorAdd (end, trace_maxs, point); + AddPointToBounds (point, trace_absmins, trace_absmaxs); + + trace_shape = shape_isbox; + trace_extents[0] = ((-trace_mins[0] > trace_maxs[0]) ? -trace_mins[0] : trace_maxs[0])+1; + trace_extents[1] = ((-trace_mins[1] > trace_maxs[1]) ? -trace_mins[1] : trace_maxs[1])+1; + trace_extents[2] = ((-trace_mins[2] > trace_maxs[2]) ? -trace_mins[2] : trace_maxs[2])+1; + } + +#if 0 if (0) { //treat *ALL* tests against the actual geometry instead of using any brushes. //also ignores the bsp etc. not fast. testing only. trace_ispoint = trace_mins[0] == 0 && trace_mins[1] == 0 && trace_mins[2] == 0 - && trace_maxs[0] == 0 && trace_maxs[1] == 0 && trace_maxs[2] == 0; + && trace_maxs[0] == 0 && trace_maxs[1] == 0 && trace_maxs[2] == 0; for (i = 0; i < mod->numsurfaces; i++) { @@ -5703,13 +5779,14 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, else if (0) { - trace_ispoint = trace_mins[0] == 0 && trace_mins[1] == 0 && trace_mins[2] == 0 - && trace_maxs[0] == 0 && trace_maxs[1] == 0 && trace_maxs[2] == 0; + trace_ispoint = trace_mins[0] == 0 && trace_mins[1] == 0 && trace_mins[2] == 0 + && trace_maxs[0] == 0 && trace_maxs[1] == 0 && trace_maxs[2] == 0; for (i = 0; i < mod->numleafs; i++) CM_TraceToLeaf(&mod->leafs[i]); } else +#endif // // check for position test special case // @@ -5739,24 +5816,10 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, return trace_trace; } // - // check for point special case - // - else if (trace_mins[0] == 0 && trace_mins[1] == 0 && trace_mins[2] == 0 - && trace_maxs[0] == 0 && trace_maxs[1] == 0 && trace_maxs[2] == 0) - { - trace_ispoint = true; - VectorClear (trace_extents); - CM_RecursiveHullCheck (mod, mod->hulls[0].firstclipnode, 0, 1, trace_start, trace_end); - } - // // general aabb trace // else { - trace_ispoint = false; - trace_extents[0] = ((-trace_mins[0] > trace_maxs[0]) ? -trace_mins[0] : trace_maxs[0])+1; - trace_extents[1] = ((-trace_mins[1] > trace_maxs[1]) ? -trace_mins[1] : trace_maxs[1])+1; - trace_extents[2] = ((-trace_mins[2] > trace_maxs[2]) ? -trace_mins[2] : trace_maxs[2])+1; CM_RecursiveHullCheck (mod, mod->hulls[0].firstclipnode, 0, 1, trace_start, trace_end); } @@ -5776,7 +5839,7 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, return trace_trace; } -static qboolean CM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int contents, trace_t *trace) +static qboolean CM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace) { if (axis) { @@ -5788,12 +5851,13 @@ static qboolean CM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3 end_l[0] = DotProduct(end, axis[0]); end_l[1] = DotProduct(end, axis[1]); end_l[2] = DotProduct(end, axis[2]); - *trace = CM_BoxTrace(model, start_l, end_l, mins, maxs, contents); + VectorSet(trace_up, axis[0][2], -axis[1][2], axis[2][2]); + *trace = CM_BoxTrace(model, start_l, end_l, mins, maxs, capsule, contents); #ifdef TERRAIN if (model->terrain) { trace_t hmt; - Heightmap_Trace(model, forcehullnum, frame, NULL, start, end, mins, maxs, contents, &hmt); + Heightmap_Trace(model, forcehullnum, frame, NULL, start, end, mins, maxs, capsule, contents, &hmt); if (hmt.fraction < trace->fraction) *trace = hmt; } @@ -5819,12 +5883,13 @@ static qboolean CM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3 } else { - *trace = CM_BoxTrace(model, start, end, mins, maxs, contents); + VectorSet(trace_up, 0, 0, 1); + *trace = CM_BoxTrace(model, start, end, mins, maxs, capsule, contents); #ifdef TERRAIN if (model->terrain) { trace_t hmt; - Heightmap_Trace(model, forcehullnum, frame, NULL, start, end, mins, maxs, contents, &hmt); + Heightmap_Trace(model, forcehullnum, frame, NULL, start, end, mins, maxs, capsule, contents, &hmt); if (hmt.fraction < trace->fraction) *trace = hmt; } @@ -5860,6 +5925,7 @@ trace_t CM_TransformedBoxTrace (model_t *mod, vec3_t start, vec3_t end, vec3_t forward, right, up; vec3_t temp; qboolean rotated; + qboolean capsule = false; // subtract origin offset VectorSubtract (start, origin, start_l); @@ -5885,10 +5951,16 @@ trace_t CM_TransformedBoxTrace (model_t *mod, vec3_t start, vec3_t end, end_l[0] = DotProduct (temp, forward); end_l[1] = -DotProduct (temp, right); end_l[2] = DotProduct (temp, up); + + VectorSet(trace_up, forward[2], -right[2], up[2]); + } + else + { + VectorSet(trace_up, 0, 0, 1); } // sweep the box through the model - trace = CM_BoxTrace (mod, start_l, end_l, mins, maxs, brushmask); + trace = CM_BoxTrace (mod, start_l, end_l, mins, maxs, capsule, brushmask); if (rotated && trace.fraction != 1.0) { diff --git a/engine/common/pmove.c b/engine/common/pmove.c index 76904dc62..1fb2e1f24 100644 --- a/engine/common/pmove.c +++ b/engine/common/pmove.c @@ -921,7 +921,7 @@ void PM_CategorizePosition (void) VectorMA (pmove.origin, 24, flatforward, fwd1); - pmove.physents[0].model->funcs.NativeTrace(pmove.physents[0].model, 0, 0, NULL, pmove.origin, fwd1, pmove.player_mins, pmove.player_maxs, MASK_PLAYERSOLID, &t); + pmove.physents[0].model->funcs.NativeTrace(pmove.physents[0].model, 0, 0, NULL, pmove.origin, fwd1, pmove.player_mins, pmove.player_maxs, pmove.capsule, MASK_PLAYERSOLID, &t); if (t.surface && t.surface->flags & Q3SURF_LADDER) { pmove.onladder = true; diff --git a/engine/common/pmove.h b/engine/common/pmove.h index 0eeb257ea..63c9ca501 100644 --- a/engine/common/pmove.h +++ b/engine/common/pmove.h @@ -67,6 +67,7 @@ typedef struct int pm_type; vec3_t player_mins; vec3_t player_maxs; + qboolean capsule; // world state int numphysent; diff --git a/engine/common/pmovetst.c b/engine/common/pmovetst.c index 193a4858c..f4863517c 100644 --- a/engine/common/pmovetst.c +++ b/engine/common/pmovetst.c @@ -226,7 +226,7 @@ static qboolean PM_TransformedHullCheck (model_t *model, vec3_t start, vec3_t en { AngleVectors (angles, axis[0], axis[1], axis[2]); VectorNegate(axis[1], axis[1]); - model->funcs.NativeTrace(model, 0, 0, axis, start_l, end_l, player_mins, player_maxs, MASK_PLAYERSOLID, trace); + model->funcs.NativeTrace(model, 0, 0, axis, start_l, end_l, player_mins, player_maxs, pmove.capsule, MASK_PLAYERSOLID, trace); } else { @@ -237,7 +237,7 @@ static qboolean PM_TransformedHullCheck (model_t *model, vec3_t start, vec3_t en if (start_l[i]+player_maxs[i] < model->mins[i] && end_l[i] + player_maxs[i] < model->mins[i]) return false; } - model->funcs.NativeTrace(model, 0, 0, NULL, start_l, end_l, player_mins, player_maxs, MASK_PLAYERSOLID, trace); + model->funcs.NativeTrace(model, 0, 0, NULL, start_l, end_l, player_mins, player_maxs, pmove.capsule, MASK_PLAYERSOLID, trace); } } else diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 6a3e2845d..808f0feff 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -3911,11 +3911,7 @@ void QCBUILTIN PF_argescape(pubprogfuncs_t *prinst, struct globalvars_s *pr_glob void QCBUILTIN PF_random (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - float num; - - num = (rand ()&0x7fff) / ((float)0x8000); - - G_FLOAT(OFS_RETURN) = num; + G_FLOAT(OFS_RETURN) = (rand ()&0x7fff) / ((float)0x8000); } //float(float number, float quantity) bitshift = #218; @@ -4284,15 +4280,14 @@ void QCBUILTIN PF_vectoyaw (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob //float(vector) vlen void QCBUILTIN PF_vlen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - float *value1; - float newv; - - value1 = G_VECTOR(OFS_PARM0); - - newv = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2]; - newv = sqrt(newv); - - G_FLOAT(OFS_RETURN) = newv; + float *value1 = G_VECTOR(OFS_PARM0); + G_FLOAT(OFS_RETURN) = sqrt(DotProduct(value1, value1)); +} +//float(vector) vhlen +void QCBUILTIN PF_vhlen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + float *value1 = G_VECTOR(OFS_PARM0); + G_FLOAT(OFS_RETURN) = sqrt(DotProduct2(value1, value1)); } //vector vectoangles(vector) diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index 37866754e..84a23173a 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -144,6 +144,7 @@ void QCBUILTIN PF_fputs (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals void QCBUILTIN PF_fgets (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_normalize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_vlen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_vhlen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_changeyaw (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_changepitch (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_vectoyaw (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); @@ -435,8 +436,8 @@ void PR_Common_Shutdown(pubprogfuncs_t *progs, qboolean errored); /*these are server ones, provided by pr_cmds.c, as required by pr_q1qvm.c*/ #ifdef VM_Q1 +void PR_SV_FillWorldGlobals(world_t *w); model_t *SVPR_GetCModel(world_t *w, int modelindex); -void SVPR_Event_Touch(world_t *w, wedict_t *s, wedict_t *o); void QCBUILTIN PF_WriteByte (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_WriteChar (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_WriteShort (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index 0ffdc0ec4..7580c008f 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -2,7 +2,6 @@ #include "pr_common.h" -qboolean Heightmap_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int contentmask, trace_t *trace); /* ============================================================================ @@ -840,7 +839,7 @@ hull_t *Q1BSP_ChooseHull(model_t *model, int forcehullnum, vec3_t mins, vec3_t m VectorSubtract (hull->clip_mins, mins, offset); return hull; } -qboolean Q1BSP_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int hitcontentsmask, trace_t *trace) +qboolean Q1BSP_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int hitcontentsmask, trace_t *trace) { hull_t *hull; vec3_t start_l, end_l; @@ -942,7 +941,7 @@ qboolean Q1BSP_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3] if (model->terrain && trace->fraction) { trace_t hmt; - Heightmap_Trace(model, forcehullnum, frame, axis, start, end, mins, maxs, hitcontentsmask, &hmt); + Heightmap_Trace(model, forcehullnum, frame, axis, start, end, mins, maxs, capsule, hitcontentsmask, &hmt); if (hmt.fraction < trace->fraction) *trace = hmt; } diff --git a/engine/common/translate.c b/engine/common/translate.c index 9fbde357d..8e0cd0beb 100644 --- a/engine/common/translate.c +++ b/engine/common/translate.c @@ -147,7 +147,7 @@ void TL_InitLanguages(void) -//#ifndef CLIENTONLY +#ifdef HEXEN2 //this stuff is for hexen2 translation strings. //(hexen2 is uuuuggllyyyy...) static char *strings_list; @@ -213,7 +213,6 @@ char *T_GetString(int num) return strings_table[num]; } -//#endif #ifndef SERVERONLY //for hexen2's objectives and stuff. @@ -281,6 +280,7 @@ char *T_GetInfoString(int num) return info_strings_table[num]; } #endif +#endif struct poline_s { diff --git a/engine/common/world.h b/engine/common/world.h index d29216b68..e39339174 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -248,6 +248,8 @@ int World_PointContents (world_t *w, vec3_t p); wedict_t *World_TestEntityPosition (world_t *w, wedict_t *ent); +qboolean World_TransformedTrace (struct model_s *model, int hulloverride, int frame, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, struct trace_s *trace, vec3_t origin, vec3_t angles, unsigned int hitcontentsmask); + /* World_Move: mins and maxs are reletive diff --git a/engine/d3d/d3d11_backend.c b/engine/d3d/d3d11_backend.c index 6d9f9da5d..45b29a177 100644 --- a/engine/d3d/d3d11_backend.c +++ b/engine/d3d/d3d11_backend.c @@ -2743,6 +2743,7 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod) if (e->scale != 1 && e->scale != 0) //hexen 2 stuff { +#ifdef HEXEN2 float z; float escale; escale = e->scale; @@ -2778,6 +2779,11 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod) break; } } +#else + VectorScale((m+0), e->scale, (m+0)); + VectorScale((m+4), e->scale, (m+4)); + VectorScale((m+8), e->scale, (m+8)); +#endif } else if (mod && !strcmp(mod->name, "progs/eyes.mdl")) { diff --git a/engine/d3d/d3d_backend.c b/engine/d3d/d3d_backend.c index 018e84e9d..a616d8102 100644 --- a/engine/d3d/d3d_backend.c +++ b/engine/d3d/d3d_backend.c @@ -2614,6 +2614,7 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod) if (e->scale != 1 && e->scale != 0) //hexen 2 stuff { +#ifdef HEXEN2 float z; float escale; escale = e->scale; @@ -2649,6 +2650,11 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod) break; } } +#else + VectorScale((m+0), e->scale, (m+0)); + VectorScale((m+4), e->scale, (m+4)); + VectorScale((m+8), e->scale, (m+8)); +#endif } else if (mod && !strcmp(mod->name, "progs/eyes.mdl")) { diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index dbb433f23..e43ac5e88 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -601,7 +601,11 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e } tc = e->topcolour; bc = e->bottomcolour; +#ifdef HEXEN2 pc = e->h2playerclass; +#else + pc = 0; +#endif if (forced || tc != TOP_DEFAULT || bc != BOTTOM_DEFAULT || plskin) { @@ -690,7 +694,7 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e Hash_Add(&skincolourmapped, cm->name, cm, &cm->bucket); cm->tcolour = tc; cm->bcolour = bc; - cm->pclass = pc; + cm->pclass = pc; //is this needed? surely it'll be baked as part of the modelname? cm->skinnum = e->skinnum; cm->subframe = subframe; cm->texnum.fullbright = r_nulltex; @@ -828,6 +832,7 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e if (scaled_height < 4) scaled_height = 4; +#ifdef HEXEN2 if (h2playertranslations && pc) { unsigned int color_offsets[5] = {2*14*256,0,1*14*256,2*14*256,2*14*256}; @@ -847,6 +852,7 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e translate32[0] = 0; } else +#endif { for (i=0 ; i<256 ; i++) translate32[i] = d_8to24rgbtable[i]; diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index a8d6fdbc3..615044b42 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -3200,6 +3200,7 @@ typedef struct { vec4_t plane; vec3_t mins; vec3_t maxs; + qboolean capsule; float frac; float htilesize; heightmap_t *hm; @@ -3357,7 +3358,7 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty) //do the trace memset(&etr, 0, sizeof(etr)); etr.fraction = 1; - model->funcs.NativeTrace (model, 0, frame, s->ents[i]->ent.axis, start_l, end_l, tr->mins, tr->maxs, tr->hitcontentsmask, &etr); + model->funcs.NativeTrace (model, 0, frame, s->ents[i]->ent.axis, start_l, end_l, tr->mins, tr->maxs, tr->capsule, tr->hitcontentsmask, &etr); tr->result->startsolid |= etr.startsolid; tr->result->allsolid |= etr.allsolid; @@ -3528,7 +3529,7 @@ Why is recursion good? Obviously, we don't care all that much about 1 */ -qboolean Heightmap_Trace(struct model_s *model, int hulloverride, int frame, vec3_t mataxis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int against, struct trace_s *trace) +qboolean Heightmap_Trace(struct model_s *model, int hulloverride, int frame, vec3_t mataxis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace) { vec2_t pos, npos; qboolean nudge[2]; @@ -3551,6 +3552,7 @@ qboolean Heightmap_Trace(struct model_s *model, int hulloverride, int frame, vec hmtrace.plane[1] = 0; hmtrace.plane[2] = 0; hmtrace.plane[3] = 0; + hmtrace.capsule = capsule; memset(trace, 0, sizeof(*trace)); trace->fraction = 1; diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index 27812a661..fc780835b 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -205,7 +205,7 @@ typedef struct { unsigned int (*BoxContents) (struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs); //deals with whatever is native for the bsp (gamecode is expected to distinguish this). - qboolean (*NativeTrace) (struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, unsigned int against, struct trace_s *trace); + qboolean (*NativeTrace) (struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace); unsigned int (*NativeContents)(struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs); unsigned int (*FatPVS) (struct model_s *model, vec3_t org, qbyte *pvsbuffer, unsigned int buffersize, qboolean merge); @@ -499,7 +499,6 @@ int Q1BSP_ClipDecal(vec3_t center, vec3_t normal, vec3_t tangent1, vec3_t tangen void Q1BSP_MarkLights (dlight_t *light, int bit, mnode_t *node); void GLQ1BSP_LightPointValues(struct model_s *model, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); -qboolean Q1BSP_Trace(struct model_s *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int hitcontentsmask, struct trace_s *trace); qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, struct trace_s *trace); qbyte *Q1BSP_LeafPVS (struct model_s *model, mleaf_t *leaf, qbyte *buffer, unsigned int buffersize); @@ -976,7 +975,7 @@ void Terr_FreeModel(model_t *mod); void Terr_PurgeTerrainModel(model_t *hm, qboolean lightmapsonly, qboolean lightmapreusable); void *Mod_LoadTerrainInfo(model_t *mod, char *loadname, qboolean force); //call this after loading a bsp qboolean Terrain_LocateSection(char *name, flocation_t *loc); //used on servers to generate sections for download. -qboolean Heightmap_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int contentmask, struct trace_s *trace); +qboolean Heightmap_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contentmask, struct trace_s *trace); unsigned int Heightmap_PointContents(model_t *model, vec3_t axis[3], vec3_t org); struct fragmentdecal_s; void Terrain_ClipDecal(struct fragmentdecal_s *dec, float *center, float radius, model_t *model); diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 93738a366..430ead4bf 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -312,6 +312,7 @@ void R_RotateForEntity (float *m, float *modelview, const entity_t *e, const mod if (e->scale != 1 && e->scale != 0) //hexen 2 stuff { +#ifdef HEXEN2 float z; float escale; escale = e->scale; @@ -347,6 +348,11 @@ void R_RotateForEntity (float *m, float *modelview, const entity_t *e, const mod break; } } +#else + VectorScale((m+0), e->scale, (m+0)); + VectorScale((m+4), e->scale, (m+4)); + VectorScale((m+8), e->scale, (m+8)); +#endif } else if (mod && !strcmp(mod->name, "progs/eyes.mdl")) { diff --git a/engine/gl/ltface.c b/engine/gl/ltface.c index bec77d9d7..45f9637ad 100644 --- a/engine/gl/ltface.c +++ b/engine/gl/ltface.c @@ -61,7 +61,7 @@ vec_t CastRay (vec3_t p1, vec3_t p2) trace_t trace; vec3_t move; - lightmodel->funcs.NativeTrace (lightmodel, 0, 0, NULL, p1, p2, vec3_origin, vec3_origin, FTECONTENTS_SOLID, &trace); + lightmodel->funcs.NativeTrace (lightmodel, 0, 0, NULL, p1, p2, vec3_origin, vec3_origin, false, FTECONTENTS_SOLID, &trace); if (trace.fraction < 1) return -1; diff --git a/engine/qclib/execloop.h b/engine/qclib/execloop.h index ac8fce802..a2fcc309d 100644 --- a/engine/qclib/execloop.h +++ b/engine/qclib/execloop.h @@ -18,7 +18,6 @@ #define fakeop fakeop16 #define dstatement_t dstatement16_t #define sofs signed short -#define uofs unsigned short #elif INTSIZE == 32 #define cont cont32 #define reeval reeval32 @@ -26,7 +25,6 @@ #define fakeop fakeop32 #define dstatement_t dstatement32_t #define sofs signed int -#define uofs unsigned int #elif INTSIZE == 24 #error INTSIZE should be set to 32. #else @@ -397,109 +395,6 @@ reeval: *(unsigned char *)ptr = (char)OPA->_float; break; - case OP_MULSTORE_F: // f *= f - OPB->_float *= OPA->_float; - break; - case OP_MULSTORE_VF: // v *= f - tmpf = OPA->_float; - OPB->_vector[0] *= tmpf; - OPB->_vector[1] *= tmpf; - OPB->_vector[2] *= tmpf; - break; - case OP_MULSTOREP_F: // e.f *= f - if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) - { - pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); - } - ptr = QCPOINTER(OPB); - OPC->_float = (ptr->_float *= OPA->_float); - break; - case OP_MULSTOREP_VF: // e.v *= f - if (QCPOINTERWRITEFAIL(OPB, sizeof(vec3_t))) - { - pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); - } - tmpf = OPA->_float; - ptr = QCPOINTER(OPB); - OPC->_vector[0] = (ptr->_vector[0] *= tmpf); - OPC->_vector[1] = (ptr->_vector[1] *= tmpf); - OPC->_vector[2] = (ptr->_vector[2] *= tmpf); - break; - - case OP_DIVSTORE_F: // f /= f - OPB->_float /= OPA->_float; - break; - case OP_DIVSTOREP_F: // e.f /= f - if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) - { - pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); - } - ptr = QCPOINTER(OPB); - OPC->_float = (ptr->_float /= OPA->_float); - break; - - case OP_ADDSTORE_F: // f += f - OPB->_float += OPA->_float; - break; - case OP_ADDSTORE_V: // v += v - OPB->_vector[0] += OPA->_vector[0]; - OPB->_vector[1] += OPA->_vector[1]; - OPB->_vector[2] += OPA->_vector[2]; - break; - case OP_ADDSTOREP_F: // e.f += f - if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) - { - pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); - } - ptr = QCPOINTER(OPB); - OPC->_float = (ptr->_float += OPA->_float); - break; - case OP_ADDSTOREP_V: // e.v += v - if (QCPOINTERWRITEFAIL(OPB, sizeof(vec3_t))) - { - pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); - } - ptr = QCPOINTER(OPB); - OPC->_vector[0] = (ptr->_vector[0] += OPA->_vector[0]); - OPC->_vector[1] = (ptr->_vector[1] += OPA->_vector[1]); - OPC->_vector[2] = (ptr->_vector[2] += OPA->_vector[2]); - break; - - case OP_SUBSTORE_F: // f -= f - OPB->_float -= OPA->_float; - break; - case OP_SUBSTORE_V: // v -= v - OPB->_vector[0] -= OPA->_vector[0]; - OPB->_vector[1] -= OPA->_vector[1]; - OPB->_vector[2] -= OPA->_vector[2]; - break; - case OP_SUBSTOREP_F: // e.f -= f - if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) - { - pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); - } - ptr = QCPOINTER(OPB); - OPC->_float = (ptr->_float -= OPA->_float); - break; - case OP_SUBSTOREP_V: // e.v -= v - if (QCPOINTERWRITEFAIL(OPB, sizeof(vec3_t))) - { - pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); - } - ptr = QCPOINTER(OPB); - OPC->_vector[0] = (ptr->_vector[0] -= OPA->_vector[0]); - OPC->_vector[1] = (ptr->_vector[1] -= OPA->_vector[1]); - OPC->_vector[2] = (ptr->_vector[2] -= OPA->_vector[2]); - break; - - //get a pointer to a field var case OP_ADDRESS: if ((unsigned)OPA->edict >= (unsigned)sv_num_edicts) @@ -941,30 +836,31 @@ reeval: OPC->_int = OPA->_int << OPB->_int; break; - + //hexen2 arrays contain a prefix global set to (arraysize-1) inserted before the actual array data + //for vectors, this prefix is the number of vectors rather than the number of globals. this can cause issues with using OP_FETCH_GBL_V within structs. case OP_FETCH_GBL_F: case OP_FETCH_GBL_S: case OP_FETCH_GBL_E: case OP_FETCH_GBL_FNC: - i = (int)OPB->_float; - if(i < 0 || i > ((eval_t *)&glob[st->a-1])->_int) + i = OPB->_float; + if((unsigned)i > (unsigned)((eval_t *)&glob[st->a-1])->_int) { + pr_xstatement = st-pr_statements; PR_RunError(&progfuncs->funcs, "array index out of bounds: %s[%d] (max %d)", PR_GlobalStringNoContents(progfuncs, st->a), i, ((eval_t *)&glob[st->a-1])->_int); } - t = (eval_t *)&glob[(uofs)st->a + i]; - OPC->_int = t->_int; + OPC->_int = ((eval_t *)&glob[st->a + i])->_int; break; case OP_FETCH_GBL_V: - i = (int)OPB->_float; - if(i < 0 || i > ((eval_t *)&glob[st->a-1])->_int) + i = OPB->_float; + if((unsigned)i > (unsigned)((eval_t *)&glob[st->a-1])->_int) { pr_xstatement = st-pr_statements; PR_RunError(&progfuncs->funcs, "array index out of bounds: %s[%d]", PR_GlobalStringNoContents(progfuncs, st->a), i); } - t = (eval_t *)&glob[(uofs)st->a + i*3]; - OPC->_vector[0] = t->_vector[0]; - OPC->_vector[1] = t->_vector[1]; - OPC->_vector[2] = t->_vector[2]; + ptr = (eval_t *)&glob[st->a + i*3]; + OPC->_vector[0] = ptr->_vector[0]; + OPC->_vector[1] = ptr->_vector[1]; + OPC->_vector[2] = ptr->_vector[2]; break; case OP_CSTATE: @@ -979,143 +875,184 @@ reeval: externs->thinktimeop(&progfuncs->funcs, (struct edict_s *)PROG_TO_EDICT(progfuncs, OPA->edict), OPB->_float); break; - - case OP_BITSETSTORE_F: // b (+) a - OPB->_float = (float)((int)OPB->_float | (int)OPA->_float); + case OP_MULSTORE_F: + /*OPC->_float = */OPB->_float *= OPA->_float; break; - case OP_BITSETSTOREP_F: // .b (+) a + case OP_MULSTORE_VF: + tmpf = OPA->_float; //don't break on vec*=vec_x; + /*OPC->_vector[0] = */OPB->_vector[0] *= tmpf; + /*OPC->_vector[1] = */OPB->_vector[1] *= tmpf; + /*OPC->_vector[2] = */OPB->_vector[2] *= tmpf; + break; + case OP_MULSTOREP_F: if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) { pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); } ptr = QCPOINTER(OPB); - ptr->_float = (float)((int)ptr->_float | (int)OPA->_float); + OPC->_float = ptr->_float *= OPA->_float; break; - case OP_BITCLRSTORE_F: // b (-) a - OPB->_float = (float)((int)OPB->_float & ~((int)OPA->_float)); - break; - case OP_BITCLRSTOREP_F: // .b (-) a + case OP_MULSTOREP_VF: if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) { pr_xstatement = st-pr_statements; - PR_RunError (&progfuncs->funcs, "bad pointer write in %s", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name)); + PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); } ptr = QCPOINTER(OPB); - ptr->_float = (float)((int)ptr->_float & ~((int)OPA->_float)); + tmpf = OPA->_float; //don't break on vec*=vec_x; + OPC->_vector[0] = ptr->_vector[0] *= tmpf; + OPC->_vector[1] = ptr->_vector[1] *= tmpf; + OPC->_vector[2] = ptr->_vector[2] *= tmpf; + break; + case OP_DIVSTORE_F: + /*OPC->_float = */OPB->_float /= OPA->_float; + break; + case OP_DIVSTOREP_F: + if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) + { + pr_xstatement = st-pr_statements; + PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); + } + ptr = QCPOINTER(OPB); + OPC->_float = ptr->_float /= OPA->_float; + break; + case OP_ADDSTORE_F: + /*OPC->_float = */OPB->_float += OPA->_float; + break; + case OP_ADDSTORE_V: + /*OPC->_vector[0] =*/ OPB->_vector[0] += OPA->_vector[0]; + /*OPC->_vector[1] =*/ OPB->_vector[1] += OPA->_vector[1]; + /*OPC->_vector[2] =*/ OPB->_vector[2] += OPA->_vector[2]; + break; + case OP_ADDSTOREP_F: + if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) + { + pr_xstatement = st-pr_statements; + PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); + } + ptr = QCPOINTER(OPB); + OPC->_float = ptr->_float += OPA->_float; + break; + case OP_ADDSTOREP_V: + if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) + { + pr_xstatement = st-pr_statements; + PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); + } + ptr = QCPOINTER(OPB); + OPC->_vector[0] = ptr->_vector[0] += OPA->_vector[0]; + OPC->_vector[1] = ptr->_vector[1] += OPA->_vector[1]; + OPC->_vector[2] = ptr->_vector[2] += OPA->_vector[2]; + break; + case OP_SUBSTORE_F: + /*OPC->_float = */OPB->_float -= OPA->_float; + break; + case OP_SUBSTORE_V: + /*OPC->_vector[0] = */OPB->_vector[0] -= OPA->_vector[0]; + /*OPC->_vector[1] = */OPB->_vector[1] -= OPA->_vector[1]; + /*OPC->_vector[2] = */OPB->_vector[2] -= OPA->_vector[2]; + break; + case OP_SUBSTOREP_F: + if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) + { + pr_xstatement = st-pr_statements; + PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); + } + ptr = QCPOINTER(OPB); + OPC->_float = ptr->_float -= OPA->_float; + break; + case OP_SUBSTOREP_V: + if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) + { + pr_xstatement = st-pr_statements; + PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); + } + ptr = QCPOINTER(OPB); + OPC->_vector[0] = ptr->_vector[0] -= OPA->_vector[0]; + OPC->_vector[1] = ptr->_vector[1] -= OPA->_vector[1]; + OPC->_vector[2] = ptr->_vector[2] -= OPA->_vector[2]; + break; + case OP_BITSETSTORE_F: + OPB->_float = (int)OPB->_float | (int)OPA->_float; + break; + case OP_BITSETSTOREP_F: + if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) + { + pr_xstatement = st-pr_statements; + PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); + } + ptr = QCPOINTER(OPB); + ptr->_float = (int)ptr->_float | (int)OPA->_float; + break; + case OP_BITCLRSTORE_F: + OPB->_float = (int)OPB->_float & ~(int)OPA->_float; + break; + case OP_BITCLRSTOREP_F: + if (QCPOINTERWRITEFAIL(OPB, sizeof(float))) + { + pr_xstatement = st-pr_statements; + PR_RunError (&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), OPB->_int, prinst.addressableused); + } + ptr = QCPOINTER(OPB); + ptr->_float = (int)ptr->_float & ~(int)OPA->_float; break; + //for scaler randoms, prevent the random value from ever reaching 1 + //this avoids issues when array[random()*array.length] case OP_RAND0: - OPC->_float = (rand()&0x7fff)/((float)0x7fff); + OPC->_float = (rand ()&0x7fff) / ((float)0x8000); break; case OP_RAND1: - OPC->_float = (rand()&0x7fff)/((float)0x7fff)*OPA->_float; + OPC->_float = (rand ()&0x7fff) / ((float)0x8000)*OPA->_float; break; - case OP_RAND2: - if(OPA->_float < OPB->_float) - { - OPC->_float = OPA->_float+((rand()&0x7fff)/((float)0x7fff) - *(OPB->_float-OPA->_float)); - } - else - { - OPC->_float = OPB->_float+((rand()&0x7fff)/((float)0x7fff) - *(OPA->_float-OPB->_float)); - } + case OP_RAND2: //backwards range shouldn't matter (except that it is b that is never reached, rather than the higher of the two) + OPC->_float = OPA->_float + (rand ()&0x7fff) / ((float)0x8000)*(OPB->_float-OPA->_float); break; + //random vectors DO result in 0 to 1 inclusive, to try to ensure a more balanced range case OP_RANDV0: - OPC->_vector[0] = (rand()&0x7fff)/((float)0x7fff); - OPC->_vector[1] = (rand()&0x7fff)/((float)0x7fff); - OPC->_vector[2] = (rand()&0x7fff)/((float)0x7fff); + OPC->_vector[0] = (rand ()&0x7fff) / ((float)0x7fff); + OPC->_vector[1] = (rand ()&0x7fff) / ((float)0x7fff); + OPC->_vector[2] = (rand ()&0x7fff) / ((float)0x7fff); break; case OP_RANDV1: - OPC->_vector[0] = (rand()&0x7fff)/((float)0x7fff)*OPA->_vector[0]; - OPC->_vector[1] = (rand()&0x7fff)/((float)0x7fff)*OPA->_vector[1]; - OPC->_vector[2] = (rand()&0x7fff)/((float)0x7fff)*OPA->_vector[2]; + OPC->_vector[0] = (rand ()&0x7fff) / ((float)0x7fff)*OPA->_vector[0]; + OPC->_vector[1] = (rand ()&0x7fff) / ((float)0x7fff)*OPA->_vector[1]; + OPC->_vector[2] = (rand ()&0x7fff) / ((float)0x7fff)*OPA->_vector[2]; break; - case OP_RANDV2: - for(i = 0; i < 3; i++) - { - if(OPA->_vector[i] < OPB->_vector[i]) - { - OPC->_vector[i] = OPA->_vector[i]+((rand()&0x7fff)/((float)0x7fff) - *(OPB->_vector[i]-OPA->_vector[i])); - } - else - { - OPC->_vector[i] = OPB->_vector[i]+(rand()*(1.0f/RAND_MAX) - *(OPA->_vector[i]-OPB->_vector[i])); - } - } + case OP_RANDV2: //backwards range shouldn't matter + OPC->_vector[0] = OPA->_vector[0] + (rand ()&0x7fff) / ((float)0x7fff)*(OPB->_vector[0]-OPA->_vector[0]); + OPC->_vector[1] = OPA->_vector[1] + (rand ()&0x7fff) / ((float)0x7fff)*(OPB->_vector[1]-OPA->_vector[1]); + OPC->_vector[2] = OPA->_vector[2] + (rand ()&0x7fff) / ((float)0x7fff)*(OPB->_vector[2]-OPA->_vector[2]); break; - case OP_SWITCH_F: case OP_SWITCH_V: case OP_SWITCH_S: case OP_SWITCH_E: case OP_SWITCH_FNC: - swtch = OPA; - swtchtype = OPCODE; + //the case opcodes depend upon the preceding switch. + //otherwise the switch itself is much like a goto + //don't embed the case/caserange checks directly into the switch so that custom caseranges can be potentially be implemented with hybrid emulation. + switchcomparison = OPCODE - OP_SWITCH_F; + switchref = OPA; RUNAWAYCHECK(); - st += (sofs)st->b - 1; // offset the st++ + st += (sofs)st->b - 1; // offset the s++ break; case OP_CASE: - switch(swtchtype) + //if the comparison is true, jump (back up) to the relevent code block + if (casecmp[switchcomparison](progfuncs, switchref, OPA)) { - case OP_SWITCH_F: - if (swtch->_float == OPA->_float) - { - RUNAWAYCHECK(); - st += (sofs)st->b-1; // -1 to offset the s++ - } - break; - case OP_SWITCH_E: - case OP_SWITCH_FNC: - if (swtch->_int == OPA->_int) - { - RUNAWAYCHECK(); - st += (sofs)st->b-1; // -1 to offset the s++ - } - break; - case OP_SWITCH_S: - if (swtch->_int == OPA->_int) - { - RUNAWAYCHECK(); - st += (sofs)st->b-1; // -1 to offset the s++ - } - if ((!swtch->_int && PR_StringToNative(&progfuncs->funcs, OPA->string)) || (!OPA->_int && PR_StringToNative(&progfuncs->funcs, swtch->string))) //one is null (cannot be not both). - break; - if (!strcmp(PR_StringToNative(&progfuncs->funcs, swtch->string), PR_StringToNative(&progfuncs->funcs, OPA->string))) - { - RUNAWAYCHECK(); - st += (sofs)st->b-1; // -1 to offset the s++ - } - break; - case OP_SWITCH_V: - if (swtch->_vector[0] == OPA->_vector[0] && swtch->_vector[1] == OPA->_vector[1] && swtch->_vector[2] == OPA->_vector[2]) - { - RUNAWAYCHECK(); - st += (sofs)st->b-1; // -1 to offset the s++ - } - break; - default: - PR_RunError (&progfuncs->funcs, "OP_CASE with bad/missing OP_SWITCH %i", swtchtype); - break; + RUNAWAYCHECK(); + st += (sofs)st->b-1; // -1 to offset the s++ } break; case OP_CASERANGE: - switch(swtchtype) + //if the comparison is true, jump (back up) to the relevent code block + if (casecmprange[switchcomparison](progfuncs, switchref, OPA, OPC)) { - case OP_SWITCH_F: - if (swtch->_float >= OPA->_float && swtch->_float <= OPB->_float) - { - RUNAWAYCHECK(); - st += (sofs)st->c-1; // -1 to offset the s++ - } - break; - default: - PR_RunError (&progfuncs->funcs, "OP_CASERANGE with bad/missing OP_SWITCH %i", swtchtype); + RUNAWAYCHECK(); + st += (sofs)st->c-1; // -1 to offset the s++ } break; @@ -1126,7 +1063,6 @@ reeval: - case OP_BITAND_IF: OPC->_int = (OPA->_int & (int)OPB->_float); break; @@ -1316,7 +1252,6 @@ reeval: #undef fakeop #undef dstatement_t #undef sofs -#undef uofs #undef OPCODE #undef ENGINEPOINTER diff --git a/engine/qclib/pr_exec.c b/engine/qclib/pr_exec.c index ac5ec9e14..b1693c0d9 100644 --- a/engine/qclib/pr_exec.c +++ b/engine/qclib/pr_exec.c @@ -755,7 +755,7 @@ pbool LocateDebugTerm(progfuncs_t *progfuncs, char *key, eval_t **result, etype_ ed = PROG_TO_EDICT(progfuncs, val->_int); if (!ed) return false; - if (fofs < 0 || fofs >= max_fields_size) + if (fofs < 0 || fofs >= (int)max_fields_size) return false; val = (eval_t *) (((char *)ed->fields) + fofs*4); } @@ -1240,6 +1240,41 @@ static char *lastfile = 0; return statement; } +static pbool casecmp_f(progfuncs_t *progfuncs, eval_t *ref, eval_t *val) {return ref->_float == val->_float;} +static pbool casecmp_i(progfuncs_t *progfuncs, eval_t *ref, eval_t *val) {return ref->_int == val->_int;} +static pbool casecmp_v(progfuncs_t *progfuncs, eval_t *ref, eval_t *val) {return ref->_vector[0] == val->_vector[0] && + ref->_vector[1] == val->_vector[1] && + ref->_vector[2] == val->_vector[2];} +static pbool casecmp_s(progfuncs_t *progfuncs, eval_t *ref, eval_t *val) { const char *refs = PR_StringToNative(&progfuncs->funcs, ref->string); + const char *vals = PR_StringToNative(&progfuncs->funcs, val->string); + return !strcmp(refs, vals);} +static pbool casecmprange_f(progfuncs_t *progfuncs, eval_t *ref, eval_t *min, eval_t *max) {return ref->_float >= min->_float && ref->_float <= max->_float;} +static pbool casecmprange_i(progfuncs_t *progfuncs, eval_t *ref, eval_t *min, eval_t *max) {return ref->_int >= min->_int && ref->_int <= max->_int;} +static pbool casecmprange_v(progfuncs_t *progfuncs, eval_t *ref, eval_t *min, eval_t *max) {return ref->_vector[0] >= min->_vector[0] && ref->_vector[0] <= max->_vector[0] && + ref->_vector[1] >= min->_vector[1] && ref->_vector[1] <= max->_vector[1] && + ref->_vector[2] >= min->_vector[2] && ref->_vector[2] <= max->_vector[2];} +static pbool casecmprange_bad(progfuncs_t *progfuncs, eval_t *ref, eval_t *min, eval_t *max){ PR_RunError (&progfuncs->funcs, "OP_CASERANGE type not supported");//BUG: pr_xstatement will not be correct. + return false;} +typedef pbool (*casecmp_t)(progfuncs_t *progfuncs, eval_t *ref, eval_t *val); +typedef pbool (*casecmprange_t)(progfuncs_t *progfuncs, eval_t *ref, eval_t *min, eval_t *max); +static casecmp_t casecmp[] = +{ + casecmp_f, //float + casecmp_v, //vector + casecmp_s, //string + casecmp_i, //ent + casecmp_i //func + //pointer, field, int, etc are emulated with func or something. I dunno +}; +static casecmprange_t casecmprange[] = +{ + casecmprange_f, //float + casecmprange_v, //vector - I'm using a bbox, not really sure what it should be + casecmprange_bad, //string - should it use stof? string ranges don't relly make sense, at all. + casecmprange_i, //ent - doesn't really make sense, but as ints/pointers/fields/etc might be emulated with this, allow it anyway, as an int type. + casecmprange_i //func +}; + #define RUNAWAYCHECK() \ if (!--*runaway) \ { \ @@ -1255,9 +1290,7 @@ static char *lastfile = 0; static int PR_ExecuteCode16 (progfuncs_t *fte_restrict progfuncs, int s, int *fte_restrict runaway) { - eval_t *t, *swtch=NULL; - - int swtchtype = 0; //warning about not being initialized before use + unsigned int switchcomparison = 0; const dstatement16_t *fte_restrict st; mfunction_t *fte_restrict newf; int i; @@ -1268,6 +1301,8 @@ static int PR_ExecuteCode16 (progfuncs_t *fte_restrict progfuncs, int s, int *ft float tmpf; int tmpi; + eval_t *switchref = (eval_t*)glob; + #define OPA ((eval_t *)&glob[st->a]) #define OPB ((eval_t *)&glob[st->b]) #define OPC ((eval_t *)&glob[st->c]) @@ -1312,9 +1347,7 @@ static int PR_ExecuteCode32 (progfuncs_t *fte_restrict progfuncs, int s, int *ft return -1; #else - eval_t *t, *swtch=NULL; - - int swtchtype = 0; //warning about not being initialized before use + unsigned int switchcomparison = 0; const dstatement32_t *fte_restrict st; mfunction_t *fte_restrict newf; int i; @@ -1324,6 +1357,7 @@ static int PR_ExecuteCode32 (progfuncs_t *fte_restrict progfuncs, int s, int *ft float *fte_restrict glob = pr_globals; float tmpf; int tmpi; + eval_t *switchref = (eval_t*)glob; #define OPA ((eval_t *)&glob[st->a]) #define OPB ((eval_t *)&glob[st->b]) diff --git a/engine/server/net_preparse.c b/engine/server/net_preparse.c index 2010014a3..c1410b6d8 100644 --- a/engine/server/net_preparse.c +++ b/engine/server/net_preparse.c @@ -662,17 +662,19 @@ void NPP_NQFlush(void) { if (cl->state == cs_spawned && ISQWCLIENT(cl)) { +#ifdef HEXEN2 char *h2finale = NULL; char *h2title = NULL; +/* if (cl->zquake_extensions & Z_EXT_SERVERTIME) { -/* ClientReliableCheckBlock(cl, 6); + ClientReliableCheckBlock(cl, 6); ClientReliableWrite_Byte(cl, svc_updatestatlong); ClientReliableWrite_Byte(cl, STAT_TIME); ClientReliableWrite_Long(cl, (int)(sv.world.physicstime * 1000)); cl->nextservertimeupdate = sv.world.physicstime+10; -*/ } - + } +*/ if (progstype == PROG_H2) { /*hexen2 does something like this in the client, but we don't support those protocols, so translate to something usable*/ @@ -699,6 +701,7 @@ void NPP_NQFlush(void) ClientReliableWrite_String(cl, h2finale); } else +#endif { ClientReliableCheckBlock(cl, 16); ClientReliableWrite_Byte(cl, svc_intermission); diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 3937eaa4e..2c4d4c322 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -274,7 +274,7 @@ pbool PDECL ED_CanFree (edict_t *ed) return true; } -void ASMCALL StateOp (pubprogfuncs_t *prinst, float var, func_t func) +static void ASMCALL StateOp (pubprogfuncs_t *prinst, float var, func_t func) { stdentvars_t *vars = PROG_TO_EDICT(prinst, pr_global_struct->self)->v; if (progstype == PROG_H2) @@ -284,87 +284,98 @@ void ASMCALL StateOp (pubprogfuncs_t *prinst, float var, func_t func) vars->think = func; vars->frame = var; } -void ASMCALL CStateOp (pubprogfuncs_t *prinst, float startFrame, float endFrame, func_t currentfunc) +#ifdef HEXEN2 +static void ASMCALL CStateOp (pubprogfuncs_t *prinst, float first, float last, func_t currentfunc) { - stdentvars_t *vars = PROG_TO_EDICT(prinst, pr_global_struct->self)->v; + float min, max; + float step; + wedict_t *e = PROG_TO_WEDICT(prinst, pr_global_struct->self); + float frame = e->v->frame; + + if (progstype == PROG_H2) + e->v->nextthink = pr_global_struct->time+0.05; + else + e->v->nextthink = pr_global_struct->time+0.1; + e->v->think = currentfunc; - vars->nextthink = pr_global_struct->time+0.05; - vars->think = currentfunc; pr_global_struct->cycle_wrapped = false; - if(startFrame <= endFrame) - { // Increment - if(vars->frame < startFrame || vars->frame > endFrame) - { - vars->frame = startFrame; - return; - } - vars->frame++; - if(vars->frame > endFrame) - { + if (first > last) + { //going backwards + min = last; + max = first; + step = -1.0; + } + else + { //forwards + min = first; + max = last; + step = 1.0; + } + if (frame < min || frame > max) + frame = first; //started out of range, must have been a different animation + else + { + frame += step; + if (frame < min || frame > max) + { //became out of range, must have wrapped pr_global_struct->cycle_wrapped = true; - vars->frame = startFrame; + frame = first; } - return; - } - // Decrement - if(vars->frame > startFrame || vars->frame < endFrame) - { - vars->frame = startFrame; - return; - } - vars->frame--; - if(vars->frame < endFrame) - { - pr_global_struct->cycle_wrapped = true; - vars->frame = startFrame; } + e->v->frame = frame; } -void ASMCALL CWStateOp (pubprogfuncs_t *prinst, float startFrame, float endFrame, func_t currentfunc) +static void ASMCALL CWStateOp (pubprogfuncs_t *prinst, float first, float last, func_t currentfunc) { - stdentvars_t *vars = PROG_TO_EDICT(prinst, pr_global_struct->self)->v; + float min, max; + float step; + wedict_t *e = PROG_TO_WEDICT(prinst, pr_global_struct->self); + float frame = e->v->weaponframe; + + if (progstype == PROG_H2) + e->v->nextthink = pr_global_struct->time+0.05; + else + e->v->nextthink = pr_global_struct->time+0.1; + e->v->think = currentfunc; - vars->nextthink = pr_global_struct->time+0.05; - vars->think = currentfunc; pr_global_struct->cycle_wrapped = false; - if(startFrame <= endFrame) - { // Increment - if(vars->weaponframe < startFrame || vars->weaponframe > endFrame) - { - vars->weaponframe = startFrame; - return; - } - vars->weaponframe++; - if(vars->weaponframe > endFrame) - { + if (first > last) + { //going backwards + min = last; + max = first; + step = -1.0; + } + else + { //forwards + min = first; + max = last; + step = 1.0; + } + if (frame < min || frame > max) + frame = first; //started out of range, must have been a different animation + else + { + frame += step; + if (frame < min || frame > max) + { //became out of range, must have wrapped pr_global_struct->cycle_wrapped = true; - vars->weaponframe = startFrame; + frame = first; } - return; - } - // Decrement - if(vars->weaponframe > startFrame || vars->weaponframe < endFrame) - { - vars->weaponframe = startFrame; - return; - } - vars->weaponframe--; - if(vars->weaponframe < endFrame) - { - pr_global_struct->cycle_wrapped = true; - vars->weaponframe = startFrame; } + e->v->weaponframe = frame; } -void ASMCALL ThinkTimeOp (pubprogfuncs_t *prinst, edict_t *ed, float var) +static void ASMCALL ThinkTimeOp (pubprogfuncs_t *prinst, edict_t *ed, float var) { stdentvars_t *vars = ed->v; vars->nextthink = pr_global_struct->time+var; } +#endif -pbool PDECL SV_BadField(pubprogfuncs_t *inst, edict_t *foo, const char *keyname, const char *value) +static pbool PDECL SV_BadField(pubprogfuncs_t *inst, edict_t *foo, const char *keyname, const char *value) { +#ifdef HEXEN2 /*Worldspawn only fields...*/ if (NUM_FOR_EDICT(inst, foo) == 0) { @@ -381,6 +392,7 @@ pbool PDECL SV_BadField(pubprogfuncs_t *inst, edict_t *foo, const char *keyname, return true; } } +#endif //don't spam warnings about missing fields if we failed to load the progs. if (!svs.numprogs) @@ -403,9 +415,11 @@ void PR_SV_FillWorldGlobals(world_t *w) w->g.v_up = *pr_global_ptrs->v_up; } -void PDECL PR_SSQC_Relocated(pubprogfuncs_t *pr, char *oldb, char *newb, int oldlen) +static void PDECL PR_SSQC_Relocated(pubprogfuncs_t *pr, char *oldb, char *newb, int oldlen) { +#ifdef VM_Q1 edict_t *ent; +#endif int i; union { globalptrs_t *g; @@ -449,7 +463,7 @@ extern int pr_numbuiltins; model_t *SVPR_GetCModel(world_t *w, int modelindex) { - if ((unsigned int)modelindex < MAX_MODELS) + if ((unsigned int)modelindex < MAX_PRECACHE_MODELS) { if (!sv.models[modelindex] && sv.strings.model_precache[modelindex]) sv.models[modelindex] = Mod_ForName(sv.strings.model_precache[modelindex], MLV_WARN); @@ -458,13 +472,13 @@ model_t *SVPR_GetCModel(world_t *w, int modelindex) else return NULL; } -void SVPR_Get_FrameState(world_t *w, wedict_t *ent, framestate_t *fstate) +static void SVPR_Get_FrameState(world_t *w, wedict_t *ent, framestate_t *fstate) { memset(fstate, 0, sizeof(*fstate)); fstate->g[FS_REG].frame[0] = ent->v->frame; } -void SVPR_Event_Touch(world_t *w, wedict_t *s, wedict_t *o) +static void SVPR_Event_Touch(world_t *w, wedict_t *s, wedict_t *o) { int oself = pr_global_struct->self; int oother = pr_global_struct->other; @@ -478,7 +492,7 @@ void SVPR_Event_Touch(world_t *w, wedict_t *s, wedict_t *o) pr_global_struct->other = oother; } -void SVPR_Event_Think(world_t *w, wedict_t *s) +static void SVPR_Event_Think(world_t *w, wedict_t *s) { pr_global_struct->self = EDICT_TO_PROG(w->progs, s); pr_global_struct->other = EDICT_TO_PROG(w->progs, w->edicts); @@ -488,7 +502,7 @@ void SVPR_Event_Think(world_t *w, wedict_t *s) PR_ExecuteProgram (w->progs, s->v->think); } -qboolean SVPR_Event_ContentsTransition(world_t *w, wedict_t *ent, int oldwatertype, int newwatertype) +static qboolean SVPR_Event_ContentsTransition(world_t *w, wedict_t *ent, int oldwatertype, int newwatertype) { if (ent->xv->contentstransition) { @@ -518,9 +532,11 @@ void Q_SetProgsParms(qboolean forcompiler) svprogparms.entspawn = ED_Spawned;//void (*entspawn) (struct edict_s *ent); //ent has been spawned, but may not have all the extra variables (that may need to be set) set svprogparms.entcanfree = ED_CanFree;//bool (*entcanfree) (struct edict_s *ent); //return true to stop ent from being freed svprogparms.stateop = StateOp;//void (*stateop) (float var, func_t func); +#ifdef HEXEN2 svprogparms.cstateop = CStateOp; svprogparms.cwstateop = CWStateOp; svprogparms.thinktimeop = ThinkTimeOp; +#endif //used when loading a game svprogparms.builtinsfor = NULL;//builtin_t *(*builtinsfor) (int num); //must return a pointer to the builtins that were used before the state was saved. @@ -810,6 +826,7 @@ void PR_LoadGlabalStruct(void) PR_SV_FillWorldGlobals(&sv.world); +#ifdef HEXEN2 /*Hexen2 has lots of extra stats, which I don't want special support for, so list them here and send them as for csqc*/ if (progstype == PROG_H2) { @@ -868,6 +885,7 @@ void PR_LoadGlabalStruct(void) SV_QCStatPtr(ev_integer, &h2infoplaque[0], STAT_H2_OBJECTIVE1); SV_QCStatPtr(ev_integer, &h2infoplaque[1], STAT_H2_OBJECTIVE2); } +#endif } progsnum_t AddProgs(const char *name) @@ -1679,8 +1697,9 @@ void Q_InitProgs(void) sv.world.defaultgravityscale = 0; else sv.world.defaultgravityscale = 1; - +#ifdef HEXEN2 SV_RegisterH2CustomTents(); +#endif #ifdef USEODE World_ODE_Start(&sv.world); @@ -2050,7 +2069,7 @@ static void SV_Effect(vec3_t org, int mdlidx, int startframe, int endframe, int SV_Multicast(org, MULTICAST_PVS); } - +#ifdef HEXEN2 static int SV_CustomTEnt_Register(char *effectname, int nettype, float *stain_rgb, float stain_radius, float *dl_rgb, float dl_radius, float dl_time, float *dl_fade) { int i; @@ -2147,7 +2166,7 @@ static int SV_CustomTEnt_Spawn(int index, float *org, float *org2, int count, fl return persist_id; } - +#endif @@ -2350,9 +2369,9 @@ void PF_setmodel_Internal (pubprogfuncs_t *prinst, edict_t *e, const char *m) break; } } - if (i==MAX_MODELS || !sv.strings.model_precache[i]) + if (i==MAX_PRECACHE_MODELS || !sv.strings.model_precache[i]) { - if (i!=MAX_MODELS) + if (i!=MAX_PRECACHE_MODELS) { #ifdef VM_Q1 if (svs.gametype == GT_Q1QVM) @@ -2479,6 +2498,7 @@ static void QCBUILTIN PF_setmodel (pubprogfuncs_t *prinst, struct globalvars_s * PF_setmodel_Internal(prinst, e, m); } +#ifdef HEXEN2 static void QCBUILTIN PF_h2set_puzzle_model (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { //qc/hc lacks string manipulation. edict_t *e; @@ -2490,6 +2510,7 @@ static void QCBUILTIN PF_h2set_puzzle_model (pubprogfuncs_t *prinst, struct glob snprintf(fullname, sizeof(fullname)-1, "models/puzzle/%s.mdl", shortname); PF_setmodel_Internal(prinst, e, fullname); } +#endif /* ================= @@ -2646,26 +2667,6 @@ static void QCBUILTIN PF_centerprint (pubprogfuncs_t *prinst, struct globalvars_ PF_centerprint_Internal(entnum, false, s); } -/* -================= -PF_vhlen - -scalar vhlen(vector) -================= -*/ -static void QCBUILTIN PF_vhlen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) -{ - float *value1; - float newv; - - value1 = G_VECTOR(OFS_PARM0); - - newv = value1[0] * value1[0] + value1[1] * value1[1]; - newv = sqrt(newv); - - G_FLOAT(OFS_RETURN) = newv; -} - /* ================= PF_particle @@ -2797,6 +2798,7 @@ static void QCBUILTIN PF_te_blooddp (pubprogfuncs_t *prinst, globalvars_t *pr_gl SV_Multicast(org, MULTICAST_PVS); } +#ifdef HEXEN2 /* ================= PF_particle2 - hexen2 @@ -2929,6 +2931,7 @@ static void QCBUILTIN PF_h2particleexplosion(pubprogfuncs_t *prinst, struct glob SV_MulticastProtExt (org, MULTICAST_PVS, pr_global_struct->dimension_send, PEXT_HEXEN2, 0); } +#endif /* ================= @@ -2968,7 +2971,7 @@ void PF_ambientsound_Internal (float *pos, const char *samp, float vol, float at for (i=0 ; i<3 ; i++) MSG_WriteCoord(msg, pos[i]); MSG_WriteByte (msg, soundnum); - MSG_WriteByte (msg, vol*255); + MSG_WriteByte (msg, bound(0, (int)(vol*255), 255)); MSG_WriteByte (msg, attenuation*64); } SV_Multicast(pos, MULTICAST_ALL_R); @@ -3162,6 +3165,7 @@ void QCBUILTIN PF_svtraceline (pubprogfuncs_t *prinst, struct globalvars_s *pr_g set_trace_globals(&trace, pr_globals); } +#ifdef HEXEN2 static void QCBUILTIN PF_traceboxh2 (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { float *v1, *v2, *mins, *maxs; @@ -3184,6 +3188,7 @@ static void QCBUILTIN PF_traceboxh2 (pubprogfuncs_t *prinst, struct globalvars_s set_trace_globals(&trace, pr_globals); } +#endif static void QCBUILTIN PF_traceboxdp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -3587,6 +3592,7 @@ static void QCBUILTIN PF_sv_getlight (pubprogfuncs_t *prinst, struct globalvars_ } } +#ifndef QUAKETC /* ========= PF_conprint @@ -3596,20 +3602,17 @@ static void QCBUILTIN PF_conprint (pubprogfuncs_t *prinst, struct globalvars_s * { Sys_Printf ("%s",PF_VarString(prinst, 0, pr_globals)); } +#endif +#ifdef HEXEN2 +//dprintf("foo %s\n", 5.0) - its stupid and potentially unsafe static void QCBUILTIN PF_h2dprintf (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { char temp[256]; char printable[2048]; - float v; char *pct; - v = G_FLOAT(OFS_PARM1); - - if (v == (int)v) - sprintf (temp, "%d",(int)v); - else - sprintf (temp, "%5.1f",v); + sprintf (temp, "%g", G_FLOAT(OFS_PARM1)); Q_strncpyz(printable, PR_GetStringOfs(prinst, OFS_PARM0), sizeof(printable)); while((pct = strstr(printable, "%s"))) @@ -3628,7 +3631,7 @@ static void QCBUILTIN PF_h2dprintv (pubprogfuncs_t *prinst, struct globalvars_s char printable[2048]; char *pct; - sprintf (temp, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM1)[0], G_VECTOR(OFS_PARM1)[1], G_VECTOR(OFS_PARM1)[2]); + sprintf (temp, "'%g %g %g'", G_VECTOR(OFS_PARM1)[0], G_VECTOR(OFS_PARM1)[1], G_VECTOR(OFS_PARM1)[2]); Q_strncpyz(printable, PR_GetStringOfs(prinst, OFS_PARM0), sizeof(printable)); while((pct = strstr(printable, "%s"))) @@ -3647,6 +3650,7 @@ static void QCBUILTIN PF_h2spawn_temp (pubprogfuncs_t *prinst, struct globalvars ed = ED_Alloc(prinst); RETURN_EDICT(prinst, ed); } +#endif static void QCBUILTIN PF_Remove (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -3751,7 +3755,7 @@ void PF_precache_sound_Internal (pubprogfuncs_t *prinst, const char *s) return; } - for (i=1 ; icallargc >= 3) VectorCopy(G_VECTOR(OFS_PARM2), rgb); #endif - style = G_FLOAT(OFS_PARM0); - num = G_FLOAT(OFS_PARM1); - if (num < 0) - num = 0; - else if (num >= 'z'-'a') - num = 'z'-'a'-1; - val = styleDefs[num]; - + val[0] = 'a' + bound(0, num, ('z'-'a')-1); + val[1] = 0; PF_applylightstyle(style, val, rgb); } +#endif /* ============= @@ -4782,6 +4778,8 @@ static void QCBUILTIN PF_WriteString2 (pubprogfuncs_t *prinst, struct globalvars G_FLOAT(OFS_PARM1) = old; } +#ifndef QUAKETC +//qtest-only builtins. static void QCBUILTIN PF_qtSingle_WriteByte (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { NPP_NQWriteByte(MSG_PRERELONE, (qbyte)G_FLOAT(OFS_PARM1)); @@ -4847,6 +4845,7 @@ static void QCBUILTIN PF_qtBroadcast_WriteEntity (pubprogfuncs_t *prinst, struct { NPP_NQWriteEntity(MSG_BROADCAST, (short)G_EDICTNUM(prinst, OFS_PARM0)); } +#endif //====================================================== @@ -5354,7 +5353,7 @@ static void QCBUILTIN PF_Ignore(pubprogfuncs_t *prinst, struct globalvars_s *pr_ G_INT(OFS_RETURN) = 0; } -#define PRSTR 0xa6ffb3d7 +#ifndef QUAKETC static void QCBUILTIN PF_newstring(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) //mvdsv { char *s; @@ -5370,6 +5369,7 @@ static void QCBUILTIN PF_newstring(pubprogfuncs_t *prinst, struct globalvars_s * G_INT(OFS_RETURN) = (char*)s - prinst->stringtable; strcpy(s, in); } +#endif // warning: ‘PF_strcatp’ defined but not used /* @@ -5927,6 +5927,7 @@ void QCBUILTIN PF_ExecuteCommand (pubprogfuncs_t *prinst, struct globalvars_s * pr_global_struct->other = old_other; } +#ifndef QUAKETC /* ================= PF_teamfield @@ -6241,7 +6242,7 @@ static void QCBUILTIN PF_log(pubprogfuncs_t *prinst, struct globalvars_s *pr_glo if (G_FLOAT(OFS_PARM1)) Con_Printf("%s", text); } - +#endif static void QCBUILTIN PF_OpenPortal (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -6467,6 +6468,126 @@ static void QCBUILTIN PF_clientcommand (pubprogfuncs_t *prinst, struct globalvar } + + + + +const char *SV_CheckRejectConnection(netadr_t *adr, const char *uinfo, unsigned int protocol, unsigned int pext1, unsigned int pext2, char *guid) +{ + char addrstr[256]; + char clfeatures[4096], *bp; + const char *ret = NULL; + if (gfuncs.CheckRejectConnection) + { + globalvars_t *pr_globals = PR_globals(svprogfuncs, PR_CURRENT); + + NET_AdrToString(addrstr, sizeof(addrstr), adr); + + *clfeatures = 0; + switch(protocol) + { + default: bp = "unknown"; break; + case SCP_QUAKEWORLD: bp = "qw"; break; + case SCP_QUAKE2: bp = "q2"; break; + case SCP_QUAKE3: bp = "q3"; break; + case SCP_NETQUAKE: bp = "nq"; break; + case SCP_PROQUAKE: bp = "nq"; break; //not nuff difference for it to be meaningful + case SCP_FITZ666: bp = "fitz666"; break; + case SCP_DARKPLACES6: bp = "dp6"; break; + case SCP_DARKPLACES7: bp = "dp7"; break; + } + Info_SetValueForKey(clfeatures, "basicprotocol", bp, sizeof(clfeatures)); + Info_SetValueForKey(clfeatures, "guid", guid, sizeof(clfeatures)); + Info_SetValueForKey(clfeatures, "maxsounds", "256", sizeof(clfeatures)); + Info_SetValueForKey(clfeatures, "maxmodels", "256", sizeof(clfeatures)); + + //this is not the limits of the client itself, but the limits that the server is able and willing to send to them. + + if ((pext1 & PEXT_SOUNDDBL) || (protocol == SCP_FITZ666 || protocol == SCP_DARKPLACES6) || (protocol == SCP_DARKPLACES7)) + Info_SetValueForKey(clfeatures, "maxsounds", va("%i", MAX_PRECACHE_SOUNDS), sizeof(clfeatures)); + else + Info_SetValueForKey(clfeatures, "maxsounds", "256", sizeof(clfeatures)); + + if ((pext1 & PEXT_MODELDBL) || (protocol == SCP_FITZ666 || protocol == SCP_DARKPLACES6) || (protocol == SCP_DARKPLACES7)) + Info_SetValueForKey(clfeatures, "maxmodels", va("%i", MAX_PRECACHE_MODELS), sizeof(clfeatures)); + else + Info_SetValueForKey(clfeatures, "maxmodels", "256", sizeof(clfeatures)); + + if (pext2 & PEXT2_REPLACEMENTDELTAS) + Info_SetValueForKey(clfeatures, "maxentities", va("%i", MAX_EDICTS), sizeof(clfeatures)); + else if (protocol == SCP_FITZ666) +// Info_SetValueForKey(clfeatures, "maxentities", "65535", sizeof(clfeatures)); + Info_SetValueForKey(clfeatures, "maxentities", "32767", sizeof(clfeatures)); + else if (protocol == SCP_DARKPLACES6 || protocol == SCP_DARKPLACES7) + Info_SetValueForKey(clfeatures, "maxentities", "32767", sizeof(clfeatures)); + else if (pext1 & PEXT_ENTITYDBL2) + Info_SetValueForKey(clfeatures, "maxentities", "2048", sizeof(clfeatures)); + else if (pext1 & PEXT_ENTITYDBL) + Info_SetValueForKey(clfeatures, "maxentities", "1024", sizeof(clfeatures)); + else if (protocol == SCP_NETQUAKE) + Info_SetValueForKey(clfeatures, "maxentities", "600", sizeof(clfeatures)); + else //if (protocol == SCP_QUAKEWORLD) + Info_SetValueForKey(clfeatures, "maxentities", "512", sizeof(clfeatures)); + + if (pext2 & PEXT2_REPLACEMENTDELTAS) //limited by packetlog/size, but server can track the whole lot, assuming they're not all sent in a single packet. + Info_SetValueForKey(clfeatures, "maxvisentities", va("%i", MAX_EDICTS), sizeof(clfeatures)); + else if (protocol == SCP_DARKPLACES6 || protocol == SCP_DARKPLACES7) //deltaing protocol allows all ents to be visible at once + Info_SetValueForKey(clfeatures, "maxvisentities", "32767", sizeof(clfeatures)); + else if (pext1 & PEXT_256PACKETENTITIES) + Info_SetValueForKey(clfeatures, "maxvisentities", "256", sizeof(clfeatures)); + else if (protocol == SCP_QUAKEWORLD) + Info_SetValueForKey(clfeatures, "maxvisentities", "64", sizeof(clfeatures)); + //others are limited by packet sizes, so the count can vary... + + //features + if (pext1 & PEXT_VIEW2) + Info_SetValueForKey(clfeatures, "PEXT_VIEW2", "1", sizeof(clfeatures)); + if (pext1 & PEXT_LIGHTSTYLECOL) + Info_SetValueForKey(clfeatures, "PEXT_LIGHTSTYLECOL", "1", sizeof(clfeatures)); + if ((pext1 & PEXT_CSQC) || (protocol == SCP_DARKPLACES6) || (protocol == SCP_DARKPLACES7)) + Info_SetValueForKey(clfeatures, "PEXT_CSQC", "1", sizeof(clfeatures)); + if ((pext1 & PEXT_FLOATCOORDS) || (protocol == SCP_DARKPLACES6) || (protocol == SCP_DARKPLACES7)) + Info_SetValueForKey(clfeatures, "PEXT_FLOATCOORDS", "1", sizeof(clfeatures)); + if ((pext1 & PEXT_ENTITYDBL) || (pext2 & PEXT2_REPLACEMENTDELTAS) || (protocol == SCP_FITZ666 || protocol == SCP_DARKPLACES6) || (protocol == SCP_DARKPLACES7)) + Info_SetValueForKey(clfeatures, "PEXT_ENTITYDBL", "1", sizeof(clfeatures)); + if (pext1 & PEXT_HEXEN2) + Info_SetValueForKey(clfeatures, "PEXT_HEXEN2", "1", sizeof(clfeatures)); + if ((pext1 & PEXT_SETATTACHMENT) || (protocol == SCP_DARKPLACES6) || (protocol == SCP_DARKPLACES7)) + Info_SetValueForKey(clfeatures, "PEXT_SETATTACHMENT", "1", sizeof(clfeatures)); + if (pext1 & PEXT_CUSTOMTEMPEFFECTS) + Info_SetValueForKey(clfeatures, "PEXT_CUSTOMTEMPEFFECTS", "1", sizeof(clfeatures)); + if ((pext2 & PEXT2_PRYDONCURSOR) || (protocol == SCP_DARKPLACES6) || (protocol == SCP_DARKPLACES7)) + Info_SetValueForKey(clfeatures, "PEXT2_PRYDONCURSOR", "1", sizeof(clfeatures)); + if (pext2 & PEXT2_VOICECHAT) + Info_SetValueForKey(clfeatures, "PEXT2_VOICECHAT", "1", sizeof(clfeatures)); + if (pext2 & PEXT2_REPLACEMENTDELTAS) + Info_SetValueForKey(clfeatures, "PEXT2_REPLACEMENTDELTAS", "1", sizeof(clfeatures)); + + pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv.world.edicts); + G_INT(OFS_PARM0) = (int)PR_TempString(svprogfuncs, addrstr); + G_INT(OFS_PARM1) = (int)PR_TempString(svprogfuncs, uinfo); + G_INT(OFS_PARM2) = (int)PR_TempString(svprogfuncs, clfeatures); + PR_ExecuteProgram (svprogfuncs, gfuncs.CheckRejectConnection); + ret = PR_GetStringOfs(svprogfuncs, OFS_RETURN); + if (!*ret) + ret = NULL; + } + return ret; +} +void SV_AddDebugPolygons(void) +{ + int i; + if (gfuncs.AddDebugPolygons) + { + pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv.world.edicts); + for (i = 0; i < sv.allocated_client_slots; i++) + if (svs.clients[i].netchan.remote_address.type == NA_LOOPBACK) + pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, svs.clients[i].edict); + PR_ExecuteProgram (svprogfuncs, gfuncs.AddDebugPolygons); + } +} + +#ifdef HEXEN2 static void QCBUILTIN PF_h2AdvanceFrame(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { edict_t *Ent; @@ -6583,121 +6704,6 @@ static void QCBUILTIN PF_h2advanceweaponframe (pubprogfuncs_t *prinst, struct gl G_FLOAT(OFS_RETURN) = state; } -const char *SV_CheckRejectConnection(netadr_t *adr, const char *uinfo, unsigned int protocol, unsigned int pext1, unsigned int pext2, char *guid) -{ - char addrstr[256]; - char clfeatures[4096], *bp; - const char *ret = NULL; - if (gfuncs.CheckRejectConnection) - { - globalvars_t *pr_globals = PR_globals(svprogfuncs, PR_CURRENT); - - NET_AdrToString(addrstr, sizeof(addrstr), adr); - - *clfeatures = 0; - switch(protocol) - { - default: bp = "unknown"; break; - case SCP_QUAKEWORLD: bp = "qw"; break; - case SCP_QUAKE2: bp = "q2"; break; - case SCP_QUAKE3: bp = "q3"; break; - case SCP_NETQUAKE: bp = "nq"; break; - case SCP_PROQUAKE: bp = "nq"; break; //not nuff difference for it to be meaningful - case SCP_FITZ666: bp = "fitz666"; break; - case SCP_DARKPLACES6: bp = "dp6"; break; - case SCP_DARKPLACES7: bp = "dp7"; break; - } - Info_SetValueForKey(clfeatures, "basicprotocol", bp, sizeof(clfeatures)); - Info_SetValueForKey(clfeatures, "guid", guid, sizeof(clfeatures)); - Info_SetValueForKey(clfeatures, "maxsounds", "256", sizeof(clfeatures)); - Info_SetValueForKey(clfeatures, "maxmodels", "256", sizeof(clfeatures)); - - //this is not the limits of the client itself, but the limits that the server is able and willing to send to them. - - if ((pext1 & PEXT_SOUNDDBL) || (protocol == SCP_FITZ666 || protocol == SCP_DARKPLACES6) || (protocol == SCP_DARKPLACES7)) - Info_SetValueForKey(clfeatures, "maxsounds", va("%i", MAX_SOUNDS), sizeof(clfeatures)); - else - Info_SetValueForKey(clfeatures, "maxsounds", "256", sizeof(clfeatures)); - - if ((pext1 & PEXT_MODELDBL) || (protocol == SCP_FITZ666 || protocol == SCP_DARKPLACES6) || (protocol == SCP_DARKPLACES7)) - Info_SetValueForKey(clfeatures, "maxmodels", va("%i", MAX_MODELS), sizeof(clfeatures)); - else - Info_SetValueForKey(clfeatures, "maxmodels", "256", sizeof(clfeatures)); - - if (pext2 & PEXT2_REPLACEMENTDELTAS) - Info_SetValueForKey(clfeatures, "maxentities", va("%i", MAX_EDICTS), sizeof(clfeatures)); - else if (protocol == SCP_FITZ666) -// Info_SetValueForKey(clfeatures, "maxentities", "65535", sizeof(clfeatures)); - Info_SetValueForKey(clfeatures, "maxentities", "32767", sizeof(clfeatures)); - else if (protocol == SCP_DARKPLACES6 || protocol == SCP_DARKPLACES7) - Info_SetValueForKey(clfeatures, "maxentities", "32767", sizeof(clfeatures)); - else if (pext1 & PEXT_ENTITYDBL2) - Info_SetValueForKey(clfeatures, "maxentities", "2048", sizeof(clfeatures)); - else if (pext1 & PEXT_ENTITYDBL) - Info_SetValueForKey(clfeatures, "maxentities", "1024", sizeof(clfeatures)); - else if (protocol == SCP_NETQUAKE) - Info_SetValueForKey(clfeatures, "maxentities", "600", sizeof(clfeatures)); - else //if (protocol == SCP_QUAKEWORLD) - Info_SetValueForKey(clfeatures, "maxentities", "512", sizeof(clfeatures)); - - if (pext2 & PEXT2_REPLACEMENTDELTAS) //limited by packetlog/size, but server can track the whole lot, assuming they're not all sent in a single packet. - Info_SetValueForKey(clfeatures, "maxvisentities", va("%i", MAX_EDICTS), sizeof(clfeatures)); - else if (protocol == SCP_DARKPLACES6 || protocol == SCP_DARKPLACES7) //deltaing protocol allows all ents to be visible at once - Info_SetValueForKey(clfeatures, "maxvisentities", "32767", sizeof(clfeatures)); - else if (pext1 & PEXT_256PACKETENTITIES) - Info_SetValueForKey(clfeatures, "maxvisentities", "256", sizeof(clfeatures)); - else if (protocol == SCP_QUAKEWORLD) - Info_SetValueForKey(clfeatures, "maxvisentities", "64", sizeof(clfeatures)); - //others are limited by packet sizes, so the count can vary... - - //features - if (pext1 & PEXT_VIEW2) - Info_SetValueForKey(clfeatures, "PEXT_VIEW2", "1", sizeof(clfeatures)); - if (pext1 & PEXT_LIGHTSTYLECOL) - Info_SetValueForKey(clfeatures, "PEXT_LIGHTSTYLECOL", "1", sizeof(clfeatures)); - if ((pext1 & PEXT_CSQC) || (protocol == SCP_DARKPLACES6) || (protocol == SCP_DARKPLACES7)) - Info_SetValueForKey(clfeatures, "PEXT_CSQC", "1", sizeof(clfeatures)); - if ((pext1 & PEXT_FLOATCOORDS) || (protocol == SCP_DARKPLACES6) || (protocol == SCP_DARKPLACES7)) - Info_SetValueForKey(clfeatures, "PEXT_FLOATCOORDS", "1", sizeof(clfeatures)); - if ((pext1 & PEXT_ENTITYDBL) || (pext2 & PEXT2_REPLACEMENTDELTAS) || (protocol == SCP_FITZ666 || protocol == SCP_DARKPLACES6) || (protocol == SCP_DARKPLACES7)) - Info_SetValueForKey(clfeatures, "PEXT_ENTITYDBL", "1", sizeof(clfeatures)); - if (pext1 & PEXT_HEXEN2) - Info_SetValueForKey(clfeatures, "PEXT_HEXEN2", "1", sizeof(clfeatures)); - if ((pext1 & PEXT_SETATTACHMENT) || (protocol == SCP_DARKPLACES6) || (protocol == SCP_DARKPLACES7)) - Info_SetValueForKey(clfeatures, "PEXT_SETATTACHMENT", "1", sizeof(clfeatures)); - if (pext1 & PEXT_CUSTOMTEMPEFFECTS) - Info_SetValueForKey(clfeatures, "PEXT_CUSTOMTEMPEFFECTS", "1", sizeof(clfeatures)); - if ((pext2 & PEXT2_PRYDONCURSOR) || (protocol == SCP_DARKPLACES6) || (protocol == SCP_DARKPLACES7)) - Info_SetValueForKey(clfeatures, "PEXT2_PRYDONCURSOR", "1", sizeof(clfeatures)); - if (pext2 & PEXT2_VOICECHAT) - Info_SetValueForKey(clfeatures, "PEXT2_VOICECHAT", "1", sizeof(clfeatures)); - if (pext2 & PEXT2_REPLACEMENTDELTAS) - Info_SetValueForKey(clfeatures, "PEXT2_REPLACEMENTDELTAS", "1", sizeof(clfeatures)); - - pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv.world.edicts); - G_INT(OFS_PARM0) = (int)PR_TempString(svprogfuncs, addrstr); - G_INT(OFS_PARM1) = (int)PR_TempString(svprogfuncs, uinfo); - G_INT(OFS_PARM2) = (int)PR_TempString(svprogfuncs, clfeatures); - PR_ExecuteProgram (svprogfuncs, gfuncs.CheckRejectConnection); - ret = PR_GetStringOfs(svprogfuncs, OFS_RETURN); - if (!*ret) - ret = NULL; - } - return ret; -} -void SV_AddDebugPolygons(void) -{ - int i; - if (gfuncs.AddDebugPolygons) - { - pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv.world.edicts); - for (i = 0; i < sv.allocated_client_slots; i++) - if (svs.clients[i].netchan.remote_address.type == NA_LOOPBACK) - pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, svs.clients[i].edict); - PR_ExecuteProgram (svprogfuncs, gfuncs.AddDebugPolygons); - } -} - void PRH2_SetPlayerClass(client_t *cl, int classnum, qboolean fromqc) { char temp[16]; @@ -7512,6 +7518,7 @@ static void QCBUILTIN PF_h2getstring(pubprogfuncs_t *prinst, struct globalvars_s char *s = T_GetString(G_FLOAT(OFS_PARM0)-1); RETURN_PSTRING(s); } +#endif static void QCBUILTIN PF_RegisterTEnt(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -8327,24 +8334,28 @@ int PF_ForceInfoKey_Internal(unsigned int entnum, const char *key, const char *v } else if (entnum <= sv.allocated_client_slots) { //woo. we found a client. - Info_SetValueForStarKey(svs.clients[entnum-1].userinfo, key, value, sizeof(svs.clients[entnum-1].userinfo)); - - SV_ExtractFromUserinfo (&svs.clients[entnum-1], false); - - MSG_WriteByte (&sv.reliable_datagram, svc_setinfo); - MSG_WriteByte (&sv.reliable_datagram, entnum-1); - MSG_WriteString (&sv.reliable_datagram, key); - MSG_WriteString (&sv.reliable_datagram, Info_ValueForKey(svs.clients[entnum-1].userinfo, key)); - - if (!strcmp(key, "*spectator")) - svs.clients[entnum-1].spectator = !!atoi(value); - if (!strcmp(key, "*transfer")) + char *oldvalue = Info_ValueForKey(svs.clients[entnum-1].userinfo, key); + if (strcmp(oldvalue, value)) { + Info_SetValueForStarKey(svs.clients[entnum-1].userinfo, key, value, sizeof(svs.clients[entnum-1].userinfo)); + + SV_ExtractFromUserinfo (&svs.clients[entnum-1], false); + + MSG_WriteByte (&sv.reliable_datagram, svc_setinfo); + MSG_WriteByte (&sv.reliable_datagram, entnum-1); + MSG_WriteString (&sv.reliable_datagram, key); + MSG_WriteString (&sv.reliable_datagram, Info_ValueForKey(svs.clients[entnum-1].userinfo, key)); + + if (!strcmp(key, "*spectator")) + svs.clients[entnum-1].spectator = !!atoi(value); + if (!strcmp(key, "*transfer")) + { #ifdef SUBSERVERS - SSV_InitiatePlayerTransfer(&svs.clients[entnum-1], value); + SSV_InitiatePlayerTransfer(&svs.clients[entnum-1], value); #else - PF_ForceInfoKey_Internal(entnum, key, ""); + PF_ForceInfoKey_Internal(entnum, key, ""); #endif + } } return 1; @@ -8656,6 +8667,7 @@ static void QCBUILTIN PF_runclientphys(pubprogfuncs_t *prinst, struct globalvars pmove.groundent = 0; pmove.waterlevel = 0; pmove.watertype = 0; + pmove.capsule = (ent->xv->geomtype == GEOMTYPE_CYLINDER); for (i=0 ; i<3 ; i++) { @@ -9035,7 +9047,6 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"setmodel", PF_setmodel, 3, 3, 3, 0, D("void(entity e, string m)","Looks up m in the model precache list, and sets both e.model and e.modelindex to match. BSP models will set e.mins and e.maxs accordingly, other models depend upon the value of sv_gameplayfix_setmodelrealbox - for compatibility you should always call setsize after all pickups or non-bsp models. Also relinks collision state.")}, {"setsize", PF_setsize, 4, 4, 4, 0, D("void(entity e, vector min, vector max)", "Sets the e's mins and maxs fields. Also relinks collision state, which sets absmin and absmax too.")}, {"qtest_setabssize",PF_setsize, 5, 0, 0, 0, D("void(entity e, vector min, vector max)", "qtest"), true}, - {"lightstylestatic",PF_lightstylestatic,0, 0, 5, 5, D("void(float style, float val, optional vector rgb)", "Sets the lightstyle to an explicit numerical level. From Hexen2.")}, {"breakpoint", PF_break, 6, 6, 6, 0, D("void()", "Trigger a debugging event. FTE will break into the qc debugger. Other engines may crash with a debug execption.")}, {"random", PF_random, 7, 7, 7, 0, D("float()", "Returns a random value between 0 and 1. Be warned, this builtin can return 1 in most engines, which can break arrays.")}, {"sound", PF_sound, 8, 8, 8, 0, D("void(entity e, float chan, string samp, float vol, float atten, optional float speedpct, optional float flags)", "Starts a sound centered upon the given entity.\nchan is the entity sound channel to use, channel 0 will allow you to mix many samples at once, others will replace the old sample\n'samp' must have been precached first\nif specified, 'speedpct' should normally be around 100 (or =0), 200 for double speed or 50 for half speed.\nflags&1 means the sound should be sent reliably.")}, @@ -9068,7 +9079,6 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"traceoff", PF_traceoff, 30, 30, 30, 0, D("void()", "Disables tracing again.")}, {"eprint", PF_eprint, 31, 31, 31, 0, D("void(entity e)", "Debugging builtin that prints all fields of the given entity to the console.")},// debug print an entire entity {"walkmove", PF_walkmove, 32, 32, 32, 0, D("float(float yaw, float dist, optional float settraceglobals)", "Attempt to walk the entity at a given angle for a given distance.\nif settraceglobals is set, the trace_* globals will be set, showing the results of the movement.\nThis function will trigger touch events.")}, - {"tracearea", PF_traceboxh2, 0, 0, 33, 0, D("void(vector v1, vector v2, vector mins, vector maxs, float nomonsters, entity ent)", "For hexen2 compat")}, // {"qtest_flymove", NULL, 33}, // float(vector dir) flymove = #33; //qbism super8's 'private'sound #33 {"droptofloor", PF_droptofloor, 34, 34, 34, 0, D("float()", "Instantly moves the entity downwards until it hits the ground. If the entity would need to drop more than 'pr_droptofloorunits' quake units, its position will be considered invalid and the builtin will abort.")}, @@ -9088,7 +9098,6 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"particle", PF_particle, 48, 0, 48, 48, D("void(vector pos, vector dir, float colour, float count)", "Spawn 'count' particles around 'pos' moving in the direction 'dir', with a palette colour index between 'colour' and 'colour+8'.")}, //48 nq readded. This isn't present in QW protocol (fte added it back). {"changeyaw", PF_changeyaw, 49, 49, 49, 0, D("#define ChangeYaw changeyaw\nvoid()", "Changes the self.angles_y field towards self.ideal_yaw by up to self.yawspeed.")}, // {"qtest_precacheitem", NULL, 50}, // defined QTest builtin that is never called - {"vhlen", PF_vhlen, 0, 0, 50, 0, D("float(vector)", "Returns the horizontal length of the given vector ignoring z dispalcement - specifically sqrt(x*x+y*y)")}, {"vectoangles", PF_vectoangles, 51, 51, 51, 0, D("vector(vector fwd, optional vector up)", "Returns the angles required to orient an entity to look in the given direction. The 'up' argument is required if you wish to set a roll angle, otherwise it will be limited to just monster-style turning.")}, {"WriteByte", PF_WriteByte, 52, 52, 52, 0, D("void(float to, float val)", "Writes a single byte into a network message buffer. Typically you will find a more correct alternative to writing arbitary data. 'to' should be one of the MSG_* constants. MSG_ONE must have msg_entity set first.")}, //52 @@ -9100,6 +9109,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"WriteString", PF_WriteString, 58, 58, 58, 0, "void(float to, string val)"}, //58 {"WriteEntity", PF_WriteEntity, 59, 59, 59, 0, "void(float to, entity val)"}, //59 +#ifndef QUAKETC {"swritebyte", PF_qtSingle_WriteByte}, //52 {"swritechar", PF_qtSingle_WriteChar}, //53 {"swriteshort", PF_qtSingle_WriteShort}, //54 @@ -9117,23 +9127,12 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"bwriteangle", PF_qtBroadcast_WriteAngle}, //64 {"bwritestring", PF_qtBroadcast_WriteString}, //65 {"bwriteentity", PF_qtBroadcast_WriteEntity}, //66 - - - {"printfloat", PF_h2dprintf, 0, 0, 60}, //60 +#endif {"sin", PF_Sin, 0, 0, 62, 60, "float(float angle)"}, //60 {"cos", PF_Cos, 0, 0, 61, 61, "float(float angle)"}, //61 {"sqrt", PF_Sqrt, 0, 0, 84, 62, "float(float value)"}, //62 - {"AdvanceFrame", PF_h2AdvanceFrame, 0, 0, 63, 0}, - {"printvec", PF_h2dprintv, 0, 0, 64, 0}, //64 - {"RewindFrame", PF_h2RewindFrame, 0, 0, 65, 0}, - {"particleexplosion",PF_h2particleexplosion,0, 0, 81, 0}, - {"movestep", PF_h2movestep, 0, 0, 82, 0}, - {"advanceweaponframe",PF_h2advanceweaponframe,0,0, 83, 0}, - - {"setclass", PF_h2setclass, 0, 0, 66, 0}, - {"changepitch", PF_changepitch, 0, 0, 0, 63, "void(entity ent)"}, {"tracetoss", PF_TraceToss, 0, 0, 0, 64, "void(entity ent, entity ignore)"}, {"etos", PF_etos, 0, 0, 0, 65, "string(entity ent)"}, @@ -9143,7 +9142,6 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"makestatic", PF_makestatic, 69, 69, 69, 0, D("void(entity e)", "Sends a copy of the entity's renderable fields to all clients, and REMOVES the entity, preventing further changes. This means it will be unmutable and non-solid.")}, //69 {"changelevel", PF_changelevel, 70, 70, 70, 0, D("void(string mapname, optional string newmapstartspot)", "Attempts to change the map to the named map. If 'newmapstartspot' is specified, the state of the current map will be preserved, and the argument will be passed to the next map in the 'startspot' global, and the next map will be loaded from archived state if it was previously visited. If not specified, all archived map states will be purged.")}, //70 - {"lightstylevalue", PF_lightstylevalue, 0, 0, 71, 0, D("float(float lstyle)", "Returns the last value passed into the lightstylestatic builtin, or the first value specified by the style string passed to the lightstyle builtin")}, //70 {"cvar_set", PF_cvar_set, 72, 72, 72, 0, D("void(string cvarname, string valuetoset)", "Instantly sets a cvar to the given string value.")}, //72 {"centerprint", PF_centerprint, 73, 73, 73, 0, "void(entity ent, string text, optional string text2, optional string text3, optional string text4, optional string text5, optional string text6, optional string text7)"}, //73 @@ -9155,7 +9153,6 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"precache_file2", PF_precache_file, 77, 77, 0, 0, "string(string str)"}, //77 {"setspawnparms", PF_setspawnparms, 78, 78, 78, 0, "void(entity player)"}, //78 - {"plaque_draw", PF_h2plaque_draw, 0, 0, 79, 0, "void(entity targ, float stringno)"}, //79 {"logfrag", PF_logfrag, 0, 79, 0, 79, "void(entity killer, entity killee)"}, //79 // Tomaz - QuakeC String Manipulation Begin @@ -9175,15 +9172,13 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"tq_fputs", PF_fputs, 0, 0, 0, 89, D("void(filestream fhandle, string s)",NULL), true},// (QSG_FILE) // Tomaz - QuakeC File System End - {"rain_go", PF_h2rain_go, 0, 0, 80, 0}, //80 - {"infokey", PF_infokey, 0, 80, 0, 80, D("string(entity e, string key)", "If e is world, returns the field 'key' from either the serverinfo or the localinfo. If e is a player, returns the value of 'key' from the player's userinfo string. There are a few special exceptions, like 'ip' which is not technically part of the userinfo.")}, //80 {"stof", PF_stof, 0, 81, 0, 81, "float(string)"}, //81 {"multicast", PF_multicast, 0, 82, 0, 82, D("#define unicast(pl,reli) do{msg_entity = pl; multicast('0 0 0', reli?MULITCAST_ONE_R:MULTICAST_ONE);}while(0)\n" "void(vector where, float set)", "Once the MSG_MULTICAST network message buffer has been filled with data, this builtin is used to dispatch it to the given target, filtering by pvs for reduced network bandwidth.")}, //82 - +#ifndef QUAKETC //mvdsv (don't require ebfs usage in qw) {"executecommand", PF_ExecuteCommand, 0, 0, 0, 83, D("void()",NULL), true}, {"mvdtokenize", PF_Tokenize, 0, 0, 0, 84, D("void(string str)",NULL), true}, @@ -9212,7 +9207,25 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"mvdcalltimeofday",PF_calltimeofday, 0, 0, 0, 102, D("void()",NULL), true}, {"forcedemoframe", PF_forcedemoframe, 0, 0, 0, 103, D("void(float now)",NULL), true}, //end of mvdsv +#endif +#ifdef HEXEN2 + {"lightstylestatic",PF_lightstylestatic,0, 0, 5, 5, D("void(float style, float val, optional vector rgb)", "Sets the lightstyle to an explicit numerical level. From Hexen2.")}, + {"tracearea", PF_traceboxh2, 0, 0, 33, 0, D("void(vector v1, vector v2, vector mins, vector maxs, float nomonsters, entity ent)", "For hexen2 compat")}, + {"vhlen", PF_vhlen, 0, 0, 50, 0, D("float(vector)", "Returns the horizontal length of the given vector ignoring z dispalcement - specifically sqrt(x*x+y*y)")}, + {"printfloat", PF_h2dprintf, 0, 0, 60, 0}, //60 + {"AdvanceFrame", PF_h2AdvanceFrame, 0, 0, 63, 0}, + {"printvec", PF_h2dprintv, 0, 0, 64, 0}, //64 + {"RewindFrame", PF_h2RewindFrame, 0, 0, 65, 0}, + {"particleexplosion",PF_h2particleexplosion,0, 0, 81, 0}, + {"movestep", PF_h2movestep, 0, 0, 82, 0}, + {"advanceweaponframe",PF_h2advanceweaponframe,0,0, 83, 0}, + + {"setclass", PF_h2setclass, 0, 0, 66, 0}, + {"lightstylevalue", PF_lightstylevalue, 0, 0, 71, 0, D("float(float lstyle)", "Returns the last value passed into the lightstylestatic builtin, or the first value specified by the style string passed to the lightstyle builtin")}, //70 + + {"plaque_draw", PF_h2plaque_draw, 0, 0, 79, 0, "void(entity targ, float stringno)"}, //79 + {"rain_go", PF_h2rain_go, 0, 0, 80, 0}, //80 {"setpuzzlemodel", PF_h2set_puzzle_model,0, 0, 87, 0}, {"starteffect", PF_h2starteffect, 0, 0, 88, 0}, //FIXME {"endeffect", PF_h2endeffect, 0, 0, 89, 0}, //FIXME @@ -9237,6 +9250,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"precache_model4", PF_precache_model, 0, 0, 116, 0},//please don't use... {"precache_sound4", PF_precache_sound, 0, 0, 117, 0}, +#endif {"tracebox", PF_traceboxdp, 0, 0, 0, 90, D("void(vector start, vector mins, vector maxs, vector end, float nomonsters, entity ent)", "Exactly like traceline, but a box instead of a uselessly thin point. Acceptable sizes are limited by bsp format, q1bsp has strict acceptable size values.")}, @@ -9293,9 +9307,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"externset", PF_externset, 0, 0, 0, 204, D("void(float prnum, __variant newval, string varname)", "Sets a global in the named progs by name.\nprnum=0 is the 'default' or 'main' progs.\nprnum=-1 means current progs.\nprnum=-2 will scan through the active progs and will use the first it finds.")}, {"externrefcall", PF_externrefcall, 0, 0, 0, 205, D("__variant(float prnum, void() func, ...)","Calls a function between progs by its reference. No longer needed as direct function calls now switch progs context automatically, and have done for a long time. There is no remaining merit for this function."), true}, {"instr", PF_instr, 0, 0, 0, 206, D("float(string input, string token)", "Returns substring(input, strstrpos(input, token), -1), or the null string if token was not found in input. You're probably better off using strstrpos.")}, -#if defined(Q2BSPS) || defined(Q3BSPS) {"openportal", PF_OpenPortal, 0, 0, 0, 207, D("void(entity portal, float state)", "Opens or closes the portals associated with a door or some such on q2 or q3 maps. On Q2BSPs, the entity should be the 'func_areaportal' entity - its style field will say which portal to open. On Q3BSPs, the entity is the door itself, the portal will be determined by the two areas found from a preceding setorigin call.")}, -#endif {"RegisterTempEnt", PF_RegisterTEnt, 0, 0, 0, 208, "float(float attributes, string effectname, ...)"}, {"CustomTempEnt", PF_CustomTEnt, 0, 0, 0, 209, "void(float type, vector pos, ...)"}, @@ -9306,10 +9318,12 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs #ifdef SVCHAT {"chat", PF_chat, 0, 0, 0, 214, "void(string filename, float starttag, entity edict)"}, //(FTE_NPCCHAT) #endif -//FTE_PEXT_HEXEN2 + +#ifdef HEXEN2 {"particle2", PF_particle2, 0, 0, 42, 215, "void(vector org, vector dmin, vector dmax, float colour, float effect, float count)"}, {"particle3", PF_particle3, 0, 0, 85, 216, "void(vector org, vector box, float colour, float effect, float count)"}, {"particle4", PF_particle4, 0, 0, 86, 217, "void(vector org, float radius, float colour, float effect, float count)"}, +#endif //EXT_DIMENSION_PLANES {"bitshift", PF_bitshift, 0, 0, 0, 218, "float(float number, float quantity)"}, @@ -9789,7 +9803,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs //end dp extras - {"getrmqeffectsversion", PF_Ignore, 0, 0, 0, 666, "float()" STUB}, + {"getrmqeffectsversion",PF_Ignore, 0, 0, 0, 666, "float()" STUB}, //don't exceed sizeof(pr_builtin)/sizeof(pr_builtin[0]) (currently 1024) without modifing the size of pr_builtin {NULL} @@ -9852,6 +9866,7 @@ void PR_ResetBuiltins(progstype_t type) //fix all nulls to PF_FIXME and add any builtincount[i]=100; } +#ifndef QUAKETC if (type == PROG_PREREL) { pr_builtin[52] = PF_qtSingle_WriteByte; @@ -9872,6 +9887,7 @@ void PR_ResetBuiltins(progstype_t type) //fix all nulls to PF_FIXME and add any pr_builtin[65] = PF_qtBroadcast_WriteString; pr_builtin[66] = PF_qtBroadcast_WriteEntity; } +#endif if (!pr_compatabilitytest.value) { @@ -10109,7 +10125,11 @@ svextqcfields #define H2 16 //mere flags #define FTE 32 +#ifdef HEXEN2 #define ALL (QW|NQ|H2|CS|MENU) +#else +#define ALL (QW|NQ|CS|MENU) +#endif #define CORE typedef struct { @@ -10558,7 +10578,7 @@ void PR_DumpPlatform_f(void) {"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}, +// {"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}, diff --git a/engine/server/pr_lua.c b/engine/server/pr_lua.c index 720b695e4..ed3fdd852 100644 --- a/engine/server/pr_lua.c +++ b/engine/server/pr_lua.c @@ -1940,7 +1940,6 @@ static qboolean Lua_Event_ContentsTransition(world_t *w, wedict_t *ent, int oldw return false; //always do legacy behaviour } -void PR_SV_FillWorldGlobals(world_t *w); static void Lua_SetupGlobals(world_t *world) { int flds; diff --git a/engine/server/pr_q1qvm.c b/engine/server/pr_q1qvm.c index a18cda1e8..28ec65bf5 100755 --- a/engine/server/pr_q1qvm.c +++ b/engine/server/pr_q1qvm.c @@ -47,8 +47,6 @@ oh, wait, ktx no longer supports those properly. #define MAX_Q1QVM_EDICTS 768 //according to ktx at api version 12 (fte's protocols go to 2048) #define MAPNAME_LEN 64 -#define VMFSID_Q1QVM 57235 //a cookie - void PR_SV_FillWorldGlobals(world_t *w); #if GAME_API_VERSION >= 13 @@ -561,7 +559,7 @@ static qintptr_t syscallhandle (void *offset, quintptr_t mask, qintptr_t fn, con case G_GetEntityToken: { - if (VM_OOB(arg[0], arg[1])) + if (VM_OOB(arg[0], arg[1]) || !arg[1]) return false; if (q1qvmentstring) { @@ -573,7 +571,7 @@ static qintptr_t syscallhandle (void *offset, quintptr_t mask, qintptr_t fn, con else { char *ret = VM_POINTER(arg[0]); - strcpy(ret, ""); + *ret = '\0'; return false; } } diff --git a/engine/server/progs.h b/engine/server/progs.h index f1ef089c7..a0999c0a6 100644 --- a/engine/server/progs.h +++ b/engine/server/progs.h @@ -126,6 +126,7 @@ void PF_InitTempStrings(pubprogfuncs_t *prinst); qboolean PR_LoadLua(void); #endif #ifdef VM_Q1 +#define VMFSID_Q1QVM 57235 //the q1qvm zone tag that is freed when the module is purged. struct client_s; void Q1QVM_Shutdown(void); qboolean PR_LoadQ1QVM(void); diff --git a/engine/server/savegame.c b/engine/server/savegame.c index b008f6c14..c28c57e95 100644 --- a/engine/server/savegame.c +++ b/engine/server/savegame.c @@ -77,7 +77,7 @@ void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version) int filelen, filepos; char *file; - char *modelnames[MAX_MODELS]; + char *modelnames[MAX_PRECACHE_MODELS]; if (version != 667 && version != 5 && version != 6) //5 for NQ, 6 for ZQ/FQ { @@ -241,7 +241,7 @@ void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version) } //model names are pointers to vm-accessible memory. as that memory is going away, we need to destroy and recreate, which requires preserving them. - for (i = 1; i < MAX_MODELS; i++) + for (i = 1; i < MAX_PRECACHE_MODELS; i++) { if (!sv.strings.model_precache[i]) { @@ -268,7 +268,7 @@ void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version) } //reload model names. - for (i = 1; i < MAX_MODELS; i++) + for (i = 1; i < MAX_PRECACHE_MODELS; i++) { if (!modelnames[i]) break; @@ -480,7 +480,7 @@ void LoadModelsAndSounds(vfsfile_t *f) int i; sv.strings.model_precache[0] = PR_AddString(svprogfuncs, "", 0, false); - for (i=1; i < MAX_MODELS; i++) + for (i=1; i < MAX_PRECACHE_MODELS; i++) { VFS_GETS(f, str, sizeof(str)); if (!*str) @@ -488,17 +488,17 @@ void LoadModelsAndSounds(vfsfile_t *f) sv.strings.model_precache[i] = PR_AddString(svprogfuncs, str, 0, false); } - if (i == MAX_MODELS) + if (i == MAX_PRECACHE_MODELS) { VFS_GETS(f, str, sizeof(str)); if (*str) SV_Error("Too many model precaches in loadgame cache"); } - for (; i < MAX_MODELS; i++) + for (; i < MAX_PRECACHE_MODELS; i++) sv.strings.model_precache[i] = NULL; // sv.sound_precache[0] = PR_AddString(svprogfuncs, "", 0); - for (i=1; i < MAX_SOUNDS; i++) + for (i=1; i < MAX_PRECACHE_SOUNDS; i++) { VFS_GETS(f, str, sizeof(str)); if (!*str) @@ -506,13 +506,13 @@ void LoadModelsAndSounds(vfsfile_t *f) // sv.sound_precache[i] = PR_AddString(svprogfuncs, str, 0); } - if (i == MAX_SOUNDS) + if (i == MAX_PRECACHE_SOUNDS) { VFS_GETS(f, str, sizeof(str)); if (*str) SV_Error("Too many sound precaches in loadgame cache"); } - for (; i < MAX_SOUNDS; i++) + for (; i < MAX_PRECACHE_SOUNDS; i++) *sv.strings.sound_precache[i] = 0; } @@ -944,7 +944,7 @@ void SV_SaveLevelCache(char *savedir, qboolean dontharmgame) VFS_PRINTF (f, "%s\n", sv.strings.lightstyles[i]?sv.strings.lightstyles[i]:""); } - for (i=1 ; icallback = gtcallback; +// gametype->callback = gtcallback; if (q3singleplayer) Cvar_ForceSet(gametype, "2");//singleplayer else if (gametype->value == 2) @@ -1731,14 +1731,14 @@ static void SV_Status_f (void) { int count = 0; Con_Printf("entities : %i/%i (mem: %i/%i)\n", sv.world.num_edicts, sv.world.max_edicts, sv.world.progs->stringtablesize, sv.world.progs->stringtablemaxsize); - for (count = 1; count < MAX_MODELS; count++) + for (count = 1; count < MAX_PRECACHE_MODELS; count++) if (!sv.strings.model_precache[count]) break; - Con_Printf("models : %i/%i\n", count, MAX_MODELS); - for (count = 1; count < MAX_SOUNDS; count++) + Con_Printf("models : %i/%i\n", count, MAX_PRECACHE_MODELS); + for (count = 1; count < MAX_PRECACHE_SOUNDS; count++) if (!*sv.strings.sound_precache[count]) break; - Con_Printf("sounds : %i/%i\n", count, MAX_SOUNDS); + Con_Printf("sounds : %i/%i\n", count, MAX_PRECACHE_SOUNDS); } Con_Printf("gamedir : %s\n", FS_GetGamedir(true)); if (sv.csqcdebug) diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index b4e9805f7..b3fabca6b 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -1238,7 +1238,13 @@ void SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizebuf_t // Con_Printf("Gen sequence %i\n", sequence); MSG_WriteFloat(msg, sv.world.physicstime); - for(j = 0; j < client->sentents.num_entities; j++) + if (client->pendingentbits[0] & UF_REMOVE) + { + SV_EmitDeltaEntIndex(msg, 0, true, true); + resendbits[outno] = UF_REMOVE; + resendnum[outno++] = 0; + } + for(j = 1; j < client->sentents.num_entities; j++) { bits = client->pendingentbits[j]; if (!(bits & ~UF_RESET2)) //skip while there's nothing to send (skip reset2 if there's no other changes, its only to reduce chances of the client getting 'new' entities containing just an origin)*/ @@ -2019,7 +2025,7 @@ qboolean Cull_Traceline(pvscamera_t *cameras, edict_t *seen) for (c = 0; c < cameras->numents; c++) { tr.fraction = 1; - if (!sv.world.worldmodel->funcs.NativeTrace (sv.world.worldmodel, 1, 0, NULL, cameras->org[c], seen->v->origin, vec3_origin, vec3_origin, FTECONTENTS_SOLID, &tr)) + if (!sv.world.worldmodel->funcs.NativeTrace (sv.world.worldmodel, 1, 0, NULL, cameras->org[c], seen->v->origin, vec3_origin, vec3_origin, false, FTECONTENTS_SOLID, &tr)) return false; //wasn't blocked } @@ -2033,7 +2039,7 @@ qboolean Cull_Traceline(pvscamera_t *cameras, edict_t *seen) end[2] = seen->v->origin[2] + ((i&4)?seen->v->mins[2]+0.1:seen->v->maxs[2]); tr.fraction = 1; - if (!sv.world.worldmodel->funcs.NativeTrace (sv.world.worldmodel, 1, 0, NULL, cameras->org[c], end, vec3_origin, vec3_origin, FTECONTENTS_SOLID, &tr)) + if (!sv.world.worldmodel->funcs.NativeTrace (sv.world.worldmodel, 1, 0, NULL, cameras->org[c], end, vec3_origin, vec3_origin, false, FTECONTENTS_SOLID, &tr)) return false; //this trace went through, so don't cull } } @@ -2898,7 +2904,7 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli else if (ent->v->solid == SOLID_BBOX || ent->v->solid == SOLID_SLIDEBOX || ent->v->skin < 0) { unsigned int mdl = ent->v->modelindex; - if (mdl < MAX_MODELS && sv.models[mdl] && sv.models[mdl]->type == mod_brush) + if (mdl < MAX_PRECACHE_MODELS && sv.models[mdl] && sv.models[mdl]->type == mod_brush) state->solid = ES_SOLID_BSP; else { diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 6747153a7..afbacd28e 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -31,8 +31,6 @@ server_t sv; // local server entity_state_t *sv_staticentities; int sv_max_staticentities; -char localmodels[MAX_MODELS][5]; // inline model names for precache - char localinfo[MAX_LOCALINFO_STRING+1]; // local game info extern cvar_t skill, sv_loadentfiles; @@ -57,12 +55,12 @@ int SV_ModelIndex (const char *name) if (!name || !name[0]) return 0; - for (i=1 ; inumsubmodels ; i++) + subs = sv.world.worldmodel->numsubmodels; + if (subs > MAX_PRECACHE_MODELS-2) { - sv.strings.model_precache[1+i] = localmodels[i]; - sv.models[i+1] = Mod_ForName (localmodels[i], MLV_WARN); + Con_Printf("Warning: worldmodel has too many submodels\n"); + subs = MAX_PRECACHE_MODELS-2; + } + + sv.strings.model_precache[1] = sv.modelname; //the qvm doesn't have access to this array + for (i=1 ; inumsubmodels ; i++) + + subs = sv.world.worldmodel->numsubmodels; + if (subs > MAX_PRECACHE_MODELS-2) { - sv.strings.model_precache[1+i] = PR_AddString(svprogfuncs, localmodels[i], 0, false); - sv.models[i+1] = Mod_ForName (localmodels[i], MLV_WARN); + Con_Printf("Warning: worldmodel has too many submodels\n"); + subs = MAX_PRECACHE_MODELS-2; + } + for (i=1 ; inumsubmodels; + if (subs > Q2MAX_MODELS-2) + { + Con_Printf("Warning: worldmodel has too many submodels\n"); + subs = Q2MAX_MODELS-2; + } + strcpy(sv.strings.configstring[Q2CS_MODELS+1], sv.modelname); for (i=1; inumsubmodels; i++) { - strcpy(sv.strings.configstring[Q2CS_MODELS+1+i], localmodels[i]); - sv.models[i+1] = Mod_ForName (localmodels[i], MLV_WARN); + Q_snprintfz(sv.strings.configstring[Q2CS_MODELS+1+i], sizeof(sv.strings.configstring[Q2CS_MODELS+1+i]), "*%u", i); + sv.models[i+1] = Mod_ForName (sv.strings.configstring[Q2CS_MODELS+1+i], MLV_WARN); } } #endif @@ -1480,9 +1507,11 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us val = svprogfuncs->GetEdictFieldValue(svprogfuncs, ent, "message", NULL); if (val) { +#ifdef HEXEN2 if (progstype == PROG_H2) snprintf(sv.mapname, sizeof(sv.mapname), "%s", T_GetString(val->_float-1)); else +#endif snprintf(sv.mapname, sizeof(sv.mapname), "%s", PR_GetString(svprogfuncs, val->string)); } else diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index b8bb9bd25..b9d87f056 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -275,7 +275,9 @@ void SV_Shutdown (void) Z_Free(lp); } +#ifdef HEXEN2 T_FreeStrings(); +#endif SV_GibFilterPurge(); @@ -1745,7 +1747,7 @@ void SV_ClientProtocolExtensionsChanged(client_t *client) //you need to reconnect for this to update, of course. so make sure its not *too* low... client->max_net_ents = bound(512, pr_maxedicts.ival, MAX_EDICTS); - client->maxmodels = MAX_MODELS; //protocol limited to 14 bits. + client->maxmodels = MAX_PRECACHE_MODELS; //protocol limited to 14 bits. } else if (ISQWCLIENT(client)) //readd? { @@ -1757,7 +1759,7 @@ void SV_ClientProtocolExtensionsChanged(client_t *client) client->max_net_ents += 1024; if (client->fteprotocolextensions & PEXT_MODELDBL) - client->maxmodels = MAX_MODELS; + client->maxmodels = MAX_PRECACHE_MODELS; } else if (ISDPCLIENT(client)) { @@ -4546,9 +4548,6 @@ void SV_InitLocal (void) SV_MVDInit(); - for (i=0 ; idrate = cl->rate; //0 disables the downloading check +#ifdef HEXEN2 val = Info_ValueForKey (cl->userinfo, "cl_playerclass"); if (val) { PRH2_SetPlayerClass(cl, atoi(val), false); } +#endif // msg command val = Info_ValueForKey (cl->userinfo, "msg"); diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index b789da717..f0288f614 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -1331,7 +1331,7 @@ static void WPhys_Physics_Toss (world_t *w, wedict_t *ent) if (trace.allsolid) { if (progstype != PROG_H2) - trace.fraction = 0; + trace.fraction = 0; //traces that start in solid report a fraction of 0. this is to prevent things from dropping out of the world completely. at least this way they ought to still be shootable etc #pragma warningmsg("The following line might help boost framerates a lot in rmq, not sure if they violate expected behaviour in other mods though - check that they're safe.") VectorNegate(gravitydir, trace.plane.normal); @@ -1976,6 +1976,7 @@ static void WPhys_WalkMove (world_t *w, wedict_t *ent, const float *gravitydir) } #endif +#ifdef HEXEN2 void WPhys_MoveChain(world_t *w, wedict_t *ent, wedict_t *movechain, float *initial_origin, float *initial_angle) { qboolean callfunc; @@ -2006,6 +2007,7 @@ void WPhys_MoveChain(world_t *w, wedict_t *ent, wedict_t *movechain, float *init } } } +#endif /* ================ @@ -2015,8 +2017,10 @@ SV_RunEntity */ void WPhys_RunEntity (world_t *w, wedict_t *ent) { +#ifdef HEXEN2 wedict_t *movechain; vec3_t initial_origin = {0},initial_angle = {0}; // warning: ‘initial_?[?]’ may be used uninitialized in this function +#endif const float *gravitydir; #ifndef CLIENTONLY @@ -2071,13 +2075,14 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent) } - +#ifdef HEXEN2 movechain = PROG_TO_WEDICT(w->progs, ent->xv->movechain); if (movechain != w->edicts) { VectorCopy(ent->v->origin,initial_origin); VectorCopy(ent->v->angles,initial_angle); } +#endif switch ( (int)ent->v->movetype) { @@ -2140,10 +2145,10 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent) break; } +#ifdef HEXEN2 if (movechain != w->edicts) - { WPhys_MoveChain(w, ent, movechain, initial_origin, initial_angle); - } +#endif #ifndef CLIENTONLY if (svent) diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 39d2517bc..e1ded4fb1 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -995,15 +995,15 @@ void SV_StartSound (int ent, vec3_t origin, int seenmask, int channel, const cha return; else { - for (sound_num=1 ; sound_numv->weaponmodel)); if (client->fteprotocolextensions & PEXT_MODELDBL) { - if ((unsigned)statsi[STAT_WEAPON] >= MAX_MODELS) + if ((unsigned)statsi[STAT_WEAPON] >= MAX_PRECACHE_MODELS) statsi[STAT_WEAPON] = 0; } else diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 3ed58f075..a3bd55225 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -983,7 +983,7 @@ void SV_SendClientPrespawnInfo(client_t *client) int maxclientsupportedsounds = 256; #ifdef PEXT_SOUNDDBL if (client->fteprotocolextensions & PEXT_SOUNDDBL) - maxclientsupportedsounds = MAX_SOUNDS; + maxclientsupportedsounds = MAX_PRECACHE_SOUNDS; #endif started = false; @@ -5932,6 +5932,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse) pmove.physents[0].model = sv.world.worldmodel; pmove.cmd = *ucmd; pmove.hullnum = SV_HullNumForPlayer(0, player_mins, player_maxs); + pmove.capsule = (sv_player->xv->geomtype == GEOMTYPE_CAPSULE); movevars.entgravity = 0; movevars.maxspeed = 0; @@ -6125,6 +6126,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse) pmove.physents[0].model = sv.world.worldmodel; pmove.cmd = *ucmd; pmove.skipent = -1; + pmove.capsule = (sv_player->xv->geomtype == GEOMTYPE_CAPSULE); movevars.entgravity = host_client->entgravity/movevars.gravity; movevars.maxspeed = host_client->maxspeed; diff --git a/engine/server/svhl_game.c b/engine/server/svhl_game.c index 7fe4a1614..2d673b42a 100644 --- a/engine/server/svhl_game.c +++ b/engine/server/svhl_game.c @@ -1655,6 +1655,7 @@ extern cvar_t temp1; pmove.physents[0].info = 0; pmove.skipent = -1; pmove.onladder = false; + pmove.capsule = false; if (ed->v.flags & (1<<24)) { diff --git a/engine/server/svq2_game.c b/engine/server/svq2_game.c index 12defbc56..6b6dba870 100644 --- a/engine/server/svq2_game.c +++ b/engine/server/svq2_game.c @@ -707,7 +707,7 @@ static int VARGS SVQ2_AreaEdicts (vec3_t mins, vec3_t maxs, q2edict_t **list, in static model_t *SVQ2_GetCModel(world_t *w, int modelindex) { - if ((unsigned int)modelindex < MAX_MODELS) + if ((unsigned int)modelindex < MAX_PRECACHE_MODELS) return sv.models[modelindex]; else return NULL; diff --git a/engine/server/svq3_game.c b/engine/server/svq3_game.c index a3a522658..5acb50ed9 100644 --- a/engine/server/svq3_game.c +++ b/engine/server/svq3_game.c @@ -156,7 +156,7 @@ static void Q3G_UnlinkEntity(q3sharedEntity_t *ent) static model_t *Q3G_GetCModel(unsigned int modelindex) { - if ((unsigned int)modelindex < MAX_MODELS) + if ((unsigned int)modelindex < MAX_PRECACHE_MODELS) { if (!sv.models[modelindex]) { @@ -416,7 +416,7 @@ static void SVQ3_Trace(q3trace_t *result, vec3_t start, vec3_t mins, vec3_t maxs if (!maxs) maxs = vec3_origin; - sv.world.worldmodel->funcs.NativeTrace(sv.world.worldmodel, 0, 0, NULL, start, end, mins, maxs, contentmask, &tr); + sv.world.worldmodel->funcs.NativeTrace(sv.world.worldmodel, 0, 0, NULL, start, end, mins, maxs, capsule, contentmask, &tr); result->allsolid = tr.allsolid; result->contents = tr.contents; VectorCopy(tr.endpos, result->endpos); @@ -476,7 +476,6 @@ static void SVQ3_Trace(q3trace_t *result, vec3_t start, vec3_t mins, vec3_t maxs if (es->r.bmodel) { - //FIXME, this is inefficient. mod = Q3G_GetCModel(es->s.modelindex); if (!mod) continue; @@ -484,9 +483,11 @@ static void SVQ3_Trace(q3trace_t *result, vec3_t start, vec3_t mins, vec3_t maxs } else { - mod = CM_TempBoxModel(es->r.mins, es->r.maxs); + if (es->r.svFlags & SVF_CAPSULE) + mod = CM_TempBoxModel(es->r.mins, es->r.maxs); + else + mod = CM_TempBoxModel(es->r.mins, es->r.maxs); tr = CM_TransformedBoxTrace(mod, start, end, mins, maxs, contentmask, es->r.currentOrigin, es->r.currentAngles); -// mod->funcs.Trace(mod, 0, 0, start, end, mins, maxs, &tr); } if (tr.fraction < result->fraction) { diff --git a/engine/server/world.c b/engine/server/world.c index f1517449d..945d3de77 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -46,7 +46,8 @@ typedef struct #ifdef Q2SERVER q2edict_t *q2passedict; #endif - int hullnum; + int hullnum; + qboolean capsule; } moveclip_t; /* @@ -119,6 +120,26 @@ hull_t *World_HullForBox (vec3_t mins, vec3_t maxs) return &box_hull; } +model_t mod_capsule; +qboolean World_BoxTrace(struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, unsigned int against, struct trace_s *trace) +{ + //bbox vs bbox (NYI) + //capsule vs bbox (NYI) + return false; +} +qboolean World_CapsuleTrace(struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace) +{ + //bbox vs capsule (NYI) + //capsule vs capsule (NYI) + return false; +} +model_t *World_CapsuleForBox(vec3_t mins, vec3_t maxs) +{ + VectorCopy(mins, mod_capsule.mins); + VectorCopy(maxs, mod_capsule.maxs); + mod_capsule.funcs.NativeTrace = World_CapsuleTrace; + return &mod_capsule; +} /* =============================================================================== @@ -910,7 +931,7 @@ qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, //wrapper function. Rotates the start and end positions around the angles if needed. //qboolean TransformedHullCheck (hull_t *hull, vec3_t start, vec3_t end, trace_t *trace, vec3_t angles) -qboolean TransformedTrace (struct model_s *model, int hulloverride, int frame, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, struct trace_s *trace, vec3_t origin, vec3_t angles, unsigned int hitcontentsmask) +qboolean World_TransformedTrace (struct model_s *model, int hulloverride, int frame, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, struct trace_s *trace, vec3_t origin, vec3_t angles, unsigned int hitcontentsmask) { vec3_t start_l, end_l; vec3_t axis[3]; @@ -929,71 +950,23 @@ qboolean TransformedTrace (struct model_s *model, int hulloverride, int frame, v return false; } - // don't rotate non bsp ents. Too small to bother. - if (model && !model->needload) - { - VectorSubtract (start, origin, start_l); - VectorSubtract (end, origin, end_l); - - if (angles[0] || angles[1] || angles[2]) - { - AngleVectors (angles, axis[0], axis[1], axis[2]); - VectorNegate(axis[1], axis[1]); - result = model->funcs.NativeTrace (model, hulloverride, frame, axis, start_l, end_l, mins, maxs, hitcontentsmask, trace); - } - else - { - result = model->funcs.NativeTrace (model, hulloverride, frame, NULL, start_l, end_l, mins, maxs, hitcontentsmask, trace); - } - - VectorAdd (trace->endpos, origin, trace->endpos); - } - else - { - hull_t *hull = &box_hull; - - memset (trace, 0, sizeof(trace_t)); - trace->fraction = 1; - trace->allsolid = true; - - VectorSubtract (start, origin, start_l); - VectorSubtract (end, origin, end_l); - VectorCopy (end_l, trace->endpos); - result = Q1BSP_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, trace); - VectorAdd (trace->endpos, origin, trace->endpos); - } - - return result; -} - -qboolean TransformedNativeTrace (struct model_s *model, int hulloverride, int frame, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int against, struct trace_s *trace, vec3_t origin, vec3_t angles) -{ - vec3_t start_l, end_l; - vec3_t axis[3]; - qboolean result; - - memset (trace, 0, sizeof(trace_t)); - trace->fraction = 1; - trace->allsolid = false; - trace->startsolid = false; - trace->inopen = true; //probably wrong... - VectorCopy (end, trace->endpos); - // don't rotate non bsp ents. Too small to bother. if (model) { VectorSubtract (start, origin, start_l); VectorSubtract (end, origin, end_l); + if (angles[0] || angles[1] || angles[2]) { AngleVectors (angles, axis[0], axis[1], axis[2]); VectorNegate(axis[1], axis[1]); - result = model->funcs.NativeTrace (model, hulloverride, frame, axis, start_l, end_l, mins, maxs, against, trace); + result = model->funcs.NativeTrace (model, hulloverride, frame, axis, start_l, end_l, mins, maxs, capsule, hitcontentsmask, trace); } else { - result = model->funcs.NativeTrace (model, hulloverride, frame, NULL, start_l, end_l, mins, maxs, against, trace); + result = model->funcs.NativeTrace (model, hulloverride, frame, NULL, start_l, end_l, mins, maxs, capsule, hitcontentsmask, trace); } + VectorAdd (trace->endpos, origin, trace->endpos); } else @@ -1022,7 +995,7 @@ Handles selection or creation of a clipping hull, and offseting (and eventually rotation) of the end points ================== */ -static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hullnum, qboolean hitmodel, unsigned int hitcontentsmask) //hullnum overrides min/max for q1 style bsps +static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hullnum, qboolean hitmodel, qboolean capsule, unsigned int hitcontentsmask) //hullnum overrides min/max for q1 style bsps { trace_t trace; model_t *model; @@ -1041,19 +1014,23 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v else model = NULL; - if (!model) + if (!model || model->needload) { vec3_t boxmins, boxmaxs; + model = NULL; VectorSubtract (ent->v->mins, maxs, boxmins); VectorSubtract (ent->v->maxs, mins, boxmaxs); - World_HullForBox(boxmins, boxmaxs); + if (ent->xv->geomtype == GEOMTYPE_CAPSULE && !hitmodel) + model = World_CapsuleForBox(boxmins, boxmaxs); + else + World_HullForBox(boxmins, boxmaxs); } // trace a line through the apropriate clipping hull 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); + World_TransformedTrace(model, 0, ent->v->frame, start, end, vec3_origin, vec3_origin, capsule, &trace, eorg, ent->v->angles, hitcontentsmask); if (trace.startsolid) //portals should not block traces. this prevents infinite looping trace.startsolid = false; hitmodel = false; @@ -1061,24 +1038,24 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v 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); + World_TransformedTrace(model, hullnum, ent->v->frame, start, end, mins, maxs, capsule, &trace, eorg, ent->v->angles, hitcontentsmask); ent->v->angles[0]*=-1; } else { - TransformedTrace(model, hullnum, ent->v->frame, start, end, mins, maxs, &trace, eorg, ent->v->angles, hitcontentsmask); + World_TransformedTrace(model, hullnum, ent->v->frame, start, end, mins, maxs, capsule, &trace, eorg, ent->v->angles, hitcontentsmask); } // if using hitmodel, we know it hit the bounding box, so try a proper trace now. - if (hitmodel && trace.fraction != 1 && ent->v->solid != SOLID_BSP && mdlidx != 0) + if (hitmodel && trace.fraction != 1 && !model) { //okay, we hit the bbox model = w->Get_CModel(w, mdlidx); - if (model && model->funcs.NativeTrace) + if (model && model->funcs.NativeTrace && !model->needload) { - //do the second trace - TransformedTrace(model, hullnum, ent->v->frame, start, end, mins, maxs, &trace, eorg, ent->v->angles, hitcontentsmask); + //do the second trace, using the actual mesh. + World_TransformedTrace(model, hullnum, ent->v->frame, start, end, mins, maxs, capsule, &trace, eorg, ent->v->angles, hitcontentsmask); } } @@ -1092,16 +1069,13 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v static trace_t WorldQ2_ClipMoveToEntity (world_t *w, q2edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, unsigned int hitcontentsmask) { trace_t trace; - model_t *model; + model_t *model = NULL; // get the clipping hull if (ent->s.solid == Q2SOLID_BSP) - { model = w->Get_CModel(w, ent->s.modelindex); - if (!model || model->type != mod_brush) - SV_Error("SOLID_BSP with non bsp model"); - } - else + + if (!model || model->type != mod_brush || model->needload) { vec3_t boxmins, boxmaxs; VectorSubtract (ent->mins, maxs, boxmins); @@ -1111,7 +1085,7 @@ static trace_t WorldQ2_ClipMoveToEntity (world_t *w, q2edict_t *ent, vec3_t star } // trace a line through the apropriate clipping hull - TransformedTrace(model, 0, 0, start, end, mins, maxs, &trace, ent->s.origin, ent->s.angles, hitcontentsmask); + World_TransformedTrace(model, 0, 0, start, end, mins, maxs, false, &trace, ent->s.origin, ent->s.angles, hitcontentsmask); // did we clip the move? if (trace.fraction < 1 || trace.startsolid ) @@ -1541,9 +1515,9 @@ static void World_ClipToEverything (world_t *w, moveclip_t *clip) } if ((int)touch->v->flags & FL_MONSTER) - trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->hitcontentsmask); + trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask); 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); + trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask); if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) { @@ -1648,9 +1622,9 @@ static void World_ClipToLinks (world_t *w, areanode_t *node, moveclip_t *clip) } if ((int)touch->v->flags & FL_MONSTER) - trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->hitcontentsmask); + trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask); 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); + trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask); if (trace.fraction < clip->trace.fraction) { @@ -1841,16 +1815,17 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e clip.hitcontentsmask = MASK_BOXSOLID; /*impacts playerclip*/ else clip.hitcontentsmask = MASK_POINTSOLID; /*ignores playerclip but hits everything else*/ + clip.capsule = (passedict->xv->geomtype == GEOMTYPE_CAPSULE); if (type & MOVE_ONLYENT) { if (!passedict) passedict = w->edicts; - return World_ClipMoveToEntity (w, passedict, passedict->v->origin, start, mins, maxs, end, hullnum, clip.type & MOVE_HITMODEL, clip.hitcontentsmask); + return World_ClipMoveToEntity (w, passedict, passedict->v->origin, start, mins, maxs, end, hullnum, type & MOVE_HITMODEL, clip.capsule, clip.hitcontentsmask); } // clip to world - clip.trace = World_ClipMoveToEntity (w, w->edicts, w->edicts->v->origin, start, mins, maxs, end, hullnum, false, clip.hitcontentsmask); + clip.trace = World_ClipMoveToEntity (w, w->edicts, w->edicts->v->origin, start, mins, maxs, end, hullnum, false, clip.capsule, clip.hitcontentsmask); clip.start = start; clip.end = end; @@ -1973,7 +1948,7 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e continue; // don't clip against owner } - trace = World_ClipMoveToEntity (w, touch, lp, clip.start, clip.mins, clip.maxs, clip.end, clip.hullnum, clip.type & MOVE_HITMODEL, clip.hitcontentsmask); + trace = World_ClipMoveToEntity (w, touch, lp, clip.start, clip.mins, clip.maxs, clip.end, clip.hullnum, clip.type & MOVE_HITMODEL, clip.capsule, clip.hitcontentsmask); if (trace.allsolid || trace.startsolid || trace.fraction < clip.trace.fraction) { @@ -2011,7 +1986,7 @@ trace_t WorldQ2_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t memset ( &clip, 0, sizeof ( moveclip_t ) ); // clip to world - w->worldmodel->funcs.NativeTrace(w->worldmodel, 0, 0, NULL, start, end, mins, maxs, hitcontentsmask, &clip.trace); + w->worldmodel->funcs.NativeTrace(w->worldmodel, 0, 0, NULL, start, end, mins, maxs, false, hitcontentsmask, &clip.trace); clip.trace.ent = ge->edicts; if (clip.trace.fraction == 0)