diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index fe3e4b27..623809bc 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -372,6 +372,15 @@ void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int bits, qboolean to->tagentity = MSG_ReadShort(); to->tagindex = MSG_ReadShort(); } + if (morebits & U_LIGHT) + { + to->light[0] = MSG_ReadShort(); + to->light[1] = MSG_ReadShort(); + to->light[2] = MSG_ReadShort(); + to->light[3] = MSG_ReadShort(); + to->lightstyle = MSG_ReadByte(); + to->lightpflags = MSG_ReadByte(); + } VectorSubtract(to->origin, from->origin, move); @@ -1500,6 +1509,10 @@ void CL_LinkPacketEntities (void) else if (s1->effects & EF_DIMLIGHT) CL_NewDlight (s1->number, s1->origin[0], s1->origin[1], s1->origin[2], 200 + flicker, 0, 0); } + if (s1->light[3]) + { + CL_NewDlightRGB (s1->number, s1->origin[0], s1->origin[1], s1->origin[2], s1->light[3], 0, s1->light[0]/1024.0f, s1->light[1]/1024.0f, s1->light[2]/1024.0f); + } // if set to invisible, skip if (s1->modelindex<1) diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 9323e4d3..6c07362e 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -890,13 +890,14 @@ int CL_RemoveClientCommands(char *command) { clcmdbuf_t *next, *first; int removed = 0; + int len = strlen(command); CL_AllowIndependantSendCmd(false); if (!clientcmdlist) return 0; - while(!strcmp(clientcmdlist->command, command)) + while(!strncmp(clientcmdlist->command, command, len)) { next = clientcmdlist->next; Z_Free(clientcmdlist); @@ -909,7 +910,7 @@ int CL_RemoveClientCommands(char *command) first = clientcmdlist; while(first->next) { - if (!strcmp(first->next->command, command)) + if (!strncmp(first->next->command, command, len)) { next = first->next->next; Z_Free(first->next); diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 5ead7d5b..7b690c62 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -369,6 +369,9 @@ void CL_SendConnectPacket ( #ifdef PEXT_CSQC fteprotextsupported |= PEXT_CSQC; #endif +#ifdef PEXT_DPFLAGS + fteprotextsupported |= PEXT_DPFLAGS; +#endif fteprotextsupported &= ftepext; @@ -1409,7 +1412,7 @@ void CL_SetInfo_f (void) if (cls.state >= ca_connected) { #ifdef Q2CLIENT - if (cls.protocol == CP_QUAKE2) + if (cls.protocol == CP_QUAKE2 || cls.protocol == CP_QUAKE3) cls.resendinfo = true; else #endif @@ -2186,7 +2189,7 @@ void CL_Download_f (void) if (Cmd_IsInsecure()) //mark server specified downloads. { - if (!strncmp(url, "game", 4) || !strcmp(url, "progs.dat") || !strcmp(url, "menu.dat") || !strcmp(url, "csqc.dat") || !strcmp(url, "qwprogs.dat") || strstr(url, "..") || strstr(url, ".dll") || strstr(url, ".so")) + if (!strnicmp(url, "game", 4) || !stricmp(url, "progs.dat") || !stricmp(url, "menu.dat") || !stricmp(url, "csprogs.dat") || !stricmp(url, "qwprogs.dat") || strstr(url, "..") || strstr(url, ".dll") || strstr(url, ".so")) { //yes, I know the user can use a different progs from the one that is specified. If you leave it blank there will be no problem. (server isn't allowed to stuff progs cvar) Con_Printf("Ignoring stuffed download of \"%s\" due to possible security risk\n", url); return; @@ -2632,7 +2635,7 @@ extern cvar_t cl_netfps; int nopacketcount; void SNDDMA_SetUnderWater(qboolean underwater); float CL_FilterTime (double time, float wantfps); -void Host_Frame (float time) +void Host_Frame (double time) { static double time1 = 0; static double time2 = 0; @@ -2640,7 +2643,7 @@ void Host_Frame (float time) int pass1, pass2, pass3; // float fps; float realframetime; - static float spare; + static double spare; RSpeedLocals(); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 9e5bfbc3..6b0557cb 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -680,6 +680,8 @@ void Sound_NextDownload (void) else #endif { + if (CL_RemoveClientCommands("modellist")) + Con_Printf("Multiple modellists\n"); // CL_SendClientCommand ("modellist %i 0", cl.servercount); CL_SendClientCommand (true, modellist_name, cl.servercount, 0); } @@ -1796,7 +1798,7 @@ void CL_ParseSoundlist (void) if (!str[0]) break; numsounds++; - if (numsounds == MAX_SOUNDS) + if (numsounds >= MAX_SOUNDS) Host_EndGame ("Server sent too many sound_precache"); // if (strlen(str)>4) @@ -1810,6 +1812,8 @@ void CL_ParseSoundlist (void) if (n) { + if (CL_RemoveClientCommands("soundlist")) + Con_Printf("Multiple soundlists\n"); // CL_SendClientCommand("soundlist %i %i", cl.servercount, n); CL_SendClientCommand(true, soundlist_name, cl.servercount, n); return; @@ -1843,7 +1847,7 @@ void CL_ParseModellist (qboolean lots) if (!str[0]) break; nummodels++; - if (nummodels==MAX_MODELS) + if (nummodels>=MAX_MODELS) Host_EndGame ("Server sent too many model_precache"); strcpy (cl.model_name[nummodels], str); diff --git a/engine/client/console.c b/engine/client/console.c index bac056f3..7ddae88d 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -1336,5 +1336,4 @@ void Con_NotifyBox (char *text) Con_Printf ("\n"); key_dest = key_game; - realtime = 0; // put the cursor back to invisible } diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 227065d5..c73cf9df 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -23,6 +23,7 @@ static csqctreadstate_t *csqcthreads; qboolean csqc_resortfrags; qboolean csqc_drawsbar; qboolean csqc_addcrosshair; +static int num_csqc_edicts; cvar_t pr_csmaxedicts = {"pr_csmaxedicts", "3072"}; cvar_t cl_csqcdebug = {"cl_csqcdebug", "0"}; //prints entity numbers which arrive (so I can tell people not to apply it to players...) @@ -147,6 +148,7 @@ static void CSQC_FindGlobals(void) fieldfloat(modelindex); \ fieldvector(origin); \ fieldvector(angles); \ + fieldvector(velocity); \ fieldfloat(alpha); /*transparency*/ \ fieldfloat(scale); /*model scale*/ \ fieldfloat(fatness); /*expand models X units along thier normals.*/ \ @@ -160,6 +162,8 @@ static void CSQC_FindGlobals(void) fieldfloat(lerpfrac); \ fieldfloat(renderflags);\ fieldfloat(forceshader);\ + fieldfloat(dimension_hit); \ + fieldfloat(dimension_solid); \ \ fieldfloat(drawmask); /*So that the qc can specify all rockets at once or all bannanas at once*/ \ fieldfunction(predraw); /*If present, is called just before it's drawn.*/ \ @@ -172,12 +176,14 @@ static void CSQC_FindGlobals(void) \ fieldentity(chain); \ fieldentity(groundentity); \ + fieldentity(owner); \ \ fieldfloat(solid); \ fieldvector(mins); \ fieldvector(maxs); \ - fieldvector(absmins); \ - fieldvector(absmaxs); \ + fieldvector(size); \ + fieldvector(absmin); \ + fieldvector(absmax); \ fieldfloat(hull); /*(FTE_PEXT_HEXEN2)*/ @@ -206,6 +212,7 @@ typedef struct csqcedict_s //add whatever you wish here trailstate_t *trailstate; + link_t area; } csqcedict_t; static csqcedict_t *csqc_edicts; //consider this 'world' @@ -342,69 +349,263 @@ void PF_fclose_progs (progfuncs_t *prinst); char *PF_VarString (progfuncs_t *prinst, int first, struct globalvars_s *pr_globals); int QCEditor (progfuncs_t *prinst, char *filename, int line, int nump, char **parms); +static model_t *CSQC_GetModelForIndex(int index); +static void CS_LinkEdict(csqcedict_t *ent, qboolean touchtriggers); - - - - -void CL_CS_LinkEdict(csqcedict_t *ent, qboolean touchtriggers) +areanode_t cs_areanodes[AREA_NODES]; +int cs_numareanodes; +areanode_t *CS_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs) { + areanode_t *anode; + vec3_t size; + vec3_t mins1, maxs1, mins2, maxs2; + + anode = &cs_areanodes[cs_numareanodes]; + cs_numareanodes++; + + ClearLink (&anode->trigger_edicts); + ClearLink (&anode->solid_edicts); + + if (depth == AREA_DEPTH) + { + anode->axis = -1; + anode->children[0] = anode->children[1] = NULL; + return anode; + } + + VectorSubtract (maxs, mins, size); + if (size[0] > size[1]) + anode->axis = 0; + else + anode->axis = 1; + + anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]); + VectorCopy (mins, mins1); + VectorCopy (mins, mins2); + VectorCopy (maxs, maxs1); + VectorCopy (maxs, maxs2); + + maxs1[anode->axis] = mins2[anode->axis] = anode->dist; + + anode->children[0] = CS_CreateAreaNode (depth+1, mins2, maxs2); + anode->children[1] = CS_CreateAreaNode (depth+1, mins1, maxs1); + + return anode; +} + +void CS_ClearWorld (void) +{ + int i; + + memset (cs_areanodes, 0, sizeof(cs_areanodes)); + cs_numareanodes = 0; + if (cl.worldmodel) + CS_CreateAreaNode (0, cl.worldmodel->mins, cl.worldmodel->maxs); + else + { + vec3_t mins, maxs; + int i; + for (i = 0; i < 3; i++) + { + mins[i] = -4096; + maxs[i] = 4096; + } + CS_CreateAreaNode (0, mins, maxs); + } + + for (i = 1; i < num_csqc_edicts; i++) + CS_LinkEdict((csqcedict_t*)EDICT_NUM(csqcprogs, i), false); +} + +void CS_UnlinkEdict (csqcedict_t *ent) +{ + if (!ent->area.prev) + return; // not linked in anywhere + RemoveLink (&ent->area); + ent->area.prev = ent->area.next = NULL; +} + +static void CS_LinkEdict(csqcedict_t *ent, qboolean touchtriggers) +{ + areanode_t *node; + + if (ent->area.prev) + CS_UnlinkEdict (ent); // unlink from old position + + if (ent == csqc_edicts) + return; // don't add the world + //FIXME: use some sort of area grid ? - VectorAdd(ent->v->origin, ent->v->mins, ent->v->absmins); - VectorAdd(ent->v->origin, ent->v->maxs, ent->v->absmaxs); + VectorAdd(ent->v->origin, ent->v->mins, ent->v->absmin); + VectorAdd(ent->v->origin, ent->v->maxs, ent->v->absmax); + + if ((int)ent->v->flags & FL_ITEM) + { + ent->v->absmin[0] -= 15; + ent->v->absmin[1] -= 15; + ent->v->absmax[0] += 15; + ent->v->absmax[1] += 15; + } + else + { // because movement is clipped an epsilon away from an actual edge, + // we must fully check even when bounding boxes don't quite touch + ent->v->absmin[0] -= 1; + ent->v->absmin[1] -= 1; + ent->v->absmin[2] -= 1; + ent->v->absmax[0] += 1; + ent->v->absmax[1] += 1; + ent->v->absmax[2] += 1; + } + + if (!ent->v->solid) + return; + + // find the first node that the ent's box crosses + node = cs_areanodes; + while (1) + { + if (node->axis == -1) + break; + if (ent->v->absmin[node->axis] > node->dist) + node = node->children[0]; + else if (ent->v->absmax[node->axis] < node->dist) + node = node->children[1]; + else + break; // crosses the node + } + +// link it in + + if (ent->v->solid == SOLID_TRIGGER) + InsertLinkBefore (&ent->area, &node->trigger_edicts); + else + InsertLinkBefore (&ent->area, &node->solid_edicts); +} + +typedef struct { + int type; + trace_t trace; + vec3_t boxmins; //mins/max of total move. + vec3_t boxmaxs; + vec3_t start; + vec3_t end; + vec3_t mins; //mins/max of ent + vec3_t maxs; + csqcedict_t *passedict; +} moveclip_t; +void CS_ClipToLinks ( areanode_t *node, moveclip_t *clip ) +{ + model_t *model; + trace_t tr; + link_t *l, *next; + csqcedict_t *touch; + + //work out who they are first. + for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next) + { + next = l->next; + touch = (csqcedict_t*)EDICT_FROM_AREA(l); + if (touch->v->solid == SOLID_NOT) + continue; + if (touch == clip->passedict) + continue; + if (touch->v->solid == SOLID_TRIGGER || touch->v->solid == SOLID_LADDER) + continue; + + if (clip->type & MOVE_NOMONSTERS && touch->v->solid != SOLID_BSP) + continue; + + if (clip->passedict) + { + // don't clip corpse against character + if (clip->passedict->v->solid == SOLID_CORPSE && (touch->v->solid == SOLID_SLIDEBOX || touch->v->solid == SOLID_CORPSE)) + continue; + // don't clip character against corpse + if (clip->passedict->v->solid == SOLID_SLIDEBOX && touch->v->solid == SOLID_CORPSE) + continue; + + if (!((int)clip->passedict->v->dimension_hit & (int)touch->v->dimension_solid)) + continue; + } + + if (clip->boxmins[0] > touch->v->absmax[0] + || clip->boxmins[1] > touch->v->absmax[1] + || clip->boxmins[2] > touch->v->absmax[2] + || clip->boxmaxs[0] < touch->v->absmin[0] + || clip->boxmaxs[1] < touch->v->absmin[1] + || clip->boxmaxs[2] < touch->v->absmin[2] ) + continue; + + if (clip->passedict && clip->passedict->v->size[0] && !touch->v->size[0]) + continue; // points never interact + + // might intersect, so do an exact clip + if (clip->trace.allsolid) + return; + if (clip->passedict) + { + if ((csqcedict_t*)PROG_TO_EDICT(svprogfuncs, touch->v->owner) == clip->passedict) + continue; // don't clip against own missiles + if ((csqcedict_t*)PROG_TO_EDICT(svprogfuncs, clip->passedict->v->owner) == touch) + continue; // don't clip against owner + } + + + if (!((int)clip->passedict->v->dimension_solid & (int)touch->v->dimension_hit)) + continue; + + model = CSQC_GetModelForIndex(touch->v->modelindex); + if (!model) + continue; + model->funcs.Trace(model, 0, 0, clip->start, clip->end, clip->mins, clip->maxs, &tr); + if (tr.fraction < clip->trace.fraction) + { + tr.ent = (void*)touch; + clip->trace = tr; + } + } } //FIXME: Not fully functional -trace_t CL_Move(vec3_t v1, vec3_t mins, vec3_t maxs, vec3_t v2, float nomonsters, csqcedict_t *passedict) +static trace_t CS_Move(vec3_t v1, vec3_t mins, vec3_t maxs, vec3_t v2, float nomonsters, csqcedict_t *passedict) { - int e; - csqcedict_t *ed; - vec3_t minb, maxb; - hull_t *hull; + moveclip_t clip; - trace_t trace, trace2; - - memset(&trace, 0, sizeof(trace)); - trace.fraction = 1; - cl.worldmodel->funcs.Trace(cl.worldmodel, 0, 0, v1, v2, mins, maxs, &trace); + if (cl.worldmodel) + { + cl.worldmodel->funcs.Trace(cl.worldmodel, 0, 0, v1, v2, mins, maxs, &clip.trace); + clip.trace.ent = (void*)csqc_edicts; + } + else + { + memset(&clip.trace, 0, sizeof(clip.trace)); + clip.trace.fraction = 1; + VectorCopy(v2, clip.trace.endpos); + clip.trace.ent = (void*)csqc_edicts; + } //why use trace.endpos instead? //so that if we hit a wall early, we don't have a box covering the whole world because of a shotgun trace. - minb[0] = ((v1[0] < trace.endpos[0])?v1[0]:trace.endpos[0]) - mins[0]-1; - minb[1] = ((v1[1] < trace.endpos[1])?v1[1]:trace.endpos[1]) - mins[1]-1; - minb[2] = ((v1[2] < trace.endpos[2])?v1[2]:trace.endpos[2]) - mins[2]-1; - maxb[0] = ((v1[0] > trace.endpos[0])?v1[0]:trace.endpos[0]) + maxs[0]+1; - maxb[1] = ((v1[1] > trace.endpos[1])?v1[1]:trace.endpos[1]) + maxs[1]+1; - maxb[2] = ((v1[2] > trace.endpos[2])?v1[2]:trace.endpos[2]) + maxs[2]+1; -/* - for (e=1; e < *csqcprogs->parms->sv_num_edicts; e++) - { - ed = (void*)EDICT_NUM(csqcprogs, e); - if (ed->isfree) - continue; //can't collide - if (!ed->v->solid) - continue; - if (ed->v->absmaxs[0] < minb[0] || - ed->v->absmaxs[1] < minb[1] || - ed->v->absmaxs[2] < minb[2] || - ed->v->absmins[0] > maxb[0] || - ed->v->absmins[1] > maxb[1] || - ed->v->absmins[2] > maxb[2]) - continue; + clip.boxmins[0] = ((v1[0] < clip.trace.endpos[0])?v1[0]:clip.trace.endpos[0]) - mins[0]-1; + clip.boxmins[1] = ((v1[1] < clip.trace.endpos[1])?v1[1]:clip.trace.endpos[1]) - mins[1]-1; + clip.boxmins[2] = ((v1[2] < clip.trace.endpos[2])?v1[2]:clip.trace.endpos[2]) - mins[2]-1; + clip.boxmaxs[0] = ((v1[0] > clip.trace.endpos[0])?v1[0]:clip.trace.endpos[0]) + maxs[0]+1; + clip.boxmaxs[1] = ((v1[1] > clip.trace.endpos[1])?v1[1]:clip.trace.endpos[1]) + maxs[1]+1; + clip.boxmaxs[2] = ((v1[2] > clip.trace.endpos[2])?v1[2]:clip.trace.endpos[2]) + maxs[2]+1; - hull = CL_HullForEntity(ed); - memset(&trace, 0, sizeof(trace)); - trace.fraction = 1; - TransformedHullCheck(hull, v1, v2, &trace2, ed->v->angles); - trace2.ent = (void*)ed; - if (trace2.fraction < trace.fraction) - trace = trace2; - } -*/ - return trace; + VectorCopy(mins, clip.mins); + VectorCopy(maxs, clip.maxs); + VectorCopy(v1, clip.start); + VectorCopy(v2, clip.end); + clip.passedict = passedict; + + CS_ClipToLinks(cs_areanodes, &clip); + return clip.trace; } - +void CS_CheckVelocity(csqcedict_t *ent) +{ +} static void PF_cs_remove (progfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -420,7 +621,7 @@ static void PF_cs_remove (progfuncs_t *prinst, struct globalvars_s *pr_globals) } P_DelinkTrailstate(&ed->trailstate); - + CS_UnlinkEdict(ed); ED_Free (prinst, (void*)ed); } @@ -608,6 +809,12 @@ static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out) out->frame1time = in->v->frame1time; out->frame2time = in->v->frame2time; + if (in->v->colormap > 0 && in->v->colormap <= MAX_CLIENTS) + { + out->colormap = cl.players[(int)in->v->colormap-1].translations; + out->scoreboard = &cl.players[(int)in->v->colormap-1]; + } + if (!in->v->alpha) out->alpha = 1; else @@ -619,7 +826,7 @@ static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out) out->skinnum = in->v->skin; out->fatness = in->v->fatness; #ifdef Q3SHADERS - out->forcedshader = *(int*)&in->v->forceshader; + out->forcedshader = *(struct shader_s**)&in->v->forceshader; #endif out->keynum = -1; @@ -988,7 +1195,7 @@ static void PF_cs_SetOrigin(progfuncs_t *prinst, struct globalvars_s *pr_globals VectorCopy(org, ent->v->origin); - CL_CS_LinkEdict(ent, false); + CS_LinkEdict(ent, false); } static void PF_cs_SetSize(progfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -1000,7 +1207,7 @@ static void PF_cs_SetSize(progfuncs_t *prinst, struct globalvars_s *pr_globals) VectorCopy(mins, ent->v->mins); VectorCopy(maxs, ent->v->maxs); - CL_CS_LinkEdict(ent, false); + CS_LinkEdict(ent, false); } static void PF_cs_traceline(progfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -1029,7 +1236,7 @@ static void PF_cs_traceline(progfuncs_t *prinst, struct globalvars_s *pr_globals savedhull = ent->v->hull; ent->v->hull = 0; - trace = CL_Move (v1, mins, maxs, v2, nomonsters, ent); + trace = CS_Move (v1, mins, maxs, v2, nomonsters, ent); ent->v->hull = savedhull; *csqcg.trace_allsolid = trace.allsolid; @@ -1062,7 +1269,7 @@ static void PF_cs_tracebox(progfuncs_t *prinst, struct globalvars_s *pr_globals) savedhull = ent->v->hull; ent->v->hull = 0; - trace = CL_Move (v1, mins, maxs, v2, nomonsters, ent); + trace = CS_Move (v1, mins, maxs, v2, nomonsters, ent); ent->v->hull = savedhull; *csqcg.trace_allsolid = trace.allsolid; @@ -1079,6 +1286,81 @@ static void PF_cs_tracebox(progfuncs_t *prinst, struct globalvars_s *pr_globals) *csqcg.trace_ent = EDICT_TO_PROG(prinst, (void*)csqc_edicts); } +static trace_t CS_Trace_Toss (csqcedict_t *tossent, csqcedict_t *ignore) +{ + int i; + int savedhull; + float gravity; + vec3_t move, end; + trace_t trace; + float maxvel = Cvar_Get("sv_maxvelocity", "2000", 0, "CSQC physics")->value; + + vec3_t origin, velocity; + + // this has to fetch the field from the original edict, since our copy is truncated + gravity = 1;//tossent->v->gravity; + if (!gravity) + gravity = 1.0; + gravity *= Cvar_Get("sv_gravity", "800", 0, "CSQC physics")->value * 0.05; + + VectorCopy (tossent->v->origin, origin); + VectorCopy (tossent->v->velocity, velocity); + + CS_CheckVelocity (tossent); + + savedhull = tossent->v->hull; + tossent->v->hull = 0; + for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds + { + velocity[2] -= gravity; + VectorScale (velocity, 0.05, move); + VectorAdd (origin, move, end); + trace = CS_Move (origin, tossent->v->mins, tossent->v->maxs, end, MOVE_NORMAL, tossent); + VectorCopy (trace.endpos, origin); + + CS_CheckVelocity (tossent); + + if (trace.fraction < 1 && trace.ent && (void*)trace.ent != ignore) + break; + } + tossent->v->hull = savedhull; + + trace.fraction = 0; // not relevant + return trace; +} +static void PF_cs_tracetoss (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + trace_t trace; + csqcedict_t *ent; + csqcedict_t *ignore; + + ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0); + if (ent == csqc_edicts) + Con_DPrintf("tracetoss: can not use world entity\n"); + ignore = (csqcedict_t*)G_EDICT(prinst, OFS_PARM1); + + trace = CS_Trace_Toss (ent, ignore); + + *csqcg.trace_allsolid = trace.allsolid; + *csqcg.trace_startsolid = trace.startsolid; + *csqcg.trace_fraction = trace.fraction; + *csqcg.trace_inwater = trace.inwater; + *csqcg.trace_inopen = trace.inopen; + VectorCopy (trace.endpos, csqcg.trace_endpos); + VectorCopy (trace.plane.normal, csqcg.trace_plane_normal); + pr_global_struct->trace_plane_dist = trace.plane.dist; + if (trace.ent) + *csqcg.trace_ent = EDICT_TO_PROG(prinst, trace.ent); + else + *csqcg.trace_ent = EDICT_TO_PROG(prinst, (void*)csqc_edicts); +} + +static int CS_PointContents(vec3_t org) +{ + if (!cl.worldmodel) + return FTECONTENTS_EMPTY; + return cl.worldmodel->hulls[0].funcs.HullPointContents(&cl.worldmodel->hulls[0], org); +} static void PF_cs_pointcontents(progfuncs_t *prinst, struct globalvars_s *pr_globals) { float *v; @@ -1086,7 +1368,7 @@ static void PF_cs_pointcontents(progfuncs_t *prinst, struct globalvars_s *pr_glo v = G_VECTOR(OFS_PARM0); - cont = cl.worldmodel->hulls[0].funcs.HullPointContents(&cl.worldmodel->hulls[0], v); + cont = CS_PointContents(v); if (cont & FTECONTENTS_SOLID) G_FLOAT(OFS_RETURN) = Q1CONTENTS_SOLID; else if (cont & FTECONTENTS_SKY) @@ -2093,14 +2375,14 @@ void PF_cs_droptofloor (progfuncs_t *prinst, struct globalvars_s *pr_globals) end[2] -= 512; VectorCopy (ent->v->origin, start); - trace = CL_Move (start, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent); + trace = CS_Move (start, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent); if (trace.fraction == 1 || trace.allsolid) G_FLOAT(OFS_RETURN) = 0; else { VectorCopy (trace.endpos, ent->v->origin); - CL_CS_LinkEdict (ent, false); + CS_LinkEdict (ent, false); ent->v->flags = (int)ent->v->flags | FL_ONGROUND; ent->v->groundentity = EDICT_TO_PROG(prinst, trace.ent); G_FLOAT(OFS_RETURN) = 1; @@ -2116,17 +2398,9 @@ static void PF_cs_copyentity (progfuncs_t *prinst, struct globalvars_s *pr_globa memcpy(out->v, in->v, csqcentsize); - CL_CS_LinkEdict (out, false); + CS_LinkEdict (out, false); } -//these are the builtins that still need to be added. -#define PF_cs_tracetoss PF_Fixme -#define PF_cs_gettaginfo PF_Fixme -#define PS_cs_setattachment PF_Fixme -#define PF_cs_break PF_Fixme -#define PF_cs_walkmove PF_Fixme -#define PF_cs_checkbottom PF_Fixme - static void PF_cl_playingdemo (progfuncs_t *prinst, struct globalvars_s *pr_globals) { G_FLOAT(OFS_RETURN) = !!cls.demoplayback; @@ -2269,6 +2543,94 @@ static void PF_shaderforname (progfuncs_t *prinst, struct globalvars_s *pr_globa #endif } +qboolean CS_CheckBottom (csqcedict_t *ent) +{ + int savedhull; + vec3_t mins, maxs, start, stop; + trace_t trace; + int x, y; + float mid, bottom; + + if (!cl.worldmodel) + return false; + + VectorAdd (ent->v->origin, ent->v->mins, mins); + VectorAdd (ent->v->origin, ent->v->maxs, maxs); + +// if all of the points under the corners are solid world, don't bother +// with the tougher checks +// the corners must be within 16 of the midpoint + start[2] = mins[2] - 1; + for (x=0 ; x<=1 ; x++) + for (y=0 ; y<=1 ; y++) + { + start[0] = x ? maxs[0] : mins[0]; + start[1] = y ? maxs[1] : mins[1]; + if (!(CS_PointContents (start) & FTECONTENTS_SOLID)) + goto realcheck; + } + +// c_yes++; + return true; // we got out easy + +realcheck: +// c_no++; +// +// check it for real... +// + start[2] = mins[2]; + +// the midpoint must be within 16 of the bottom + start[0] = stop[0] = (mins[0] + maxs[0])*0.5; + start[1] = stop[1] = (mins[1] + maxs[1])*0.5; + stop[2] = start[2] - 2*pm_stepheight; + trace = CS_Move (start, vec3_origin, vec3_origin, stop, true, ent); + + if (trace.fraction == 1.0) + return false; + mid = bottom = trace.endpos[2]; + +// the corners must be within 16 of the midpoint + for (x=0 ; x<=1 ; x++) + for (y=0 ; y<=1 ; y++) + { + start[0] = stop[0] = x ? maxs[0] : mins[0]; + start[1] = stop[1] = y ? maxs[1] : mins[1]; + + savedhull = ent->v->hull; + ent->v->hull = 0; + trace = CS_Move (start, vec3_origin, vec3_origin, stop, true, ent); + ent->v->hull = savedhull; + + if (trace.fraction != 1.0 && trace.endpos[2] > bottom) + bottom = trace.endpos[2]; + if (trace.fraction == 1.0 || mid - trace.endpos[2] > pm_stepheight) + return false; + } + +// c_yes++; + return true; +} +static void PF_cs_checkbottom (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + csqcedict_t *ent; + + ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0); + + G_FLOAT(OFS_RETURN) = CS_CheckBottom (ent); +} + +static void PF_cs_break (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + Con_Printf ("break statement\n"); +#ifdef TEXTEDITOR + (*prinst->pr_trace)++; +#endif +} + +static void PF_cs_walkmove (progfuncs_t *prinst, struct globalvars_s *pr_globals) +{ +} #define PF_FixTen PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme,PF_Fixme @@ -2277,6 +2639,10 @@ static void PF_shaderforname (progfuncs_t *prinst, struct globalvars_s *pr_globa //PF_cs_ - works in csqc only (dependant upon globals or fields) //PF_cl_ - works in csqc and menu (if needed...) +//these are the builtins that still need to be added. +#define PF_cs_gettaginfo PF_Fixme +#define PS_cs_setattachment PF_Fixme + //warning: functions that depend on globals are bad, mkay? static builtin_t csqc_builtins[] = { //0 @@ -2703,7 +3069,6 @@ static int csqc_numbuiltins = sizeof(csqc_builtins)/sizeof(csqc_builtins[0]); static jmp_buf csqc_abort; static progparms_t csqcprogparms; -static int num_csqc_edicts; @@ -2769,17 +3134,32 @@ void CSQC_Shutdown(void) qbyte *CSQC_PRLoadFile (char *path, void *buffer, int bufsize) { qbyte *file; - //pretend it doesn't - file = COM_LoadStackFile(path, buffer, bufsize); -#ifndef _DEBUG - if (!cls.demoplayback) //allow any csqc when playing a demo - if (!strcmp(path, "csprogs.dat")) //Fail to load any csprogs who's checksum doesn't match. - if (Com_BlockChecksum(buffer, com_filesize) != csqcchecksum) - return NULL; -#endif + if (!strcmp(path, "csprogs.dat")) + { + char newname[MAX_QPATH]; + _snprintf(newname, MAX_PATH, "csprogsvers/%x.dat", csqcchecksum); - return file; + file = COM_LoadStackFile(newname, buffer, bufsize); + if (file) + if (Com_BlockChecksum(file, com_filesize) == csqcchecksum) //and the user wasn't trying to be cunning. + return file; + + file = COM_LoadStackFile(path, buffer, bufsize); + if (!cls.demoplayback) //allow them to use csprogs.dat if playing a demo, and don't care about the checksum + { + if (Com_BlockChecksum(file, com_filesize) != csqcchecksum) + return NULL; //not valid + + //back it up + COM_WriteFile(newname, file, com_filesize); + } + + return file; + + } + + return COM_LoadStackFile(path, buffer, bufsize);; } double csqctime; @@ -2854,9 +3234,12 @@ qboolean CSQC_Init (unsigned int checksum) return false; } + num_csqc_edicts = 0; + CS_ClearWorld(); + PF_InitTempStrings(csqcprogs); - memset(csqcent, 0, sizeof(*csqcent)*maxcsqcentities); + memset(csqcent, 0, sizeof(*csqcent)*maxcsqcentities); //clear the server->csqc entity translations. csqcentsize = PR_InitEnts(csqcprogs, pr_csmaxedicts.value); diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h index a7f07f02..b4bd8fed 100644 --- a/engine/client/quakedef.h +++ b/engine/client/quakedef.h @@ -230,7 +230,7 @@ void Host_Shutdown(void); void VARGS Host_Error (char *error, ...); void VARGS Host_EndGame (char *message, ...); qboolean Host_SimulationTime(float time); -void Host_Frame (float time); +void Host_Frame (double time); void Host_Quit_f (void); void VARGS Host_ClientCommands (char *fmt, ...); void Host_ShutdownServer (qboolean crash); diff --git a/engine/client/r_part.c b/engine/client/r_part.c index 41e83d57..bce0d8d4 100644 --- a/engine/client/r_part.c +++ b/engine/client/r_part.c @@ -372,6 +372,7 @@ void P_ParticleEffect_f(void) particle_t *parts; beamseg_t *beamsegs; skytris_t *st; + qboolean settype = false; part_type_t *ptype; int pnum, assoc; @@ -688,7 +689,7 @@ void P_ParticleEffect_f(void) ptype->type = PT_DECAL; else ptype->type = PT_NORMAL; - + settype = true; } else if (!strcmp(var, "isbeam")) { @@ -876,14 +877,17 @@ void P_ParticleEffect_f(void) if (ptype->friction) ptype->flags |= PT_FRICTION; - if (ptype->type == PT_NORMAL && !*ptype->texname) - ptype->type = PT_SPARK; - if (ptype->type == PT_SPARK) + if (!settype) { - if (*ptype->texname) - ptype->type = PT_TEXTUREDSPARK; - if (ptype->scale) - ptype->type = PT_SPARKFAN; + if (ptype->type == PT_NORMAL && !*ptype->texname) + ptype->type = PT_SPARK; + if (ptype->type == PT_SPARK) + { + if (*ptype->texname) + ptype->type = PT_TEXTUREDSPARK; + if (ptype->scale) + ptype->type = PT_SPARKFAN; + } } if (ptype->rampmode && !ptype->ramp) diff --git a/engine/client/renderer.c b/engine/client/renderer.c index bc81f1d3..5aa3c37a 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -1267,6 +1267,7 @@ void R_SetRenderer(int wanted) VID_SetPalette = ri->VID_SetPalette; VID_ShiftPalette = ri->VID_ShiftPalette; VID_GetRGBInfo = ri->VID_GetRGBInfo; + VID_SetWindowCaption = ri->VID_SetWindowCaption; Media_ShowFrame8bit = ri->Media_ShowFrame8bit; Media_ShowFrameRGBA_32 = ri->Media_ShowFrameRGBA_32; diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index b47200a0..2d3f7afd 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -697,8 +697,7 @@ void Sys_InitFloatTime (void) } #endif -// DWORD starttime; -double Sys_DoubleTime (void) +unsigned int Sys_Milliseconds (void) { static DWORD starttime; static qboolean first = true; @@ -712,19 +711,24 @@ double Sys_DoubleTime (void) starttime = now; return 0.0; } - + /* if (now < starttime) // wrapped? { double r; - r = (now / 1000.0) + (LONG_MAX - starttime / 1000.0); + r = (now) + (LONG_MAX - starttime); starttime = now; return r; } if (now - starttime == 0) return 0.0; +*/ + return (now - starttime); +} - return (now - starttime) / 1000.0; +double Sys_DoubleTime (void) +{ + return Sys_Milliseconds()/1000.f; } @@ -1090,21 +1094,14 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin { SV_Init (&parms); - SV_Frame (0.1); + SV_Frame (); - oldtime = Sys_DoubleTime () - 0.1; while (1) { if (!isDedicated) Sys_Error("Dedicated was cleared"); - NET_Sleep(100, false); - - // find time passed since last cycle - newtime = Sys_DoubleTime (); - time = newtime - oldtime; - oldtime = newtime; - - SV_Frame (time); + NET_Sleep(100, false); + SV_Frame (); } return TRUE; } @@ -1141,7 +1138,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin time = newtime - oldtime; oldtime = newtime; - SV_Frame (time); + SV_Frame (); } else #endif diff --git a/engine/common/common.c b/engine/common/common.c index 50fa04d4..ffb496e6 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -3046,6 +3046,12 @@ int COM_FOpenFile(char *filename, FILE **file) *file = NULL; return com_filesize; } +int COM_FOpenWriteFile(char *filename, FILE **file) +{ + COM_CreatePath(filename); + *file = fopen(filename, "wb"); + return !!*file; +} //int COM_FOpenFile (char *filename, FILE **file) {file_from_pak=0;return COM_FOpenFile2 (filename, file, false);} //FIXME: TEMPORARY diff --git a/engine/common/common.h b/engine/common/common.h index 04ca8502..b11aba85 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -280,6 +280,11 @@ typedef enum {FSLFRT_LENGTH, FSLFRT_DEPTH_OSONLY, FSLFRT_DEPTH_ANYPATH} FSLF_Ret int FS_FLocateFile(char *filename, FSLF_ReturnType_e returntype, flocation_t *loc); int COM_FOpenFile (char *filename, FILE **file); +int COM_FOpenWriteFile (char *filename, FILE **file); + +//#ifdef _MSC_VER //this is enough to annoy me, without conflicting with other (more bizzare) platforms. +//#define fopen dont_use_fopen +//#endif void COM_CloseFile (FILE *h); diff --git a/engine/common/cvar.c b/engine/common/cvar.c index cb17ea06..91ab3cb5 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -238,7 +238,7 @@ cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force) if (cls.state >= ca_connected) { #ifdef Q2CLIENT - if (cls.protocol == CP_QUAKE2) //q2 just resends the lot. Kinda bad... + if (cls.protocol == CP_QUAKE2 || cls.protocol == CP_QUAKE3) //q2 just resends the lot. Kinda bad... { cls.resendinfo = true; } diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index d7075a86..816cca00 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -1893,6 +1893,9 @@ void CModQ3_LoadSubmodels (lump_t *l) } //submodels } + + VectorCopy(map_cmodels[0].mins, loadmodel->mins); + VectorCopy(map_cmodels[0].maxs, loadmodel->maxs); } void CModQ3_LoadShaders (lump_t *l, qboolean useshaders) diff --git a/engine/common/protocol.h b/engine/common/protocol.h index 5ffb028d..9e15f529 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -443,6 +443,7 @@ enum clcq2_ops_e #define U_DPFLAGS (1<<11) #define U_TAGINFO (1<<12) +#define U_LIGHT (1<<13) #define U_FARMORE (1<<15) @@ -696,6 +697,10 @@ typedef struct entity_state_s qbyte dpflags; qbyte solid; + unsigned short light[4]; + qbyte lightstyle; + qbyte lightpflags; + unsigned short tagentity; unsigned short tagindex; } entity_state_t; diff --git a/engine/common/qvm.c b/engine/common/qvm.c index e4953381..1f0b16ee 100644 --- a/engine/common/qvm.c +++ b/engine/common/qvm.c @@ -435,9 +435,6 @@ qvm_t *QVM_Load(const char *name, sys_callex_t syscall) qvm->ds_mask--; - - qvm->ds_mask=0xFFFFFFFF; // FIXME: make real mask to fit ds+ss size - // load instructions { qbyte *src=raw+header->codeOffset; @@ -566,9 +563,6 @@ static void inline QVM_Enter(qvm_t *vm, long size) { long *fp; - if (size&3) - Con_Printf("QVM_Enter: size&3\n"); - vm->bp-=size; if(vm->bplen_ds) Sys_Error("VM run time error: out of stack\n"); @@ -587,9 +581,6 @@ static void inline QVM_Return(qvm_t *vm, long size) { long *fp; - if (size&3) - Con_Printf("QVM_Return: size&3\n"); - fp=(long*)(vm->ds+vm->bp); vm->bp+=size; @@ -624,13 +615,18 @@ int QVM_Exec(register qvm_t *qvm, int command, int arg0, int arg1, int arg2, int //all stack shifts in this function are referenced through these 2 macros. #define POP(t) qvm->sp+=t;if (qvm->sp > stackstart) Sys_Error("QVM Stack underflow"); #define PUSH(v) qvm->sp--;if (qvm->sp < stackend) Sys_Error("QVM Stack overflow");*qvm->sp=v - register qvm_op_t op=-1; - register unsigned long param; + qvm_op_t op=-1; + unsigned long param; long *fp; unsigned long *stackstart; unsigned long *stackend; + static int recurse = 0; + + if (recurse++) + Host_EndGame("QVM recursivly entered\n"); + stackstart = (unsigned long*)(qvm->ss+qvm->len_ss); stackend = (unsigned long*)(qvm->ss); @@ -689,6 +685,7 @@ int QVM_Exec(register qvm_t *qvm, int command, int arg0, int arg1, int arg2, int if (!qvm->pc) { // pick return value from stack + recurse--; return qvm->sp[0]; } break; diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index d3dbe0e0..5f36bd96 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -1181,6 +1181,9 @@ void GLDraw_Character (int x, int y, unsigned int num) draw_mesh_st[3][0] = fcol; draw_mesh_st[3][1] = frow+size; + qglEnable(GL_BLEND); + qglDisable(GL_ALPHA_TEST); + if (num&CON_2NDCHARSETTEXT) GL_DrawMesh(&draw_mesh, char_tex2); else @@ -1440,6 +1443,9 @@ void GLDraw_Pic (int x, int y, mpic_t *pic) draw_mesh_st[3][0] = gl->sl; draw_mesh_st[3][1] = gl->th; + qglDisable(GL_ALPHA_TEST); + qglEnable(GL_BLEND); + GL_DrawMesh(&draw_mesh, gl->texnum); } diff --git a/engine/gl/gl_ppl.c b/engine/gl/gl_ppl.c index 9a8ecd32..5496bf98 100644 --- a/engine/gl/gl_ppl.c +++ b/engine/gl/gl_ppl.c @@ -1824,6 +1824,9 @@ void PPL_DrawEnt(entity_t *e, void *parm) qglEnd(); currententity = e; + qglDepthMask(1); + qglDisable(GL_POLYGON_OFFSET_FILL); + R_IBrokeTheArrays(); R_DrawGAliasModel (currententity); diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 40636063..5eab890b 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -341,7 +341,7 @@ qboolean R_CullSphere (vec3_t org, float radius) void R_RotateForEntity (entity_t *e) { float m[16]; - if (e->flags & Q2RF_WEAPONMODEL) + if (e->flags & Q2RF_WEAPONMODEL && r_refdef.currentplayernum>=0) { //rotate to view first m[0] = cl.viewent[r_refdef.currentplayernum].axis[0][0]; m[1] = cl.viewent[r_refdef.currentplayernum].axis[0][1]; @@ -800,7 +800,7 @@ void GLR_DrawEntitiesOnList (void) switch (currententity->model->type) { case mod_alias: - if (r_refdef.flags & 1 || !cl.worldmodel || cl.worldmodel->fromgame == fg_doom) + if (r_refdef.flags & Q2RDF_NOWORLDMODEL || !cl.worldmodel || cl.worldmodel->fromgame == fg_doom) R_DrawGAliasModel (currententity); break; @@ -1159,7 +1159,7 @@ void GLR_SetupFrame (void) VectorCopy (r_refdef.vieworg, r_origin); // current viewleaf - if (r_refdef.flags & 1) + if (r_refdef.flags & Q2RDF_NOWORLDMODEL) { } #ifdef Q2BSPS @@ -1501,7 +1501,7 @@ void R_RenderScene (void) TRACE(("dbg: calling R_SetFrustrum\n")); R_SetFrustum (); - if (!(r_refdef.flags & 1)) + if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL)) { #ifdef DOOMWADS if (!GLR_DoomWorld ()) @@ -1527,7 +1527,7 @@ void R_RenderScene (void) TRACE(("dbg: calling R_RenderDlights\n")); R_RenderDlights (); - if (cl.worldmodel) + if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL)) { TRACE(("dbg: calling R_DrawParticles\n")); P_DrawParticles (); @@ -1548,6 +1548,7 @@ R_Clear int gldepthfunc = GL_LEQUAL; void R_Clear (void) { + qglDepthMask(1); if (r_mirroralpha.value != 1.0) { if (gl_clear.value && !r_secondaryview) @@ -1566,7 +1567,7 @@ void R_Clear (void) { static int trickframe; - if (gl_clear.value && !(r_refdef.flags & 1)) + if (gl_clear.value && !(r_refdef.flags & Q2RDF_NOWORLDMODEL)) qglClear (GL_COLOR_BUFFER_BIT); trickframe++; @@ -1585,7 +1586,7 @@ void R_Clear (void) } else { - if (gl_clear.value && !r_secondaryview) + if (gl_clear.value && !r_secondaryview && !(r_refdef.flags & Q2RDF_NOWORLDMODEL)) qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); else qglClear (GL_DEPTH_BUFFER_BIT); @@ -1989,7 +1990,7 @@ void GLR_RenderView (void) return; } - if (!(r_refdef.flags & 1)) + if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL)) if (!r_worldentity.model || !cl.worldmodel) { GL_DoSwap(); diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index a43f6adc..69a8fc0a 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -9486,6 +9486,11 @@ void PR_RegisterFields(void) //it's just easier to do it this way. fieldfloat(glow_color); fieldfloat(glow_trail); + fieldvector(color); + fieldfloat(light_lev); + fieldfloat(style); + fieldfloat(pflags); + //UDC_EXTEFFECT... yuckie PR_RegisterFieldVar(svprogfuncs, ev_float, "fieldcolor", (int)&((entvars_t*)0)->seefcolour, -1); PR_RegisterFieldVar(svprogfuncs, ev_float, "fieldsizex", (int)&((entvars_t*)0)->seefsizex, -1); diff --git a/engine/server/progdefs.h b/engine/server/progdefs.h index 8851c539..e8de9523 100644 --- a/engine/server/progdefs.h +++ b/engine/server/progdefs.h @@ -194,6 +194,11 @@ typedef struct entvars_s float glow_color; float glow_trail; + vec3_t color; + float light_lev; + float style; + float pflags; + //EXT_DIMENSION_VISIBLE float dimension_see; float dimension_seen; diff --git a/engine/server/savegame.c b/engine/server/savegame.c index 93635721..b7032fd2 100644 --- a/engine/server/savegame.c +++ b/engine/server/savegame.c @@ -490,7 +490,7 @@ qboolean SV_LoadLevelCache(char *level, char *startspot, qboolean ignoreplayers) gametype = cache->gametype; - sprintf (name, "%s/saves/%s", com_gamedir, level); + sprintf (name, "saves/%s", level); COM_DefaultExtension (name, ".lvc"); // Con_TPrintf (STL_LOADGAMEFROM, name); @@ -519,7 +519,7 @@ qboolean SV_LoadLevelCache(char *level, char *startspot, qboolean ignoreplayers) // been used. The menu calls it before stuffing loadgame command // SCR_BeginLoadingPlaque (); - f = fopen (name, "rb"); + COM_FOpenFile(name, &f); if (!f) { Con_TPrintf (STL_ERRORCOULDNTOPEN); diff --git a/engine/server/server.h b/engine/server/server.h index cab978ef..39e280f0 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -106,6 +106,7 @@ typedef struct qboolean csqcdebug; double time; + double starttime; float physicstime; //nq clients do so much better with times sent with physics than real. int framenum; @@ -312,6 +313,13 @@ typedef struct //merge? int num_entities; int first_entity; // into the circular sv_packet_entities[] int senttime; // for ping calculations + + + int serverMessageNum; + int serverCommandNum; + int serverTime; // server time the message is valid for (in msec) + int localTime; + int deltaFrame; } q3client_frame_t; #endif @@ -863,7 +871,7 @@ extern FILE *sv_fraglogfile; // void VARGS SV_Error (char *error, ...); void SV_Shutdown (void); -void SV_Frame (float time); +void SV_Frame (void); void SV_FinalMessage (char *message); void SV_DropClient (client_t *drop); struct quakeparms_s; diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index 07daa083..8639a77a 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -527,12 +527,15 @@ void SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qb if (to->glowsize != from->glowsize) to->dpflags |= 4; - if (to->dpflags != from->dpflags) + if (to->dpflags != from->dpflags && protext & PEXT_DPFLAGS) evenmorebits |= U_DPFLAGS; - if (to->tagentity != from->tagentity || to->tagindex != from->tagindex) + if ((to->tagentity != from->tagentity || to->tagindex != from->tagindex) && protext & PEXT_DPFLAGS) evenmorebits |= U_TAGINFO; + if ((to->light[0] != from->light[0] || to->light[1] != from->light[1] || to->light[2] != from->light[2] || to->light[3] != from->light[3] || to->lightstyle != from->lightstyle || to->lightpflags != from->lightstyle) && protext & PEXT_DPFLAGS) + evenmorebits |= U_LIGHT; + if (evenmorebits&0xff00) evenmorebits |= U_YETMORE; if (evenmorebits&0x00ff) @@ -622,6 +625,15 @@ void SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qb MSG_WriteShort (msg, to->tagindex); } + if (evenmorebits & U_LIGHT) + { + MSG_WriteShort (msg, to->light[0]); + MSG_WriteShort (msg, to->light[1]); + MSG_WriteShort (msg, to->light[2]); + MSG_WriteShort (msg, to->light[3]); + MSG_WriteByte (msg, to->lightstyle); + MSG_WriteByte (msg, to->lightpflags); + } } /* @@ -826,8 +838,8 @@ void SVDP_EmitEntity(entity_state_t *from, entity_state_t *to, sizebuf_t *msg, q bits |= E5_COLORMAP; if (from->tagentity != to->tagentity || from->tagindex != to->tagindex) bits |= E5_ATTACHMENT; -// if (from->light[0] != to->light[0] || o->light[1] != to->light[1] || o->light[2] != to->light[2] || o->light[3] != to->light[3] || o->lightstyle != to->lightstyle || o->lightpflags != to->lightpflags) -// bits |= E5_LIGHT; + if (from->light[0] != to->light[0] || from->light[1] != to->light[1] || from->light[2] != to->light[2] || from->light[3] != to->light[3] || from->lightstyle != to->lightstyle || from->lightpflags != to->lightpflags) + bits |= E5_LIGHT; if (from->glowsize != to->glowsize || from->glowcolour != to->glowcolour) bits |= E5_GLOW; // if (from->colormod[0] != to->colormod[0] || o->colormod[1] != to->colormod[1] || o->colormod[2] != to->colormod[2]) @@ -937,15 +949,15 @@ void SVDP_EmitEntity(entity_state_t *from, entity_state_t *to, sizebuf_t *msg, q MSG_WriteShort(msg, to->tagentity); MSG_WriteByte(msg, to->tagindex); } -// if (bits & E5_LIGHT) -// { -// MSG_WriteShort(msg, to->light[0]); -// MSG_WriteShort(msg, to->light[1]); -// MSG_WriteShort(msg, to->light[2]); -// MSG_WriteShort(msg, to->light[3]); -// MSG_WriteByte(msg, to->lightstyle); -// MSG_WriteByte(msg, to->lightpflags); -// } + if (bits & E5_LIGHT) + { + MSG_WriteShort(msg, to->light[0]); + MSG_WriteShort(msg, to->light[1]); + MSG_WriteShort(msg, to->light[2]); + MSG_WriteShort(msg, to->light[3]); + MSG_WriteByte(msg, to->lightstyle); + MSG_WriteByte(msg, to->lightpflags); + } if (bits & E5_GLOW) { MSG_WriteByte(msg, to->glowsize); @@ -2646,7 +2658,15 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore state->abslight = (int)(ent->v->abslight*255) & 255; state->tagentity = ent->v->tag_entity; state->tagindex = ent->v->tag_index; - if ((int)ent->v->flags & FL_CLASS_DEPENDENT && client->playerclass) + + state->light[0] = ent->v->color[0]*255; + state->light[1] = ent->v->color[1]*255; + state->light[2] = ent->v->color[2]*255; + state->light[3] = ent->v->light_lev; + state->lightstyle = ent->v->style; + state->lightpflags = ent->v->pflags; + + if ((int)ent->v->flags & FL_CLASS_DEPENDENT && client->playerclass) //hexen2 wierdness. { char modname[MAX_QPATH]; Q_strncpyz(modname, sv.model_precache[state->modelindex], sizeof(modname)); diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 978cfc03..b4424799 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -635,8 +635,19 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us Cvar_ApplyLatches(CVAR_LATCH); +//work out the gamespeed + sv.gamespeed = sv_gamespeed.value; + Info_SetValueForStarKey(svs.info, "*gamespeed", va("%i", (int)(sv.gamespeed*100)), MAX_SERVERINFO_STRING); + sv.gamespeed = atof(Info_ValueForKey(svs.info, "*gamespeed"))/100; + if (sv.gamespeed < 0.1 || sv.gamespeed == 1) + { + sv.gamespeed = 1; + Info_SetValueForStarKey(svs.info, "*gamespeed", "", MAX_SERVERINFO_STRING); + } +//reset the server time. sv.time = 0.1; //some progs don't like time starting at 0. //cos of spawn funcs like self.nextthink = time... + sv.starttime = Sys_DoubleTime(); COM_FlushTempoaryPacks(); @@ -698,15 +709,6 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us Info_SetValueForStarKey(svs.info, "*cheats", "", MAX_SERVERINFO_STRING); } - sv.gamespeed = sv_gamespeed.value; - Info_SetValueForStarKey(svs.info, "*gamespeed", va("%i", (int)(sv.gamespeed*100)), MAX_SERVERINFO_STRING); - sv.gamespeed = atof(Info_ValueForKey(svs.info, "*gamespeed"))/100; - if (sv.gamespeed < 0.1 || sv.gamespeed == 1) - { - sv.gamespeed = 1; - Info_SetValueForStarKey(svs.info, "*gamespeed", "", MAX_SERVERINFO_STRING); - } - //do we allow csprogs? #ifdef PEXT_CSQC file = COM_LoadTempFile("csprogs.dat"); @@ -868,6 +870,11 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us } sv.allocated_client_slots = i; break; +#endif +#ifdef Q3SERVER + case GT_QUAKE3: + sv.allocated_client_slots = 32; + break; #endif } @@ -1069,6 +1076,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us #endif realtime += 0.1; sv.time += 0.1; + sv.starttime -= 0.1; SV_Physics (); #ifndef SERVERONLY diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 2ca2d032..58ee2996 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -2304,7 +2304,7 @@ void SV_WriteIP_f (void) Con_Printf ("Writing %s.\n", name); - f = fopen (name, "wb"); + COM_FOpenWriteFile(name, &f); if (!f) { Con_Printf ("Couldn't open %s\n", name); @@ -2692,10 +2692,11 @@ SV_Frame ================== */ -void SV_Frame (float time) +void SV_Frame (void) { extern cvar_t pr_imitatemvdsv; static double start, end; + float oldtime; start = Sys_DoubleTime (); svs.stats.idle += start - end; @@ -2708,15 +2709,26 @@ void SV_Frame (float time) sv.gamespeed = 1; // decide the simulation time - if (!sv.paused) { + { + oldtime = sv.time; + sv.time = (Sys_DoubleTime() - sv.starttime)*sv.gamespeed; + if (sv.time < oldtime) + sv.time = oldtime; //urm + + if (sv.paused) + { + sv.starttime += sv.time - oldtime; //move the offset + sv.time = oldtime; //and keep time as it was. + } + #ifndef SERVERONLY if (isDedicated) #endif - realtime += time; + realtime += sv.time - oldtime; - time *= sv.gamespeed; - sv.time += time; } + + #ifdef IWEB_H__ IWebRun(); #endif @@ -3074,6 +3086,9 @@ void SV_InitLocal (void) #ifdef PEXT_CSQC svs.fteprotocolextensions |= PEXT_CSQC; #endif +#ifdef PEXT_DPFLAGS + svs.fteprotocolextensions |= PEXT_DPFLAGS; +#endif // if (svs.protocolextensions) // Info_SetValueForStarKey (svs.info, "*"DISTRIBUTION"_ext", va("%x", svs.protocolextensions), MAX_SERVERINFO_STRING); diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 1182120f..f35316c2 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -3919,7 +3919,6 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse) if (progstype == PROG_H2) sv_player->v->light_level = 128; //hmm... HACK!!! - sv_player->v->Version++; sv_player->v->button0 = ucmd->buttons & 1; sv_player->v->button2 = (ucmd->buttons >> 1) & 1; if (pr_allowbutton1.value) //many mods use button1 - it's just a wasted field to many mods. So only work it if the cvar allows.