/* Copyright (C) 1996-1997 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // sv_main.c -- server main program #include "quakedef.h" server_t sv; server_static_t svs; char localmodels[MAX_MODELS][5]; // inline model names for precache //============================================================================ cvar_t sv_dismin = {"sv_dismin", "0.1", false};//Tei default /* =============== SV_Init =============== */ // Tei stepsize extern cvar_t sv_stepsize; // Tei stepsize // Tei autoanimagic extern int eval_autoanimagic; extern int eval_autoanimagic_lowframe; // Tei autoanimagic void R_Beam (vec3_t origin, vec3_t end) ; //extern cvar_t r_waterwarp;//Tei / Fritz waterwarp extern cvar_t sp_nofarsound; void SV_Init (void) { int i; extern cvar_t sv_maxvelocity; extern cvar_t sv_gravity; extern cvar_t sv_nostep; extern cvar_t sv_friction; extern cvar_t sv_edgefriction; extern cvar_t sv_stopspeed; extern cvar_t sv_maxspeed; extern cvar_t sv_accelerate; extern cvar_t sv_idealpitchscale; extern cvar_t sv_aim; // Tei custom sky extern cvar_t sv_skyvalue; extern cvar_t sv_skydim; extern cvar_t sv_skyspeedscale; extern cvar_t sv_skyflattern; extern cvar_t mod_smartroute; // Tei custom sky // Tei autolava extern cvar_t r_autolightday; extern cvar_t r_autofogwater; extern cvar_t r_autobubbleglobal; extern cvar_t r_autolava; extern cvar_t r_autotele; extern cvar_t r_autosnow; extern cvar_t r_autorain; extern cvar_t r_autometeor; extern cvar_t r_autozing; extern cvar_t r_autobubbles; extern cvar_t r_autograss; extern cvar_t r_grassdensity; extern cvar_t r_grasspeed; extern cvar_t r_autohell; extern cvar_t r_autofogfog; extern cvar_t r_autowindx; extern cvar_t r_autowindy; extern cvar_t r_autowindz; extern cvar_t r_autofoot; // Tei autolava Cvar_RegisterVariable (&sv_maxvelocity); Cvar_RegisterVariable (&sv_gravity); Cvar_RegisterVariable (&sv_friction); Cvar_RegisterVariable (&mod_smartroute);//Tei smarter routing Cvar_RegisterVariable (&sv_edgefriction); Cvar_RegisterVariable (&sv_stopspeed); Cvar_RegisterVariable (&sv_maxspeed); Cvar_RegisterVariable (&sv_accelerate); Cvar_RegisterVariable (&sv_idealpitchscale); Cvar_RegisterVariable (&sv_aim); Cvar_RegisterVariable (&sv_nostep); Cvar_RegisterVariable (&sp_nofarsound);//Tei optimization for singleplayer Cvar_RegisterVariable (&impaim); // Tomaz - Improved Aiming //.. tei, moved here to try to fix dm problems. // Tei stepsize Cvar_RegisterVariable (&sv_stepsize); // Tei stepsize // Tei custom Sky Cvar_RegisterVariable (&sv_skyvalue); Cvar_RegisterVariable (&sv_skydim); Cvar_RegisterVariable (&sv_skyspeedscale); Cvar_RegisterVariable (&sv_skyflattern); // Tei custom Sky // Tei autofx Cvar_RegisterVariable (&sv_dismin);//Dx min for update Cvar_RegisterVariable (&r_autolava); Cvar_RegisterVariable (&r_autohell);//for fun Cvar_RegisterVariable (&r_autotele); Cvar_RegisterVariable (&r_autosnow); Cvar_RegisterVariable (&r_autorain); Cvar_RegisterVariable (&r_autometeor); Cvar_RegisterVariable (&r_autofogwater); Cvar_RegisterVariable (&r_autofogfog); Cvar_RegisterVariable (&r_autowindx); Cvar_RegisterVariable (&r_autowindy); Cvar_RegisterVariable (&r_autowindz); Cvar_RegisterVariable (&r_autobubbleglobal); Cvar_RegisterVariable (&r_autolightday); Cvar_RegisterVariable (&r_autozing); Cvar_RegisterVariable (&r_autobubbles); Cvar_RegisterVariable (&r_autofoot); Cvar_RegisterVariable (&r_autograss); Cvar_RegisterVariable (&r_grassdensity); Cvar_RegisterVariable (&r_grasspeed); // Tei autofx // Cvar_RegisterVariable (&r_waterwarp);//Tei / Fitz waterwarp for (i=0 ; i MAX_DATAGRAM-16) return; MSG_WriteByte (&sv.datagram, svc_particle); MSG_WriteCoord (&sv.datagram, org[0]); MSG_WriteCoord (&sv.datagram, org[1]); MSG_WriteCoord (&sv.datagram, org[2]); for (i=0 ; i<3 ; i++) { v = dir[i]*16; if (v > 127) v = 127; else if (v < -128) v = -128; MSG_WriteChar (&sv.datagram, v); } MSG_WriteByte (&sv.datagram, count); MSG_WriteByte (&sv.datagram, color); } /* ================== SV_StartSound Each entity can have eight independant sound sources, like voice, weapon, feet, etc. Channel 0 is an auto-allocate channel, the others override anything allready running on that entity/channel pair. An attenuation of 0 will play full volume everywhere in the level. Larger attenuations will drop off. (max 4 attenuation) ================== */ void SV_StartSound (edict_t *entity, int channel, char *sample, int volume, float attenuation) { int sound_num; int field_mask; int i; int ent; if (volume < 0 || volume > 255) Sys_Error ("SV_StartSound: volume = %i", volume); if (attenuation < 0 || attenuation > 4) Sys_Error ("SV_StartSound: attenuation = %f", attenuation); if (channel < 0 || channel > 7) Sys_Error ("SV_StartSound: channel = %i", channel); if (sv.datagram.cursize > MAX_DATAGRAM-16) return; // find precache number for sound for (sound_num=1 ; sound_numv.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i])); } /* ============================================================================== CLIENT SPAWNING ============================================================================== */ /* ================ SV_SendServerinfo Sends the first message from the server to a connected client. This will be sent on the initial connection and upon each server load. ================ */ void SV_SendServerinfo (client_t *client) { char **s; char message[2048]; MSG_WriteByte (&client->message, svc_print); sprintf (message, "%c\nVERSION %4.2f SERVER (%i CRC)\n", 2, VERSION, pr_crc); MSG_WriteString (&client->message,message); MSG_WriteByte (&client->message, svc_serverinfo); MSG_WriteLong (&client->message, PROTOCOL_VERSION); MSG_WriteByte (&client->message, svs.maxclients); if (!coop.value && deathmatch.value) MSG_WriteByte (&client->message, GAME_DEATHMATCH); else MSG_WriteByte (&client->message, GAME_COOP); sprintf (message, pr_strings+sv.edicts->v.message); MSG_WriteString (&client->message,message); for (s = sv.model_precache+1 ; *s ; s++) MSG_WriteString (&client->message, *s); MSG_WriteByte (&client->message, 0); for (s = sv.sound_precache+1 ; *s ; s++) MSG_WriteString (&client->message, *s); MSG_WriteByte (&client->message, 0); // send music MSG_WriteByte (&client->message, svc_cdtrack); MSG_WriteByte (&client->message, sv.edicts->v.sounds); MSG_WriteByte (&client->message, sv.edicts->v.sounds); // set view MSG_WriteByte (&client->message, svc_setview); MSG_WriteShort (&client->message, NUM_FOR_EDICT(client->edict)); MSG_WriteByte (&client->message, svc_signonnum); MSG_WriteByte (&client->message, 1); client->sendsignon = true; client->spawned = false; // need prespawn, spawn, etc } /* ================ SV_ConnectClient Initializes a client_t for a new net connection. This will only be called once for a player each game, not once for each level change. ================ */ void SV_ConnectClient (int clientnum) { edict_t *ent; client_t *client; int edictnum; struct qsocket_s *netconnection; int i; float spawn_parms[NUM_SPAWN_PARMS]; client = svs.clients + clientnum; Con_DPrintf ("Client %s connected\n", client->netconnection->address); edictnum = clientnum+1; ent = EDICT_NUM(edictnum); // set up the client_t netconnection = client->netconnection; if (sv.loadgame) memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms)); memset (client, 0, sizeof(*client)); client->netconnection = netconnection; strcpy (client->name, "unconnected"); client->active = true; client->spawned = false; client->edict = ent; client->message.data = client->msgbuf; client->message.maxsize = sizeof(client->msgbuf); client->message.allowoverflow = true; // we can catch it if (sv.loadgame) memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms)); else { // call the progs to get default spawn parms for the new client PR_ExecuteProgram (pr_global_struct->SetNewParms); for (i=0 ; ispawn_parms[i] = (&pr_global_struct->parm1)[i]; } SV_SendServerinfo (client); } /* =================== SV_CheckForNewClients =================== */ void SV_ForcedSettings (void); void SV_CheckForNewClients (void) { struct qsocket_s *ret; int i; // // check for new connections // while (1) { ret = NET_CheckNewConnections (); if (!ret) break; // // init a new client structure // for (i=0 ; i //SV_ForcedSettings(); // <-- koval } } /* =============================================================================== FRAME UPDATES =============================================================================== */ /* ================== SV_ClearDatagram ================== */ void SV_ClearDatagram (void) { SZ_Clear (&sv.datagram); } /* ============================================================================= The PVS must include a small area around the client to allow head bobbing or other small motion on the client side. Otherwise, a bob might cause an entity that should be visible to not show up, especially when the bob crosses a waterline. ============================================================================= */ int fatbytes; byte fatpvs[MAX_MAP_LEAFS/8]; void SV_AddToFatPVS (vec3_t org, mnode_t *node) { int i; byte *pvs; mplane_t *plane; float d; while (1) { // if this is a leaf, accumulate the pvs bits if (node->contents < 0) { if (node->contents != CONTENTS_SOLID) { pvs = Mod_LeafPVS ( (mleaf_t *)node, sv.worldmodel); for (i=0 ; iplane; d = PlaneDiff (org, plane); if (d > 8) node = node->children[0]; else if (d < -8) node = node->children[1]; else { // go down both SV_AddToFatPVS (org, node->children[0]); node = node->children[1]; } } } /* ============= SV_FatPVS Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the given point. ============= */ byte *SV_FatPVS (vec3_t org) { fatbytes = (sv.worldmodel->numleafs+31)>>3; Q_memset (fatpvs, 0, fatbytes); SV_AddToFatPVS (org, sv.worldmodel->nodes); return fatpvs; } //============================================================================= extern cvar_t deathmatch; extern cvar_t coop; extern cvar_t mod_showbbox; entity_t *CL_EntityNum (int num); void LR_DrawBox( edict_t *ent) { vec3_t p1,p2; VectorCopy(ent->v.absmax,p1);p1[0] = ent->v.absmin[0]; R_Beam(ent->v.absmax, p1);//XFX VectorCopy(ent->v.absmax,p2); p2[1] = ent->v.absmin[1];p2[0] = ent->v.absmin[0]; R_Beam(p1, p2);//XFX p2[2] = ent->v.absmin[2];p1[2] = ent->v.absmin[2]; R_Beam(p1, p2);//XFX p2[0] = ent->v.absmax[0];p1[0] = ent->v.absmax[0]; R_Beam(p1, p2);//XFX p2[2] = ent->v.absmax[2];p1[2] = ent->v.absmax[2]; R_Beam(p1, p2);//XFX p2[0] = ent->v.absmin[0];p1[1] = p2[1]; R_Beam(p1, p2);//XFX p2[2] = ent->v.absmin[2];p1[2] = ent->v.absmin[2]; R_Beam(p1, p2);//XFX p2[1] = ent->v.absmax[1];p1[1] = ent->v.absmax[1]; R_Beam(p1, p2);//XFX p2[2] = ent->v.absmax[2];p2[0] = ent->v.absmax[0]; R_Beam(p1, p2);//XFX p2[1] = ent->v.absmin[1];p1[1] = ent->v.absmin[1]; R_Beam(p1, p2);//XFX p2[0] = ent->v.absmin[0];p1[0] = ent->v.absmin[0]; R_Beam(p1, p2);//XFX p2[1] = ent->v.absmax[1];p1[1] = ent->v.absmax[1]; R_Beam(p1, p2);//XFX } #ifndef EXTENDQC #define EXTENDQC #endif /* ============= SV_WriteEntitiesToClient ============= */ int SizebufExtend(sizebuf_t * buf, int length) { byte * newdata; newdata = realloc(buf->data,buf->maxsize+length); if (newdata) { buf->maxsize += length; buf->data = newdata; } else { newdata = malloc(buf->maxsize+length); if (newdata) { memcpy(newdata,buf->data,buf->maxsize); buf->data = newdata; buf->maxsize = buf->maxsize+length; } else return false; } return true; } //Xsniper - Fixes Tomaz .alpha and .glow and .scale problems extern void FindEdictFieldOffsets(); //Xsniper - End void SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg) { int e, i; int bits; byte *pvs; vec3_t org; float miss; edict_t *ent; // Tomaz - QC Alpha Scale Glow Begin int clentnum; float alpha; float scale; float glow_size; float glow_red; float glow_green; float glow_blue; eval_t *val; // Tomaz - QC Alpha Scale Glow End qboolean modehud;//Tei hud entitys //Xsniper - Fixes Tomaz .alpha and .glow and .scale problems FindEdictFieldOffsets(); //Xsniper - End // find the client's PVS VectorAdd (clent->v.origin, clent->v.view_ofs, org); pvs = SV_FatPVS (org); clentnum = EDICT_TO_PROG(clent); // send over all entities (excpet the client) that touch the pvs ent = NEXT_EDICT(sv.edicts); for (e=1 ; ev.modelindex && ent->v.modelindexv.modelindex]->type ==mod_hud));//Tei hud entitys else modehud = false; if (!ent->v.modelindex || !pr_strings[ent->v.model]) continue; if ((val = GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)) && val->edict == clentnum) continue; if ((val = GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)) && val->edict && val->edict != clentnum) continue; if (!modehud) { for (i=0 ; i < ent->num_leafs ; i++) if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) )) break; if (i == ent->num_leafs) continue; // not visible } } if (msg->maxsize - msg->cursize < 16) { if (!SizebufExtend(msg, 4096)) Con_Printf("-"); else Con_Printf("+"); #ifndef SINGLEPLAYER Con_Printf ("packet overflow\n"); #endif if (ent->v.model) { if (!strncmp(pr_strings + ent->v.classname,"spike",6)) continue; //spike inhibited if (!strncmp(pr_strings + ent->v.model,"progs/zom",9)) continue; //Zombie inhibited if (!strncmp(pr_strings + ent->v.model,"progs/gib",9)) continue; //Gibs inhibited } if (msg->maxsize - msg->cursize < 8)//WARNING! { #ifndef SINGLEPLAYER Con_Printf ("packet overflow..heavy level\n"); #endif if (!(pr_strings + ent->v.classname) || !ent->v.classname) // "" continue; //inhibir anonymous, DANGEROUS!! if (msg->maxsize - msg->cursize < 6) if (ent->v.movetype == MOVETYPE_FLY ||ent->v.movetype == MOVETYPE_BOUNCE ) continue; } //return; } // send an update bits = 0; if( mod_showbbox.value) LR_DrawBox( ent);//Tei draw bbox for (i=0 ; i<3 ; i++) { miss = ent->v.origin[i] - ent->baseline.origin[i]; if ( miss < -0.1 || miss > 0.1 ) bits |= U_ORIGIN1<v.angles[0] != ent->baseline.angles[0] ) bits |= U_ANGLE1; if ( ent->v.angles[1] != ent->baseline.angles[1] ) bits |= U_ANGLE2; if ( ent->v.angles[2] != ent->baseline.angles[2] ) bits |= U_ANGLE3; if (ent->v.movetype == MOVETYPE_STEP) bits |= U_NOLERP; // don't mess up the step animation if (ent->baseline.colormap != ent->v.colormap) bits |= U_COLORMAP; if (ent->baseline.skin != ent->v.skin) bits |= U_SKIN; if (ent->baseline.frame != ent->v.frame) bits |= U_FRAME; if (ent->baseline.effects != ent->v.effects) bits |= U_EFFECTS; if (ent->baseline.modelindex != ent->v.modelindex) bits |= U_MODEL; // Tomaz - QC Alpha Scale Glow & More Frames Begin { alpha = 1; scale = 1; glow_size = 0; glow_red = 0; glow_green = 0; glow_blue = 0; if (ent->forcefx3 == EF3_GLASS) { alpha = 0.3; } if (val = GETEDICTFIELDVALUE(ent, eval_alpha)) alpha = val->_float; if ((val = GETEDICTFIELDVALUE(ent, eval_renderamt)) && val->_float != 0) // HalfLife support alpha = val->_float / 255; if (val = GETEDICTFIELDVALUE(ent, eval_scale)) scale = val->_float; if (scale > 4) scale = 4; if (val = GETEDICTFIELDVALUE(ent, eval_glow_size)) glow_size = val->_float; if (glow_size > 1024) glow_size = 1024; if (val = GETEDICTFIELDVALUE(ent, eval_glow_red)) glow_red = val->_float; if (val = GETEDICTFIELDVALUE(ent, eval_glow_green)) glow_green = val->_float; if (val = GETEDICTFIELDVALUE(ent, eval_glow_blue)) glow_blue = val->_float; if (alpha < 1) bits |= U_ALPHA; if ((scale <= 4) && (scale > 0)) bits |= U_SCALE; //Tei, codified fx3 if (ent->forcefx3) { glow_size = -1; glow_red = ent->forcefx3; } //Tei, codifieed fx3 if (glow_size >= 0 || glow_size == -1) { bits |= U_GLOW_SIZE; bits |= U_GLOW_RED; bits |= U_GLOW_GREEN; bits |= U_GLOW_BLUE; } if (((int) ent->baseline.frame & 0xFF00) != ((int) ent->v.frame & 0xFF00)) bits |= U_FRAME2; } // Tomaz - QC Alpha Scale Glow & More Frames End if (e >= 256) bits |= U_LONGENTITY; if (bits >= 256) bits |= U_MOREBITS; // Tomaz - QC Control Begin if (bits >= 65536) bits |= U_EXTEND1; if (bits >= 16777216) bits |= U_EXTEND2; // Tomaz - QC Control End // // write the message // MSG_WriteByte (msg,bits | U_SIGNAL); if (bits & U_MOREBITS) MSG_WriteByte (msg, bits>>8); // Tomaz - QC Control Begin if (bits & U_EXTEND1) MSG_WriteByte (msg, bits>>16); if (bits & U_EXTEND2) MSG_WriteByte (msg, bits>>24); // Tomaz - QC Control End if (bits & U_LONGENTITY) MSG_WriteShort (msg,e); else MSG_WriteByte (msg,e); if (bits & U_MODEL) MSG_WriteByte (msg, ent->v.modelindex); if (bits & U_FRAME) MSG_WriteByte (msg, ent->v.frame); if (bits & U_COLORMAP) MSG_WriteByte (msg, ent->v.colormap); if (bits & U_SKIN) MSG_WriteByte (msg, ent->v.skin); if (bits & U_EFFECTS) MSG_WriteByte (msg, ent->v.effects); if (bits & U_ORIGIN1) MSG_WriteCoord (msg, ent->v.origin[0]); if (bits & U_ANGLE1) MSG_WriteAngle(msg, ent->v.angles[0]); if (bits & U_ORIGIN2) MSG_WriteCoord (msg, ent->v.origin[1]); if (bits & U_ANGLE2) MSG_WriteAngle(msg, ent->v.angles[1]); if (bits & U_ORIGIN3) MSG_WriteCoord (msg, ent->v.origin[2]); if (bits & U_ANGLE3) MSG_WriteAngle(msg, ent->v.angles[2]); // Tomaz - QC Alpha Scale Glow & More Frames Begin if (bits & U_ALPHA) MSG_WriteFloat(msg, alpha); if (bits & U_SCALE) MSG_WriteFloat(msg, scale); if (bits & U_GLOW_SIZE) MSG_WriteFloat(msg, glow_size); if (bits & U_GLOW_RED) MSG_WriteFloat(msg, glow_red); if (bits & U_GLOW_GREEN) MSG_WriteFloat(msg, glow_green); if (bits & U_GLOW_BLUE) MSG_WriteFloat(msg, glow_blue); if (bits & U_FRAME2) MSG_WriteByte(msg, (int)ent->v.frame >> 8); // Tomaz - QC Alpha Scale Glow & More Frames End } } void SV_WriteEntitiesToClient_oldish (edict_t *clent, sizebuf_t *msg) { int e, i; int bits; byte *pvs; vec3_t org; float miss; edict_t *ent; #ifdef SINGLEPLAYER entity_t *cent;//SPE for telejano int k; #endif #ifdef EXTENDQC int clentnum; float alpha; float scale; float glow_size; float glow_red; float glow_green; float glow_blue; eval_t *val; #endif qboolean modehud; int singleplayer = !deathmatch.value && !coop.value; VectorAdd (clent->v.origin, clent->v.view_ofs, org);// find the client's PVS pvs = SV_FatPVS (org); clentnum = EDICT_TO_PROG(clent); ent = NEXT_EDICT(sv.edicts);// send over all entities (excpet the client) that touch the pvs for (e=1 ; ev.modelindex || !pr_strings[ent->v.model]) continue; modehud=false; if (ent->v.model) if (!strncmp(pr_strings + ent->v.model,"pics/",5)) modehud = true; if ((val = GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)) && val->edict == clentnum) continue; if ((val = GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)) && val->edict && val->edict != clentnum) continue; if (!modehud) { for (i=0 ; i < ent->num_leafs ; i++) if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) )) break; if (i == ent->num_leafs) continue; // not visible if (ent->v.effects3 == EF3_NONET ) continue; } } if (msg->maxsize - msg->cursize < 16) { Con_Printf ("packet overflow\n"); if (ent->v.model) { if (!strncmp(pr_strings + ent->v.classname,"spike",6)) continue; //spike inhibited if (!strncmp(pr_strings + ent->v.model,"progs/zom",9)) continue; //Zombie inhibited if (!strncmp(pr_strings + ent->v.model,"progs/gib",9)) continue; //Gibs inhibited } if (msg->maxsize - msg->cursize < 8)//WARNING! { Con_Printf ("packet overflow..heavy level\n"); if (!(pr_strings + ent->v.classname)) // "" continue; //inhibir anonymous, DANGEROUS!! } return; } // send an update bits = 0; if( mod_showbbox.value) LR_DrawBox( ent);//Tei draw bbox #ifdef SINGLEPLAYER //Entity in the spotlight cent = CL_EntityNum (e); //SPE //Easy to avoid VectorCopy( ent->v.origin, cent->origin); VectorCopy( ent->v.origin, cent->baseline.origin); VectorCopy( ent->v.angles, cent->angles); VectorCopy( ent->v.angles, cent->baseline.angles); cent->baseline.frame = ent->v.frame; k = ent->v.colormap; cent->colormap = cl.scores[k-1].translations; //This where problematic to avoid if (ent->v.movetype == MOVETYPE_STEP) bits |= U_NOLERP; // don't mess up the step animation if (ent->baseline.skin != ent->v.skin) bits |= U_SKIN; if (ent->baseline.effects != ent->v.effects) bits |= U_EFFECTS; //if (ent->baseline.modelindex != ent->v.modelindex) // bits |= U_MODEL; cent->baseline.modelindex = ent->v.modelindex; #else //TELEJANO NORMAL CODE for (i=0 ; i<3 ; i++) { miss = ent->v.origin[i] - ent->baseline.origin[i]; if ( miss < -0.1 || miss > 0.1 ) bits |= U_ORIGIN1<v.angles[0] != ent->baseline.angles[0] ) bits |= U_ANGLE1; if ( ent->v.angles[1] != ent->baseline.angles[1] ) bits |= U_ANGLE2; if ( ent->v.angles[2] != ent->baseline.angles[2] ) bits |= U_ANGLE3; if (ent->v.movetype == MOVETYPE_STEP) bits |= U_NOLERP; // don't mess up the step animation if (ent->baseline.colormap != ent->v.colormap) bits |= U_COLORMAP; if (ent->baseline.skin != ent->v.skin) bits |= U_SKIN; if (ent->baseline.frame != ent->v.frame) bits |= U_FRAME; if (ent->baseline.effects != ent->v.effects) bits |= U_EFFECTS; if (ent->baseline.modelindex != ent->v.modelindex) bits |= U_MODEL; #endif #ifdef EXTENDQC if (val = GETEDICTFIELDVALUE(ent, eval_alpha)) { alpha = val->_float; if(alpha && alpha != 1.0f) { bits |= U_ALPHA; //Con_Printf("A:%3.2f ", alpha); } } if (val = GETEDICTFIELDVALUE(ent, eval_scale)) { scale = val->_float; if(scale && scale != 1.0f) { bits |= U_SCALE; //Con_Printf("S:%3.2f ", scale); } } if (val = GETEDICTFIELDVALUE(ent, eval_glow_size)) { glow_size = val->_float; if(glow_size) bits |= U_GLOW_SIZE; if (val = GETEDICTFIELDVALUE(ent, eval_glow_red)) { glow_red = val->_float; bits |= U_GLOW_RED; } if (val = GETEDICTFIELDVALUE(ent, eval_glow_green)) { glow_green = val->_float; bits |= U_GLOW_GREEN; } if (val = GETEDICTFIELDVALUE(ent, eval_glow_blue)) { glow_blue = val->_float; bits |= U_GLOW_BLUE; } } #endif if (e >= 256) bits |= U_LONGENTITY; if (bits >= 256) bits |= U_MOREBITS; // // write the message // MSG_WriteByte (msg,bits | U_SIGNAL); if (bits & U_MOREBITS) MSG_WriteByte (msg, bits>>8); #ifdef EXTENDQC if (bits & U_EXTEND1) MSG_WriteByte (msg, bits>>16); #endif if (bits & U_LONGENTITY) MSG_WriteShort (msg,e); else MSG_WriteByte (msg,e); if (bits & U_MODEL) MSG_WriteByte (msg, ent->v.modelindex); //MSG_WriteModel (msg, ent->v.modelindex); if (bits & U_FRAME) MSG_WriteByte (msg, ent->v.frame); //MSG_WriteFrame (msg, ent->v.frame); if (bits & U_COLORMAP) MSG_WriteByte (msg, ent->v.colormap); if (bits & U_SKIN) MSG_WriteByte (msg, ent->v.skin); //MSG_WriteSkin (msg, ent->v.skin); if (bits & U_EFFECTS) MSG_WriteByte (msg, ent->v.effects); //MSG_WriteEffect(msg, ent->v.effects); if (bits & U_ORIGIN1) MSG_WriteCoord (msg, ent->v.origin[0]); if (bits & U_ANGLE1) MSG_WriteAngle(msg, ent->v.angles[0]); if (bits & U_ORIGIN2) MSG_WriteCoord (msg, ent->v.origin[1]); if (bits & U_ANGLE2) MSG_WriteAngle(msg, ent->v.angles[1]); if (bits & U_ORIGIN3) MSG_WriteCoord (msg, ent->v.origin[2]); if (bits & U_ANGLE3) MSG_WriteAngle(msg, ent->v.angles[2]); #ifdef EXTENDQC if (bits & U_ALPHA) MSG_WriteFloat(msg, alpha); if (bits & U_SCALE) MSG_WriteFloat(msg, scale); if (bits & U_GLOW_SIZE) MSG_WriteFloat(msg, glow_size); if (bits & U_GLOW_RED) MSG_WriteFloat(msg, glow_red); if (bits & U_GLOW_GREEN) MSG_WriteFloat(msg, glow_green); if (bits & U_GLOW_BLUE) MSG_WriteFloat(msg, glow_blue); #endif } } //Tei hudmodels entity + qure mouse support enum {GUIstate_null = 0, GUIstate_mouseover = 1, GUIstate_mousedown, GUIstate_rmousedown, GUIstate_numstates} guistates_t; #define GUISTATE_MOUSEOVER 1 #define GUISTATE_MOUSEDOWN 2 #define GUISTATE_RMOUSEDOWN 4 #define GUISTATE_MOUSEUP 8 #define OTHER 0 #define OVER 1 #define DOWN 2 #define UP 4 #define CLICK 8 #define ROVER 16 #define RDOWN 32 #define RUP 64 #define RCLICK 128 #define ONOUT 256 //#define HUDCALL(func,value ) {pr_global_struct->trace_fraction = value;PR_ExecuteProgram(func);}; #define USE PR_ExecuteProgram(object->v.use); #define HudParam(value, val2) {pr_global_struct->trace_fraction = value;pr_global_struct->trace_inopen = val2;USE;}; int mouse_pos[2]; extern int mouse_down[2]; void UpdateMouseHud ( edict_t * object) { int state, oldstate; oldstate = (int)object->v.button0; if(mouse_pos[0] > object->v.origin[0] && mouse_pos[0] < object->v.origin[0]+object->v.absmax[0] && mouse_pos[1] > object->v.origin[1] && mouse_pos[1] < object->v.origin[1]+object->v.absmax[1]) { state = state | GUISTATE_MOUSEOVER; if(!(oldstate & GUISTATE_MOUSEOVER) && object->v.touch) { pr_global_struct->trace_fraction = GUISTATE_MOUSEOVER; pr_global_struct->trace_inopen = OVER; PR_ExecuteProgram(object->v.touch); } if(mouse_down[0]) { if(!(oldstate & GUISTATE_MOUSEDOWN) && object->v.use) HudParam( GUISTATE_MOUSEDOWN ,DOWN); state = state | GUISTATE_MOUSEDOWN; }else{ if(object->v.use) HudParam( GUISTATE_MOUSEUP,UP ); if((oldstate & GUISTATE_MOUSEDOWN) && object->v.use) HudParam( GUISTATE_MOUSEDOWN,CLICK ); } if(mouse_down[1]) { if(!(oldstate & GUISTATE_RMOUSEDOWN) && object->v.use) HudParam( GUISTATE_RMOUSEDOWN,RDOWN ); state = state | GUISTATE_RMOUSEDOWN; }else{ if((oldstate & GUISTATE_RMOUSEDOWN) && object->v.use) HudParam( GUISTATE_RMOUSEDOWN,RUP ); } }else{ if((oldstate & GUISTATE_MOUSEOVER) && object->v.touch) { pr_global_struct->trace_fraction = GUISTATE_MOUSEOVER; pr_global_struct->trace_inopen = ONOUT; PR_ExecuteProgram(object->v.touch); } if((oldstate & GUISTATE_MOUSEDOWN) && object->v.use) HudParam( GUISTATE_MOUSEDOWN ,UP); if((oldstate & GUISTATE_RMOUSEDOWN) && object->v.use) HudParam( GUISTATE_RMOUSEDOWN,RUP ); } object->v.button0 = (float)state; } extern cvar_t r_efflies;//Tei/Venomus flies /* ============= SV_CleanupEnts ============= */ void SV_CleanupEnts (void) { int e, minframe,i; //int entnum; //Tei xfx edict_t *ent; eval_t *val, *val2; ent = NEXT_EDICT(sv.edicts); for (e=1 ; ev.effects = (int)ent->v.effects & ~EF_MUZZLEFLASH; // Tei - autovanish val = GETEDICTFIELDVALUE(ent, eval_alpha); if ((ent->v.effects3 == EF3_AUTOVANISH) && (val->_float == 0)) { val->_float = 1; } else if ((ent->v.effects3 == EF3_AUTOVANISH) && (val->_float >0.02) ) { val->_float= val->_float - 0.01; } else { if ( (ent->v.effects3 == EF3_AUTOVANISH) && (val->_float <=0.02) ) { ED_Free (ent); } } // Rotate from autoanimagic frame to autoanimagic_lowframe if ( eval_autoanimagic ) { // yes... autoanimagic defined val = GETEDICTFIELDVALUE(ent, eval_autoanimagic); if (val->_float) { // yes autoanimagic!=0 if (eval_autoanimagic_lowframe) { val2 = GETEDICTFIELDVALUE(ent, eval_autoanimagic_lowframe); minframe = val2->_float; } else minframe = 0; if (ent->v.frame>minframe) ent->v.frame = ent->v.frame - 1; else ent->v.frame = val->_float; } } // Tei - autoanimagic // if ( (ent->v.modelindex && ent->v.modelindexv.modelindex]) && ((sv.models[ (int)ent->v.modelindex]->type ==mod_hud)) ) { UpdateMouseHud( ent ); } // // Tei - xfx /* if (ent->v.movetype == MOVETYPE_PREDATOR ) { entnum = G_EDICTNUM(ent->v.aiment); if (sv.datagram.cursize <= MAX_DATAGRAM-16) { MSG_WriteByte (&svs.clients[entnum-1].message, svc_setview); MSG_WriteShort(&svs.clients[entnum-1].message, NUM_FOR_EDICT(ent)); //MSG_WriteString(&svs.clients[entnum-1].message, newpic); } } */ // Tei - xfx } } /* ================== SV_WriteClientdataToMessage ================== */ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg) { int bits; int i; edict_t *other; int items; eval_t *val; // // send a damage message // if (ent->v.dmg_take || ent->v.dmg_save) { other = PROG_TO_EDICT(ent->v.dmg_inflictor); MSG_WriteByte (msg, svc_damage); MSG_WriteByte (msg, ent->v.dmg_save); MSG_WriteByte (msg, ent->v.dmg_take); for (i=0 ; i<3 ; i++) MSG_WriteCoord (msg, other->v.origin[i] + 0.5*(other->v.mins[i] + other->v.maxs[i])); ent->v.dmg_take = 0; ent->v.dmg_save = 0; } // // send the current viewpos offset from the view entity // SV_SetIdealPitch (); // how much to look up / down ideally // a fixangle might get lost in a dropped packet. Oh well. if ( ent->v.fixangle ) { MSG_WriteByte (msg, svc_setangle); for (i=0 ; i < 3 ; i++) MSG_WriteAngle (msg, ent->v.angles[i] ); ent->v.fixangle = 0; } bits = 0; if (ent->v.view_ofs[2] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT; if (ent->v.idealpitch) bits |= SU_IDEALPITCH; // stuff the sigil bits into the high bits of items for sbar, or else // mix in items2 val = GETEDICTFIELDVALUE(ent, eval_items2); if (val) items = (int)ent->v.items | ((int)val->_float << 23); else items = (int)ent->v.items | ((int)pr_global_struct->serverflags << 28); bits |= SU_ITEMS; if ( (int)ent->v.flags & FL_ONGROUND) bits |= SU_ONGROUND; if ( ent->v.waterlevel >= 2) bits |= SU_INWATER; for (i=0 ; i<3 ; i++) { if (ent->v.punchangle[i]) bits |= (SU_PUNCH1<v.velocity[i]) bits |= (SU_VELOCITY1<v.weaponframe) bits |= SU_WEAPONFRAME; if (ent->v.armorvalue) bits |= SU_ARMOR; // if (ent->v.weapon) bits |= SU_WEAPON; // send the data MSG_WriteByte (msg, svc_clientdata); MSG_WriteShort (msg, bits); if (bits & SU_VIEWHEIGHT) MSG_WriteChar (msg, ent->v.view_ofs[2]); if (bits & SU_IDEALPITCH) MSG_WriteChar (msg, ent->v.idealpitch); for (i=0 ; i<3 ; i++) { if (bits & (SU_PUNCH1<v.punchangle[i]); if (bits & (SU_VELOCITY1<v.velocity[i]/16); } // [always sent] if (bits & SU_ITEMS) MSG_WriteLong (msg, items); if (bits & SU_WEAPONFRAME) // MSG_WriteFrame (msg, ent->v.weaponframe); MSG_WriteByte (msg, ent->v.weaponframe); if (bits & SU_ARMOR) MSG_WriteByte (msg, ent->v.armorvalue); if (bits & SU_WEAPON) MSG_WriteByte (msg, SV_ModelIndex(pr_strings+ent->v.weaponmodel)); MSG_WriteShort (msg, ent->v.health); MSG_WriteByte (msg, ent->v.currentammo); MSG_WriteByte (msg, ent->v.ammo_shells); MSG_WriteByte (msg, ent->v.ammo_nails); MSG_WriteByte (msg, ent->v.ammo_rockets); MSG_WriteByte (msg, ent->v.ammo_cells); if (standard_quake) { MSG_WriteByte (msg, ent->v.weapon); } else { for(i=0;i<32;i++) { if ( ((int)ent->v.weapon) & (1<edict, &msg); SV_WriteEntitiesToClient (client->edict, &msg); // copy the server datagram if there is space if (msg.cursize + sv.datagram.cursize < msg.maxsize) SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize); // send the datagram if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1) { SV_DropClient (true);// if the message couldn't send, kick off return false; } return true; } /* ======================= SV_UpdateToReliableMessages ======================= */ void SV_UpdateToReliableMessages (void) { int i, j; client_t *client; // check for changes to be sent over the reliable streams for (i=0, host_client = svs.clients ; iold_frags != host_client->edict->v.frags) { for (j=0, client = svs.clients ; jactive) continue; MSG_WriteByte (&client->message, svc_updatefrags); MSG_WriteByte (&client->message, i); MSG_WriteShort (&client->message, host_client->edict->v.frags); } host_client->old_frags = host_client->edict->v.frags; } } for (j=0, client = svs.clients ; jactive) continue; SZ_Write (&client->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize); } SZ_Clear (&sv.reliable_datagram); } /* ======================= SV_SendNop Send a nop message without trashing or sending the accumulated client message buffer ======================= */ void SV_SendNop (client_t *client) { sizebuf_t msg; byte buf[4]; msg.data = buf; msg.maxsize = sizeof(buf); msg.cursize = 0; MSG_WriteChar (&msg, svc_nop); if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1) SV_DropClient (true); // if the message couldn't send, kick off client->last_message = realtime; } /* ======================= SV_SendClientMessages ======================= */ void SV_SendClientMessages (void) { int i; // update frags, names, etc SV_UpdateToReliableMessages (); // build individual updates for (i=0, host_client = svs.clients ; iactive) continue; if (host_client->spawned) { if (!SV_SendClientDatagram (host_client)) continue; } else { // the player isn't totally in the game yet // send small keepalive messages if too much time has passed // send a full message when the next signon stage has been requested // some other message data (name changes, etc) may accumulate // between signon stages if (!host_client->sendsignon) { if (realtime - host_client->last_message > 5) SV_SendNop (host_client); continue; // don't send out non-signon messages } } // check for an overflowed message. Should only happen // on a very fucked up connection that backs up a lot, then // changes level if (host_client->message.overflowed) { SV_DropClient (true); host_client->message.overflowed = false; continue; } if (host_client->message.cursize || host_client->dropasap) { if (!NET_CanSendMessage (host_client->netconnection)) { // I_Printf ("can't write\n"); continue; } if (host_client->dropasap) SV_DropClient (false); // went to another level else { if (NET_SendMessage (host_client->netconnection , &host_client->message) == -1) SV_DropClient (true); // if the message couldn't send, kick off SZ_Clear (&host_client->message); host_client->last_message = realtime; host_client->sendsignon = false; } } } // clear muzzle flashes SV_CleanupEnts (); } /* ============================================================================== SERVER SPAWNING ============================================================================== */ /* ================ SV_ModelIndex ================ */ int SV_ModelIndex (char *name) { int i; if (!name || !name[0]) return 0; for (i=0 ; ifree) continue; if (entnum > svs.maxclients && !svent->v.modelindex) continue; // // create entity baseline // VectorCopy (svent->v.origin, svent->baseline.origin); VectorCopy (svent->v.angles, svent->baseline.angles); svent->baseline.frame = svent->v.frame; svent->baseline.skin = svent->v.skin; if (entnum > 0 && entnum <= svs.maxclients) { svent->baseline.colormap = entnum; svent->baseline.modelindex = SV_ModelIndex("progs/player.mdl"); } else { svent->baseline.colormap = 0; svent->baseline.modelindex = SV_ModelIndex(pr_strings + svent->v.model); } // // add to the message // MSG_WriteByte (&sv.signon,svc_spawnbaseline); MSG_WriteShort (&sv.signon,entnum); //MSG_WriteModel (&sv.signon, svent->baseline.modelindex); MSG_WriteByte (&sv.signon, svent->baseline.modelindex); //MSG_WriteFrame (&sv.signon, svent->baseline.frame); MSG_WriteByte (&sv.signon, svent->baseline.frame); MSG_WriteByte (&sv.signon, svent->baseline.colormap); //MSG_WriteSkin (&sv.signon, svent->baseline.skin); MSG_WriteByte (&sv.signon, svent->baseline.skin); for (i=0 ; i<3 ; i++) { MSG_WriteCoord(&sv.signon, svent->baseline.origin[i]); MSG_WriteAngle(&sv.signon, svent->baseline.angles[i]); } } } /* ================ SV_SendReconnect Tell all the clients that the server is changing levels ================ */ void SV_SendReconnect (void) { char data[128]; sizebuf_t msg; msg.data = data; msg.cursize = 0; msg.maxsize = sizeof(data); MSG_WriteChar (&msg, svc_stufftext); MSG_WriteString (&msg, "reconnect\n"); NET_SendToAll (&msg, 5); if (cls.state != ca_dedicated) Cmd_ExecuteString ("reconnect\n", src_command); } /* ================ SV_SaveSpawnparms Grabs the current state of each client for saving across the transition to another level ================ */ void SV_SaveSpawnparms (void) { int i, j; svs.serverflags = pr_global_struct->serverflags; for (i=0, host_client = svs.clients ; iactive) continue; // call the progs to get default spawn parms for the new client pr_global_struct->self = EDICT_TO_PROG(host_client->edict); PR_ExecuteProgram (pr_global_struct->SetChangeParms); for (j=0 ; jspawn_parms[j] = (&pr_global_struct->parm1)[j]; } } /* ================ SV_SpawnServer This is called at the start of each level ================ */ extern float scr_centertime_off; void CL_ClearPRJ();//Tei void Clear_Flares(void);//Tei flares //void CL_CleanSlots();//Tei void R_SetSkyBox (char *sky); int hell_count; //Tei hellfire prj counter extern cvar_t mod_turbo;//Tei turbo void SV_SpawnServer (char *server) { edict_t *ent; int i; char mapshots[32]; // Tomaz - MapShots char mapnames[32]; // Tomaz - MapShots hell_count = 0; // let's not have any servers with no name if (hostname.string[0] == 0) Cvar_Set ("hostname", "UNNAMED"); scr_centertime_off = 0; Con_DPrintf ("SpawnServer: %s\n",server); svs.changelevel_issued = false; // now safe to issue another // // tell all connected clients that we are going to a new level // if (sv.active) { SV_SendReconnect (); } // // make cvars consistant // if (coop.value) Cvar_SetValue ("deathmatch", 0); current_skill = (int)(skill.value + 0.5); if (current_skill < 0) current_skill = 0; if (current_skill > 3 && !mod_turbo.value)//Tei turbo values support current_skill = 3; Cvar_SetValue ("skill", (float)current_skill); // // set up the new server // Host_ClearMemory (); memset (&sv, 0, sizeof(sv)); strcpy (sv.name, server); // Tei prj CL_ClearPRJ(); Clear_Flares(); // Tei prj // load progs to get entity field count #ifdef MULTIPRS PR_LoadSVProgset (); #else PR_LoadProgs (); #endif // allocate server memory sv.max_edicts = MAX_EDICTS; sv.edicts = Hunk_AllocName (sv.max_edicts*pr_edict_size, "edicts"); #if 0 //def MULTIPRS edictoffset = (byte *)sv.edicts; sv_progs.edictoffset = edictoffset; cl_progs.edictoffset = edictoffset; #endif sv.datagram.maxsize = sizeof(sv.datagram_buf); sv.datagram.cursize = 0; sv.datagram.data = sv.datagram_buf; sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf); sv.reliable_datagram.cursize = 0; sv.reliable_datagram.data = sv.reliable_datagram_buf; sv.signon.maxsize = sizeof(sv.signon_buf); sv.signon.cursize = 0; sv.signon.data = sv.signon_buf; // leave slots at start for clients only sv.num_edicts = svs.maxclients+1; for (i=0 ; inumvertexes == -1) { Con_Printf ("Couldn't spawn server %s\n", sv.modelname); sv.active = false; return; } // Tomaz - Fixing Wrong BSP Version Error End // // clear world interaction links // SV_ClearWorld (); sv.sound_precache[0] = pr_strings; sv.model_precache[0] = pr_strings; sv.model_precache[1] = sv.modelname; for (i=1 ; inumsubmodels ; i++) { sv.model_precache[1+i] = localmodels[i]; sv.models[i+1] = Mod_ForName (localmodels[i], false); } // // load the rest of the entities // ent = EDICT_NUM(0); memset (&ent->v, 0, progs->entityfields * 4); ent->free = false; ent->v.model = sv.worldmodel->name - pr_strings; ent->v.modelindex = 1; // world model ent->v.solid = SOLID_BSP; ent->v.movetype = MOVETYPE_PUSH; if (coop.value) pr_global_struct->coop = coop.value; else pr_global_struct->deathmatch = deathmatch.value; pr_global_struct->mapname = sv.name - pr_strings; // serverflags are for cross level information (sigils) pr_global_struct->serverflags = svs.serverflags; ED_LoadFromFile (sv.worldmodel->entities); VectorClear(sv.edicts->v.angles); sv.active = true; // all setup is completed, any further precache statements are errors sv.state = ss_active; // run two frames to allow everything to settle host_frametime = 0.1; SV_Physics (); SV_Physics (); // create a baseline for more efficient communications SV_CreateBaseline (); // send serverinfo to all connected clients for (i=0,host_client = svs.clients ; iactive) SV_SendServerinfo (host_client); Con_DPrintf ("Server spawned.\n"); }