From 71c88e4a876a4cfcccf312e3cd4ddbb1ced6d11f Mon Sep 17 00:00:00 2001 From: havoc Date: Wed, 1 Dec 2004 05:39:03 +0000 Subject: [PATCH] implemented PRYDON_CLIENTCURSOR extension (clientside mouse pointer that feeds back information to the QuakeC) added DP_BUTTONUSE extension (+use/-use button) added DP_BUTTONCHAT extension (true while input is not focused on the game) reimplemented DP_ENT_COLORMOD extension due to popular request, and changed its definition to allow colors above '1 1 1' for brightening effects implemented PROTOCOL_DARKPLACES6 protocol, featuring delta compression of ammo counts and other properties (using generic svc_updatestat and svc_updatestatubyte messages), precaching models and sounds during the game (svc_precache). removed cmd parameter from a lot of input code (now uses cl.cmd. instead of cmd->) added sv_gameplayfix_setmodelrealbox to allow disabling of the setmodel real model bounding box on alias models (may improve mod compatibility if set to 0, thus performing a setsize (self, '-16 -16 -16', '16 16 16') instead of the real alias model box). added SV_ModelIndex and SV_SoundIndex functions to clean up the server's precaching and model lookup processes (code reduction/maintenance reduction). changed sv.model_precache and sv.sound_precache to be real char arrays rather than pointers, so precache names no longer need to be constants as they're now copied. added some modelindex bounds checks to a few pieces of code. the dpfields array is now sorted and matches the supported fields list (added the missing ones). client now acknowledges the last 3 frames in each input packet to reduce packet loss issues. renamed clc_ackentities to clc_ackframe as it is now used for compressing stats as well as entities in PROTOCOL_DARKPLACES6, this also means it always produces a packet for every frame even if there's no changed entities (or room under the rate limit for that matter) PROTOCOL_DARKPLACES5 and 6 now perform a non-harmful serverside packetlog reset (marking all packets as lost) if the packetlog fills up, this should eliminate choked-to-death cases where the client lost everything for a few seconds. MAX_CL_STATS expanded from 32 to 256 (just incase more stats are added, this prevents protocol breakage on too many unknown extra stats) fixed a bug with the worst case rtlight rendering (the color array was disabled, oops). some cl.* fields converted to cl.stats elements (STAT_ITEMS for instance) to accomodate the PROTOCOL_DARKPLACES6 stats updates git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@4801 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_collision.c | 5 +- cl_input.c | 166 +++++++++++++++----- cl_main.c | 17 +- cl_parse.c | 166 ++++++++++++-------- client.h | 35 +++-- common.c | 12 +- gl_draw.c | 2 + gl_models.c | 3 + gl_rsurf.c | 49 +++--- host.c | 7 +- host_cmd.c | 4 +- input.h | 6 +- pr_cmds.c | 114 +++++--------- pr_edict.c | 79 ++++++---- progs.h | 8 + protocol.c | 201 ++++++++++++++++-------- protocol.h | 28 ++-- quakedef.h | 7 +- r_shadow.c | 58 +++---- r_sprites.c | 3 + sbar.c | 95 ++++++------ server.h | 21 ++- sv_main.c | 412 +++++++++++++++++++++++++++---------------------- sv_user.c | 64 ++++++-- vid_glx.c | 4 +- vid_null.c | 2 +- vid_sdl.c | 10 +- vid_shared.c | 22 ++- vid_wgl.c | 22 +-- view.c | 10 +- 30 files changed, 993 insertions(+), 639 deletions(-) diff --git a/cl_collision.c b/cl_collision.c index c2f2eaaa..bc888322 100644 --- a/cl_collision.c +++ b/cl_collision.c @@ -143,8 +143,9 @@ float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, ve ent = &cl_entities[n].render; if (!ent->model || !ent->model->TraceBox) continue; - //if (((ent->model->type != mod_brushq1 && ent->model->type != mod_brushq2 && ent->model->type != mod_brushq3) || ent->alpha < 1) && !(cl_entities[n].state_current.effects & EF_SELECTABLE)) - // continue; + // if transparent and not selectable, skip entity + if (!(cl_entities[n].state_current.effects & EF_SELECTABLE) && (ent->alpha < 1 || (ent->effects & (EF_ADDITIVE | EF_NODEPTHTEST)))) + continue; if (ent->mins[0] > tracemaxs[0] || ent->maxs[0] < tracemins[0] || ent->mins[1] > tracemaxs[1] || ent->maxs[1] < tracemins[1] || ent->mins[2] > tracemaxs[2] || ent->maxs[2] < tracemins[2]) diff --git a/cl_input.c b/cl_input.c index 610bd30d..a9694ddb 100644 --- a/cl_input.c +++ b/cl_input.c @@ -49,7 +49,7 @@ state bit 2 is edge triggered on the down to up transition kbutton_t in_mlook, in_klook; kbutton_t in_left, in_right, in_forward, in_back; kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright; -kbutton_t in_strafe, in_speed, in_jump, in_attack; +kbutton_t in_strafe, in_speed, in_jump, in_attack, in_use; kbutton_t in_up, in_down; // LordHavoc: added 6 new buttons kbutton_t in_button3, in_button4, in_button5, in_button6, in_button7, in_button8; @@ -156,6 +156,9 @@ void IN_StrafeUp(void) {KeyUp(&in_strafe);} void IN_AttackDown(void) {KeyDown(&in_attack);} void IN_AttackUp(void) {KeyUp(&in_attack);} +void IN_UseDown(void) {KeyDown(&in_use);} +void IN_UseUp(void) {KeyUp(&in_use);} + // LordHavoc: added 6 new buttons void IN_Button3Down(void) {KeyDown(&in_button3);} void IN_Button3Up(void) {KeyUp(&in_button3);} @@ -305,31 +308,35 @@ CL_BaseMove Send the intended movement message to the server ================ */ -void CL_BaseMove (usercmd_t *cmd) +void CL_BaseMove (void) { + vec3_t temp; if (cls.signon != SIGNONS) return; CL_AdjustAngles (); - memset (cmd, 0, sizeof(*cmd)); + // PRYDON_CLIENTCURSOR needs to survive basemove resets + VectorCopy (cl.cmd.cursor_screen, temp); + memset (&cl.cmd, 0, sizeof(cl.cmd)); + VectorCopy (temp, cl.cmd.cursor_screen); if (in_strafe.state & 1) { - cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right); - cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_left); + cl.cmd.sidemove += cl_sidespeed.value * CL_KeyState (&in_right); + cl.cmd.sidemove -= cl_sidespeed.value * CL_KeyState (&in_left); } - cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright); - cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft); + cl.cmd.sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright); + cl.cmd.sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft); - cmd->upmove += cl_upspeed.value * CL_KeyState (&in_up); - cmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down); + cl.cmd.upmove += cl_upspeed.value * CL_KeyState (&in_up); + cl.cmd.upmove -= cl_upspeed.value * CL_KeyState (&in_down); if (! (in_klook.state & 1) ) { - cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward); - cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back); + cl.cmd.forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward); + cl.cmd.forwardmove -= cl_backspeed.value * CL_KeyState (&in_back); } // @@ -337,20 +344,71 @@ void CL_BaseMove (usercmd_t *cmd) // if (in_speed.state & 1) { - cmd->forwardmove *= cl_movespeedkey.value; - cmd->sidemove *= cl_movespeedkey.value; - cmd->upmove *= cl_movespeedkey.value; + cl.cmd.forwardmove *= cl_movespeedkey.value; + cl.cmd.sidemove *= cl_movespeedkey.value; + cl.cmd.upmove *= cl_movespeedkey.value; } } +#include "cl_collision.h" + +void CL_UpdatePrydonCursor(void) +{ + vec3_t temp, scale; + + if (!cl_prydoncursor.integer) + VectorClear(cl.cmd.cursor_screen); + + /* + if (cl.cmd.cursor_screen[0] < -1) + { + cl.viewangles[YAW] -= m_yaw.value * (cl.cmd.cursor_screen[0] - -1) * vid.realwidth * sensitivity.value * cl.viewzoom; + cl.cmd.cursor_screen[0] = -1; + } + if (cl.cmd.cursor_screen[0] > 1) + { + cl.viewangles[YAW] -= m_yaw.value * (cl.cmd.cursor_screen[0] - 1) * vid.realwidth * sensitivity.value * cl.viewzoom; + cl.cmd.cursor_screen[0] = 1; + } + if (cl.cmd.cursor_screen[1] < -1) + { + cl.viewangles[PITCH] += m_pitch.value * (cl.cmd.cursor_screen[1] - -1) * vid.realheight * sensitivity.value * cl.viewzoom; + cl.cmd.cursor_screen[1] = -1; + } + if (cl.cmd.cursor_screen[1] > 1) + { + cl.viewangles[PITCH] += m_pitch.value * (cl.cmd.cursor_screen[1] - 1) * vid.realheight * sensitivity.value * cl.viewzoom; + cl.cmd.cursor_screen[1] = 1; + } + */ + cl.cmd.cursor_screen[0] = bound(-1, cl.cmd.cursor_screen[0], 1); + cl.cmd.cursor_screen[1] = bound(-1, cl.cmd.cursor_screen[1], 1); + cl.cmd.cursor_screen[2] = 1; + + scale[0] = -tan(r_refdef.fov_x * M_PI / 360.0); + scale[1] = -tan(r_refdef.fov_y * M_PI / 360.0); + scale[2] = 1; + + // trace distance + VectorScale(scale, 1000000, scale); + + // FIXME: use something other than renderer variables here + // (but they need to match) + VectorCopy(r_vieworigin, cl.cmd.cursor_start); + VectorSet(temp, cl.cmd.cursor_screen[2] * scale[2], cl.cmd.cursor_screen[0] * scale[0], cl.cmd.cursor_screen[1] * scale[1]); + Matrix4x4_Transform(&r_view_matrix, temp, cl.cmd.cursor_end); + cl.cmd.cursor_fraction = CL_SelectTraceLine(cl.cmd.cursor_start, cl.cmd.cursor_end, cl.cmd.cursor_impact, cl.cmd.cursor_normal, &cl.cmd.cursor_entitynumber); + // makes sparks where cursor is + //CL_SparkShower(cl.cmd.cursor_impact, cl.cmd.cursor_normal, 5, 0); +} /* ============== CL_SendMove ============== */ -void CL_SendMove(usercmd_t *cmd) +void CL_SendMove(void) { int i; int bits; @@ -359,9 +417,11 @@ void CL_SendMove(usercmd_t *cmd) static double lastmovetime; static float forwardmove, sidemove, upmove, total; // accumulation - forwardmove += cmd->forwardmove; - sidemove += cmd->sidemove; - upmove += cmd->upmove; + CL_UpdatePrydonCursor(); + + forwardmove += cl.cmd.forwardmove; + sidemove += cl.cmd.sidemove; + upmove += cl.cmd.upmove; total++; // LordHavoc: cap outgoing movement messages to sys_ticrate if (!cl.islocalgame && (realtime - lastmovetime < sys_ticrate.value)) @@ -378,8 +438,6 @@ void CL_SendMove(usercmd_t *cmd) buf.cursize = 0; buf.data = data; - cl.cmd = *cmd; - // send the movement message MSG_WriteByte (&buf, clc_move); @@ -395,7 +453,7 @@ void CL_SendMove(usercmd_t *cmd) for (i = 0;i < 3;i++) MSG_WriteAngle32f (&buf, cl.viewangles[i]); } - else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5) + else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5 || cl.protocol == PROTOCOL_DARKPLACES6) { for (i = 0;i < 3;i++) MSG_WriteAngle16i (&buf, cl.viewangles[i]); @@ -411,28 +469,58 @@ void CL_SendMove(usercmd_t *cmd) // send button bits bits = 0; - // LordHavoc: added 6 new buttons - if (in_attack.state & 3) bits |= 1;in_attack.state &= ~2; - if (in_jump.state & 3) bits |= 2;in_jump.state &= ~2; - if (in_button3.state & 3) bits |= 4;in_button3.state &= ~2; - if (in_button4.state & 3) bits |= 8;in_button4.state &= ~2; - if (in_button5.state & 3) bits |= 16;in_button5.state &= ~2; - if (in_button6.state & 3) bits |= 32;in_button6.state &= ~2; - if (in_button7.state & 3) bits |= 64;in_button7.state &= ~2; - if (in_button8.state & 3) bits |= 128;in_button8.state &= ~2; - - MSG_WriteByte (&buf, bits); + // LordHavoc: added 13 new buttons and chat button + if (in_attack.state & 3) bits |= 1;in_attack.state &= ~2; + if (in_jump.state & 3) bits |= 2;in_jump.state &= ~2; + if (in_button3.state & 3) bits |= 4;in_button3.state &= ~2; + if (in_button4.state & 3) bits |= 8;in_button4.state &= ~2; + if (in_button5.state & 3) bits |= 16;in_button5.state &= ~2; + if (in_button6.state & 3) bits |= 32;in_button6.state &= ~2; + if (in_button7.state & 3) bits |= 64;in_button7.state &= ~2; + if (in_button8.state & 3) bits |= 128;in_button8.state &= ~2; + if (in_use.state & 3) bits |= 256;in_use.state &= ~2; + if (key_dest != key_game || key_consoleactive) bits |= 512; + if (cl_prydoncursor.integer) bits |= 1024; + // button bits 11-31 unused currently + if (cl.cmd.cursor_screen[0] <= -1) bits |= 8; + if (cl.cmd.cursor_screen[0] >= 1) bits |= 16; + if (cl.cmd.cursor_screen[1] <= -1) bits |= 32; + if (cl.cmd.cursor_screen[1] >= 1) bits |= 64; + + if (cl.protocol == PROTOCOL_DARKPLACES6) + MSG_WriteLong (&buf, bits); + else + MSG_WriteByte (&buf, bits); MSG_WriteByte (&buf, in_impulse); in_impulse = 0; - // FIXME: should ack latest 3 frames perhaps? - if (cl.latestframenum > 0) + // PRYDON_CLIENTCURSOR + if (cl.protocol == PROTOCOL_DARKPLACES6) + { + // 30 bytes + MSG_WriteShort (&buf, cl.cmd.cursor_screen[0] * 32767.0f); + MSG_WriteShort (&buf, cl.cmd.cursor_screen[1] * 32767.0f); + MSG_WriteFloat (&buf, cl.cmd.cursor_start[0]); + MSG_WriteFloat (&buf, cl.cmd.cursor_start[1]); + MSG_WriteFloat (&buf, cl.cmd.cursor_start[2]); + MSG_WriteFloat (&buf, cl.cmd.cursor_impact[0]); + MSG_WriteFloat (&buf, cl.cmd.cursor_impact[1]); + MSG_WriteFloat (&buf, cl.cmd.cursor_impact[2]); + MSG_WriteShort (&buf, cl.cmd.cursor_entitynumber); + } + + // ack the last few frame numbers + // (redundent to improve handling of client->server packet loss) + if (cl.latestframenums[LATESTFRAMENUMS-1] > 0) { if (developer_networkentities.integer >= 1) - Con_Printf("send clc_ackentities %i\n", cl.latestframenum); - MSG_WriteByte(&buf, clc_ackentities); - MSG_WriteLong(&buf, cl.latestframenum); + Con_Printf("send clc_ackframe %i\n", cl.latestframenums[LATESTFRAMENUMS-1]); + for (i = 0;i < LATESTFRAMENUMS;i++) + { + MSG_WriteByte(&buf, clc_ackframe); + MSG_WriteLong(&buf, cl.latestframenums[i]); + } } // deliver the message @@ -492,6 +580,10 @@ void CL_InitInput (void) Cmd_AddCommand ("+mlook", IN_MLookDown); Cmd_AddCommand ("-mlook", IN_MLookUp); + // LordHavoc: added use button + Cmd_AddCommand ("+use", IN_UseDown); + Cmd_AddCommand ("-use", IN_UseUp); + // LordHavoc: added 6 new buttons Cmd_AddCommand ("+button3", IN_Button3Down); Cmd_AddCommand ("-button3", IN_Button3Up); diff --git a/cl_main.c b/cl_main.c index 75d0d0eb..2898df65 100644 --- a/cl_main.c +++ b/cl_main.c @@ -61,6 +61,8 @@ cvar_t cl_beams_lightatend = {CVAR_SAVE, "cl_beams_lightatend", "0"}; cvar_t cl_noplayershadow = {CVAR_SAVE, "cl_noplayershadow", "0"}; +cvar_t cl_prydoncursor = {0, "cl_prydoncursor", "0"}; + mempool_t *cl_refdef_mempool; mempool_t *cl_entities_mempool; @@ -390,6 +392,7 @@ entity_t *CL_NewTempEntity(void) ent->render.colormap = -1; // no special coloring ent->render.scale = 1; ent->render.alpha = 1; + VectorSet(ent->render.colormod, 1, 1, 1); return ent; } @@ -530,6 +533,7 @@ void CL_LinkNetworkEntity(entity_t *e) else e->render.colormap = -1; // no special coloring e->render.skinnum = e->state_current.skin; + VectorScale(e->state_current.colormod, (1.0f / 32.0f), e->render.colormod); if (e->render.flags & RENDER_VIEWMODEL) { if (!r_drawviewmodel.integer || chase_active.integer || envmap) @@ -610,6 +614,8 @@ void CL_LinkNetworkEntity(entity_t *e) // transfer certain model flags to effects if (e->render.model->flags2 & EF_FULLBRIGHT) e->render.effects |= EF_FULLBRIGHT; + if (cl_prydoncursor.integer && (e->render.effects & EF_SELECTABLE) && cl.cmd.cursor_entitynumber == e - cl_entities) + VectorScale(e->render.colormod, 2, e->render.colormod); } // animation lerp @@ -886,6 +892,7 @@ void CL_RelinkWorld(void) ent->render.flags = RENDER_SHADOW; if (!r_fullbright.integer) ent->render.flags |= RENDER_LIGHT; + VectorSet(ent->render.colormod, 1, 1, 1); } static void CL_RelinkStaticEntities(void) @@ -905,6 +912,7 @@ static void CL_RelinkStaticEntities(void) // hide player shadow during intermission or nehahra movie if (!(e->render.effects & EF_NOSHADOW) && !(e->render.flags & RENDER_TRANSPARENT)) e->render.flags |= RENDER_SHADOW; + VectorSet(e->render.colormod, 1, 1, 1); R_LerpAnimation(&e->render); r_refdef.entities[r_refdef.numentities++] = &e->render; } @@ -931,7 +939,7 @@ static void CL_RelinkNetworkEntities(void) ent->state_current.flags = RENDER_VIEWMODEL; if (cl.stats[STAT_HEALTH] <= 0 || cl.intermission) ent->state_current.modelindex = 0; - else if (cl.items & IT_INVISIBILITY) + else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY) { if (gamemode == GAME_TRANSFUSION) ent->state_current.alpha = 128; @@ -998,6 +1006,7 @@ static void CL_RelinkEffects(void) ent->render.frame = ent->render.frame2; ent->render.colormap = -1; // no special coloring ent->render.alpha = 1; + VectorSet(ent->render.colormod, 1, 1, 1); Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, e->origin[0], e->origin[1], e->origin[2], 0, 0, 0, 1); Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix); @@ -1198,10 +1207,10 @@ int CL_ReadFromServer(void) CL_SendCmd ================= */ -void CL_SendCmd(usercmd_t *cmd) +void CL_SendCmd(void) { if (cls.signon == SIGNONS) - CL_SendMove(cmd); + CL_SendMove(); if (cls.demoplayback) { @@ -1350,6 +1359,8 @@ void CL_Init (void) Cvar_RegisterVariable(&cl_beams_lightatend); Cvar_RegisterVariable(&cl_noplayershadow); + Cvar_RegisterVariable(&cl_prydoncursor); + if (gamemode == GAME_NETHERWORLD) { Cvar_RegisterVariable (&cl_playermodel); diff --git a/cl_parse.c b/cl_parse.c index 54aa5934..0e67fe36 100644 --- a/cl_parse.c +++ b/cl_parse.c @@ -83,7 +83,7 @@ char *svc_strings[128] = "", // 48 "", // 49 "svc_cgame", // 50 // [short] length [bytes] data - "svc_unusedlh1", // 51 // unused + "svc_updatestatubyte", // 51 // [byte] stat [byte] value "svc_effect", // 52 // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate "svc_effect2", // 53 // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate "svc_sound2", // 54 // short soundindex instead of byte @@ -332,9 +332,9 @@ void CL_ParseServerInfo (void) // hack for unmarked Nehahra movie demos which had a custom protocol if (i == PROTOCOL_QUAKE && cls.demoplayback && demo_nehahra.integer) i = PROTOCOL_NEHAHRAMOVIE; - if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_DARKPLACES5 && i != PROTOCOL_NEHAHRAMOVIE) + if (i != PROTOCOL_QUAKE && i != PROTOCOL_DARKPLACES1 && i != PROTOCOL_DARKPLACES2 && i != PROTOCOL_DARKPLACES3 && i != PROTOCOL_DARKPLACES4 && i != PROTOCOL_DARKPLACES5 && i != PROTOCOL_DARKPLACES6 && i != PROTOCOL_NEHAHRAMOVIE) { - Host_Error("CL_ParseServerInfo: Server is protocol %i, not %i (Quake), %i (DP1), %i (DP2), %i (DP3), %i (DP4), %i (DP5), or %i (Nehahra movie)", i, PROTOCOL_QUAKE, PROTOCOL_DARKPLACES1, PROTOCOL_DARKPLACES2, PROTOCOL_DARKPLACES3, PROTOCOL_DARKPLACES4, PROTOCOL_DARKPLACES5, PROTOCOL_NEHAHRAMOVIE); + Host_Error("CL_ParseServerInfo: Server is protocol %i, not %i (Quake), %i (DP1), %i (DP2), %i (DP3), %i (DP4), %i (DP5), %i (DP6), or %i (Nehahra movie)", i, PROTOCOL_QUAKE, PROTOCOL_DARKPLACES1, PROTOCOL_DARKPLACES2, PROTOCOL_DARKPLACES3, PROTOCOL_DARKPLACES4, PROTOCOL_DARKPLACES5, PROTOCOL_DARKPLACES6, PROTOCOL_NEHAHRAMOVIE); return; } cl.protocol = i; @@ -592,6 +592,25 @@ void CL_ParseClientdata (int bits) { int i, j; + VectorCopy (cl.mvelocity[0], cl.mvelocity[1]); + + if (cl.protocol != PROTOCOL_DARKPLACES6) + { + cl.stats[STAT_VIEWHEIGHT] = DEFAULT_VIEWHEIGHT; + cl.stats[STAT_ITEMS] = 0; + cl.stats[STAT_VIEWZOOM] = 255; + } + cl.idealpitch = 0; + cl.punchangle[0] = 0; + cl.punchangle[1] = 0; + cl.punchangle[2] = 0; + cl.punchvector[0] = 0; + cl.punchvector[1] = 0; + cl.punchvector[2] = 0; + cl.mvelocity[0][0] = 0; + cl.mvelocity[0][1] = 0; + cl.mvelocity[0][2] = 0; + bits &= 0xFFFF; if (bits & SU_EXTEND1) bits |= (MSG_ReadByte() << 16); @@ -599,85 +618,63 @@ void CL_ParseClientdata (int bits) bits |= (MSG_ReadByte() << 24); if (bits & SU_VIEWHEIGHT) - cl.viewheight = MSG_ReadChar (); - else - cl.viewheight = DEFAULT_VIEWHEIGHT; + cl.stats[STAT_VIEWHEIGHT] = MSG_ReadChar (); if (bits & SU_IDEALPITCH) cl.idealpitch = MSG_ReadChar (); - else - cl.idealpitch = 0; - VectorCopy (cl.mvelocity[0], cl.mvelocity[1]); for (i = 0;i < 3;i++) { if (bits & (SU_PUNCH1<= 1 && i < MAX_MODELS) + { + model_t *model = Mod_ForName(s, false, false, i == 1); + if (!model) + Con_Printf("svc_precache: Mod_ForName(\"%s\") failed\n", s); + cl.model_precache[i] = model; + } + else + Con_Printf("svc_precache: index %i outside range %i...%i\n", i, 1, MAX_MODELS); + } + else + { + i -= 32768; + if (i >= 1 && i < MAX_SOUNDS) + { + sfx_t *sfx = S_PrecacheSound (s, true, false); + // FIXME: SFXFLAG_SERVEROSUND should be set on the sfx + if (!sfx) + Con_Printf("svc_precache: S_PrecacheSound(\"%s\") failed\n", s); + cl.sound_precache[i] = sfx; + } + else + Con_Printf("svc_precache: index %i outside range %i...%i\n", i, 1, MAX_SOUNDS); + } + } break; case svc_stopsound: @@ -1584,6 +1619,13 @@ void CL_ParseServerMessage(void) cl.stats[i] = MSG_ReadLong (); break; + case svc_updatestatubyte: + i = MSG_ReadByte (); + if (i < 0 || i >= MAX_CL_STATS) + Host_Error ("svc_updatestat: %i is invalid", i); + cl.stats[i] = MSG_ReadByte (); + break; + case svc_spawnstaticsound: CL_ParseStaticSound (false); break; @@ -1676,7 +1718,7 @@ void CL_ParseServerMessage(void) EntityFrame_CL_ReadFrame(); else if (cl.protocol == PROTOCOL_DARKPLACES4) EntityFrame4_CL_ReadFrame(); - else if (cl.protocol == PROTOCOL_DARKPLACES5) + else if (cl.protocol == PROTOCOL_DARKPLACES5 || cl.protocol == PROTOCOL_DARKPLACES6) EntityFrame5_CL_ReadFrame(); else Host_Error("CL_ParseServerMessage: svc_entities: unknown cl.protocol %i\n", cl.protocol); diff --git a/client.h b/client.h index 45dc560f..b3272d1f 100644 --- a/client.h +++ b/client.h @@ -255,6 +255,9 @@ typedef struct entity_render_s // render flags int flags; + // colormod tinting of models + float colormod[3]; + // interpolated animation // frame that the model is interpolating from @@ -337,6 +340,14 @@ typedef struct float forwardmove; float sidemove; float upmove; + + vec3_t cursor_screen; + vec3_t cursor_start; + vec3_t cursor_end; + vec3_t cursor_impact; + vec3_t cursor_normal; + vec_t cursor_fraction; + int cursor_entitynumber; } usercmd_t; typedef struct @@ -456,16 +467,18 @@ typedef struct // send a clc_nop periodically until connected float sendnoptime; - // last command sent to the server + // current input to send to the server usercmd_t cmd; // information for local display // health, etc int stats[MAX_CL_STATS]; - // inventory bit flags - int items; + // last known inventory bit flags, for blinking + int olditems; // cl.time of acquiring item, for blinking float item_gettime[32]; + // last known STAT_ACTIVEWEAPON + int activeweapon; // cl.time of changing STAT_ACTIVEWEAPON float weapontime; // use pain anim frame if cl.time < this @@ -503,7 +516,6 @@ typedef struct float driftmove; double laststop; - float viewheight; // local amount for smoothing stepups //float crouch; @@ -569,8 +581,9 @@ typedef struct int protocol; // entity database stuff - // latest received entity frame number - int latestframenum; + // latest received entity frame numbers +#define LATESTFRAMENUMS 3 + int latestframenums[LATESTFRAMENUMS]; entityframe_database_t *entitydatabase; entityframe4_database_t *entitydatabase4; } @@ -625,6 +638,8 @@ extern cvar_t cl_explosions_lifetime; extern cvar_t cl_stainmaps; extern cvar_t cl_stainmapsclearonload; +extern cvar_t cl_prydoncursor; + // these are updated by CL_ClearState extern int cl_num_entities; extern int cl_num_static_entities; @@ -682,8 +697,8 @@ extern kbutton_t in_strafe; extern kbutton_t in_speed; void CL_InitInput (void); -void CL_SendCmd (usercmd_t *cmd); -void CL_SendMove (usercmd_t *cmd); +void CL_SendCmd (void); +void CL_SendMove (void); void CL_ValidateState(entity_state_t *s); void CL_MoveLerpEntityStates(entity_t *ent); @@ -700,8 +715,8 @@ void CL_ClearState (void); int CL_ReadFromServer (void); -void CL_WriteToServer (usercmd_t *cmd); -void CL_BaseMove (usercmd_t *cmd); +void CL_WriteToServer (void); +void CL_BaseMove (void); float CL_KeyState (kbutton_t *key); diff --git a/common.c b/common.c index 6f8065a6..75c7ae9b 100644 --- a/common.c +++ b/common.c @@ -273,9 +273,9 @@ void MSG_WriteCoord32f (sizebuf_t *sb, float f) void MSG_WriteCoord (sizebuf_t *sb, float f, int protocol) { - if (protocol == PROTOCOL_QUAKE) + if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_NEHAHRAMOVIE) MSG_WriteCoord13i (sb, f); - else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5) + else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5 || protocol == PROTOCOL_DARKPLACES6) MSG_WriteCoord32f (sb, f); else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4) MSG_WriteCoord16i (sb, f); @@ -314,7 +314,7 @@ void MSG_WriteAngle32f (sizebuf_t *sb, float f) void MSG_WriteAngle (sizebuf_t *sb, float f, int protocol) { - if (protocol == PROTOCOL_DARKPLACES5) + if (protocol == PROTOCOL_DARKPLACES5 || protocol == PROTOCOL_DARKPLACES6) MSG_WriteAngle16i (sb, f); else MSG_WriteAngle8i (sb, f); @@ -445,9 +445,9 @@ float MSG_ReadCoord32f (void) float MSG_ReadCoord (int protocol) { - if (protocol == PROTOCOL_QUAKE || protocol == 250) + if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_NEHAHRAMOVIE) return MSG_ReadCoord13i(); - else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5) + else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5 || protocol == PROTOCOL_DARKPLACES6) return MSG_ReadCoord32f(); else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4) return MSG_ReadCoord16i(); @@ -480,7 +480,7 @@ float MSG_ReadAngle32f (void) float MSG_ReadAngle (int protocol) { - if (protocol == PROTOCOL_DARKPLACES5) + if (protocol == PROTOCOL_DARKPLACES5 || protocol == PROTOCOL_DARKPLACES6) return MSG_ReadAngle16i (); else return MSG_ReadAngle8i (); diff --git a/gl_draw.c b/gl_draw.c index 336912a1..e63b7d4b 100644 --- a/gl_draw.c +++ b/gl_draw.c @@ -308,6 +308,8 @@ cachepic_t *Draw_CachePic (char *path) pic->tex = draw_generateconchars(); if (pic->tex == NULL && !strcmp(path, "ui/mousepointer.tga")) pic->tex = draw_generatemousepointer(); + if (pic->tex == NULL && !strcmp(path, "gfx/prydoncursor001.tga")) + pic->tex = draw_generatemousepointer(); if (pic->tex == NULL && !strcmp(path, "gfx/crosshair1.tga")) pic->tex = draw_generatecrosshair(0); if (pic->tex == NULL && !strcmp(path, "gfx/crosshair2.tga")) diff --git a/gl_models.c b/gl_models.c index 5bd5f03e..1b2b134c 100644 --- a/gl_models.c +++ b/gl_models.c @@ -144,6 +144,9 @@ void R_DrawAliasModelCallback (const void *calldata1, int calldata2) } else tint[0] = tint[1] = tint[2] = 1; + tint[0] *= ent->colormod[0]; + tint[1] *= ent->colormod[1]; + tint[2] *= ent->colormod[2]; if (!fullbright && !(ent->flags & RENDER_TRANSPARENT)) colorscale *= r_lightmapintensity; colorscale *= ifog; diff --git a/gl_rsurf.c b/gl_rsurf.c index 72d39741..720f5c71 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -832,7 +832,7 @@ static void RSurfShader_Transparent_Callback(const void *calldata1, int calldata base = fullbright ? 2.0f : r_ambient.value * (1.0f / 64.0f); if (surf->flags & SURF_DRAWTURB) base *= 0.5f; - if ((surf->flags & SURF_DRAWTURB) && gl_textureshader && r_watershader.value && !fogenabled && fullbright) + if ((surf->flags & SURF_DRAWTURB) && gl_textureshader && r_watershader.value && !fogenabled && fullbright && ent->colormod[0] == 1 && ent->colormod[1] == 1 && ent->colormod[2] == 1) { // NVIDIA Geforce3 distortion texture shader on water GL_Color(1, 1, 1, currentalpha); @@ -882,7 +882,7 @@ static void RSurfShader_Transparent_Callback(const void *calldata1, int calldata m.texrgbscale[0] = 4; colorscale *= 0.25f; } - R_FillColors(varray_color4f, surf->mesh.num_vertices, base, base, base, currentalpha); + R_FillColors(varray_color4f, surf->mesh.num_vertices, base * ent->colormod[0], base * ent->colormod[1], base * ent->colormod[2], currentalpha); if (!fullbright) { if (surf->dlightframe == r_framecount) @@ -963,7 +963,7 @@ static void RSurfShader_OpaqueWall_Pass_BaseCombine_TextureLightmapDetailGlow(co m.tex[3] = R_GetTexture(texture->skin.glow); m.texcombinergb[3] = GL_ADD; } - GL_Color(r_lightmapintensity, r_lightmapintensity, r_lightmapintensity, 1); + GL_Color(r_lightmapintensity * ent->colormod[0], r_lightmapintensity * ent->colormod[1], r_lightmapintensity * ent->colormod[2], 1); while((surf = *surfchain++) != NULL) { @@ -998,7 +998,7 @@ static void RSurfShader_OpaqueWall_Pass_BaseCombine_TextureLightmapDetail(const m.texrgbscale[1] = 2; m.tex[2] = R_GetTexture(texture->skin.detail); m.texrgbscale[2] = 2; - GL_Color(r_lightmapintensity, r_lightmapintensity, r_lightmapintensity, 1); + GL_Color(r_lightmapintensity * ent->colormod[0], r_lightmapintensity * ent->colormod[1], r_lightmapintensity * ent->colormod[2], 1); while((surf = *surfchain++) != NULL) { @@ -1030,7 +1030,7 @@ static void RSurfShader_OpaqueWall_Pass_BaseCombine_TextureLightmap(const entity m.tex[0] = R_GetTexture(texture->skin.base); m.tex[1] = R_GetTexture((**surfchain).lightmaptexture); m.texrgbscale[1] = 2; - GL_Color(r_lightmapintensity, r_lightmapintensity, r_lightmapintensity, 1); + GL_Color(r_lightmapintensity * ent->colormod[0], r_lightmapintensity * ent->colormod[1], r_lightmapintensity * ent->colormod[2], 1); while((surf = *surfchain++) != NULL) { if (surf->visframe == r_framecount) @@ -1058,9 +1058,9 @@ static void RSurfShader_OpaqueWall_Pass_BaseTexture(const entity_render_t *ent, GL_BlendFunc(GL_ONE, GL_ZERO); m.tex[0] = R_GetTexture(texture->skin.base); if (ent->flags & RENDER_LIGHT) - GL_Color(r_lightmapintensity, r_lightmapintensity, r_lightmapintensity, 1); + GL_Color(r_lightmapintensity * ent->colormod[0], r_lightmapintensity * ent->colormod[1], r_lightmapintensity * ent->colormod[2], 1); else - GL_Color(1, 1, 1, 1); + GL_Color(ent->colormod[0], ent->colormod[1], ent->colormod[2], 1); while((surf = *surfchain++) != NULL) { if (surf->visframe == r_framecount) @@ -1111,7 +1111,7 @@ static void RSurfShader_OpaqueWall_Pass_BaseAmbient(const entity_render_t *ent, GL_DepthMask(false); GL_DepthTest(true); m.tex[0] = R_GetTexture(texture->skin.base); - GL_Color(r_ambient.value * (1.0f / 128.0f), r_ambient.value * (1.0f / 128.0f), r_ambient.value * (1.0f / 128.0f), 1); + GL_Color(r_ambient.value * (1.0f / 128.0f) * ent->colormod[0], r_ambient.value * (1.0f / 128.0f) * ent->colormod[1], r_ambient.value * (1.0f / 128.0f) * ent->colormod[2], 1); while((surf = *surfchain++) != NULL) { if (surf->visframe == r_framecount) @@ -1948,20 +1948,20 @@ void R_Q3BSP_DrawFace_TransparentCallback(const void *voident, int facenumber) { m.tex[1] = R_GetTexture(face->lightmaptexture); m.pointer_texcoord[1] = face->data_texcoordlightmap2f; - GL_Color(1, 1, 1, ent->alpha); + GL_Color(ent->colormod[0], ent->colormod[1], ent->colormod[2], ent->alpha); } else { - if (ent->alpha == 1) + if (ent->colormod[0] == 1 && ent->colormod[1] == 1 && ent->colormod[2] == 1 && ent->alpha == 1) m.pointer_color = face->data_color4f; else { int i; for (i = 0;i < face->num_vertices;i++) { - varray_color4f[i*4+0] = face->data_color4f[i*4+0]; - varray_color4f[i*4+1] = face->data_color4f[i*4+1]; - varray_color4f[i*4+2] = face->data_color4f[i*4+2]; + varray_color4f[i*4+0] = face->data_color4f[i*4+0] * ent->colormod[0]; + varray_color4f[i*4+1] = face->data_color4f[i*4+1] * ent->colormod[1]; + varray_color4f[i*4+2] = face->data_color4f[i*4+2] * ent->colormod[2]; varray_color4f[i*4+3] = face->data_color4f[i*4+3] * ent->alpha; } m.pointer_color = varray_color4f; @@ -1973,9 +1973,9 @@ void R_Q3BSP_DrawFace_TransparentCallback(const void *voident, int facenumber) int i; for (i = 0;i < face->num_vertices;i++) { - varray_color4f[i*4+0] = face->data_color4f[i*4+0] * 2.0f; - varray_color4f[i*4+1] = face->data_color4f[i*4+1] * 2.0f; - varray_color4f[i*4+2] = face->data_color4f[i*4+2] * 2.0f; + varray_color4f[i*4+0] = face->data_color4f[i*4+0] * ent->colormod[0] * 2.0f; + varray_color4f[i*4+1] = face->data_color4f[i*4+1] * ent->colormod[1] * 2.0f; + varray_color4f[i*4+2] = face->data_color4f[i*4+2] * ent->colormod[2] * 2.0f; varray_color4f[i*4+3] = face->data_color4f[i*4+3] * ent->alpha; } m.pointer_color = varray_color4f; @@ -2139,7 +2139,7 @@ void R_Q3BSP_DrawFaceList(entity_render_t *ent, q3mtexture_t *t, int texturenumf GL_DepthMask(true); GL_DepthTest(true); GL_BlendFunc(GL_ONE, GL_ZERO); - GL_Color(1, 1, 1, 1); + GL_Color(ent->colormod[0], ent->colormod[1], ent->colormod[2], 1); if (t->textureflags & Q3TEXTUREFLAG_TWOSIDED) qglDisable(GL_CULL_FACE); memset(&m, 0, sizeof(m)); @@ -2156,6 +2156,7 @@ void R_Q3BSP_DrawFaceList(entity_render_t *ent, q3mtexture_t *t, int texturenumf } if (t->skin.glow) { + GL_Color(1, 1, 1, 1); GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); GL_DepthMask(false); m.tex[0] = R_GetTexture(t->skin.glow); @@ -2210,19 +2211,19 @@ void R_Q3BSP_DrawFaceList(entity_render_t *ent, q3mtexture_t *t, int texturenumf m.texrgbscale[1] = 2; if (face->lightmaptexture) { - GL_Color(r_lightmapintensity, r_lightmapintensity, r_lightmapintensity, 1); + GL_Color(r_lightmapintensity * ent->colormod[0], r_lightmapintensity * ent->colormod[1], r_lightmapintensity * ent->colormod[2], 1); m.pointer_color = NULL; } - else if (r_lightmapintensity == 1) + else if (r_lightmapintensity == 1 && ent->colormod[0] == 1 && ent->colormod[1] == 1 && ent->colormod[2] == 1) m.pointer_color = face->data_color4f; else { m.pointer_color = varray_color4f; for (i = 0;i < face->num_vertices;i++) { - varray_color4f[i*4+0] = face->data_color4f[i*4+0] * r_lightmapintensity; - varray_color4f[i*4+1] = face->data_color4f[i*4+1] * r_lightmapintensity; - varray_color4f[i*4+2] = face->data_color4f[i*4+2] * r_lightmapintensity; + varray_color4f[i*4+0] = face->data_color4f[i*4+0] * ent->colormod[0] * r_lightmapintensity; + varray_color4f[i*4+1] = face->data_color4f[i*4+1] * ent->colormod[1] * r_lightmapintensity; + varray_color4f[i*4+2] = face->data_color4f[i*4+2] * ent->colormod[2] * r_lightmapintensity; varray_color4f[i*4+3] = face->data_color4f[i*4+3]; } } @@ -2257,7 +2258,7 @@ void R_Q3BSP_DrawFaceList(entity_render_t *ent, q3mtexture_t *t, int texturenumf } GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR); GL_DepthMask(false); - GL_Color(r_lightmapintensity, r_lightmapintensity, r_lightmapintensity, 1); + GL_Color(r_lightmapintensity * ent->colormod[0], r_lightmapintensity * ent->colormod[1], r_lightmapintensity * ent->colormod[2], 1); memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(t->skin.base); for (texturefaceindex = 0;texturefaceindex < texturenumfaces;texturefaceindex++) @@ -2275,7 +2276,7 @@ void R_Q3BSP_DrawFaceList(entity_render_t *ent, q3mtexture_t *t, int texturenumf { GL_BlendFunc(GL_ONE, GL_ONE); GL_DepthMask(false); - GL_Color(r_ambient.value * (1.0f / 128.0f), r_ambient.value * (1.0f / 128.0f), r_ambient.value * (1.0f / 128.0f), 1); + GL_Color(r_ambient.value * (1.0f / 128.0f) * ent->colormod[0], r_ambient.value * (1.0f / 128.0f) * ent->colormod[1], r_ambient.value * (1.0f / 128.0f) * ent->colormod[2], 1); memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(t->skin.base); for (texturefaceindex = 0;texturefaceindex < texturenumfaces;texturefaceindex++) diff --git a/host.c b/host.c index 8d9d9f5e..49cc616a 100644 --- a/host.c +++ b/host.c @@ -737,7 +737,6 @@ void _Host_Frame (float time) static double time2 = 0; static double time3 = 0; int pass1, pass2, pass3; - usercmd_t cmd; // Used for receiving input if (setjmp(host_abortserver)) return; // something bad happened, or the server disconnected @@ -758,14 +757,14 @@ void _Host_Frame (float time) IN_Commands(); // Collect input into cmd - IN_ProcessMove(&cmd); + IN_ProcessMove(); // process console commands Cbuf_Execute(); // if running the server locally, make intentions now if (cls.state == ca_connected && sv.active) - CL_SendCmd(&cmd); + CL_SendCmd(); //------------------- // @@ -795,7 +794,7 @@ void _Host_Frame (float time) // if running the server remotely, send intentions now after // the incoming messages have been read if (!sv.active) - CL_SendCmd(&cmd); + CL_SendCmd(); CL_ReadFromServer(); } diff --git a/host_cmd.c b/host_cmd.c index d3fcd5f6..8a616af2 100644 --- a/host_cmd.c +++ b/host_cmd.c @@ -75,6 +75,7 @@ void Host_Status_f (void) case PROTOCOL_DARKPLACES3: protocolname = "PROTOCOL_DARKPLACES3";break; case PROTOCOL_DARKPLACES4: protocolname = "PROTOCOL_DARKPLACES4";break; case PROTOCOL_DARKPLACES5: protocolname = "PROTOCOL_DARKPLACES5";break; + case PROTOCOL_DARKPLACES6: protocolname = "PROTOCOL_DARKPLACES6";break; default: protocolname = "PROTOCOL_UNKNOWN";break; } print ("protocol: %i (%s)\n", sv.protocol, protocolname); @@ -1133,6 +1134,7 @@ void Host_Spawn_f (void) client_t *client; func_t RestoreGame; mfunction_t *f; + int stats[MAX_CL_STATS]; if (cmd_source == src_command) { @@ -1247,7 +1249,7 @@ void Host_Spawn_f (void) MSG_WriteAngle (&host_client->message, host_client->edict->v->angles[1], sv.protocol); MSG_WriteAngle (&host_client->message, 0, sv.protocol); - SV_WriteClientdataToMessage (host_client->edict, &host_client->message); + SV_WriteClientdataToMessage (host_client, host_client->edict, &host_client->message, stats); MSG_WriteByte (&host_client->message, svc_signonnum); MSG_WriteByte (&host_client->message, 3); diff --git a/input.h b/input.h index f48aa9c4..8572a950 100644 --- a/input.h +++ b/input.h @@ -34,15 +34,15 @@ void IN_Commands (void); // oportunity for devices to stick commands on the script buffer // AK added to allow mouse movement for the menu -void IN_ProcessMove(usercmd_t *cmd); +void IN_ProcessMove(void); -void IN_Move (usercmd_t *cmd); +void IN_Move (void); // add additional movement on top of the keyboard move cmd void IN_PreMove(void); void IN_PostMove(void); -void IN_Mouse(usercmd_t *cmd, float mx, float my); +void IN_Mouse(float mx, float my); void IN_ClearStates (void); // restores all button and position states to defaults diff --git a/pr_cmds.c b/pr_cmds.c index ddf9d458..5214f332 100644 --- a/pr_cmds.c +++ b/pr_cmds.c @@ -70,6 +70,8 @@ void PF_VarString(int first, char *out, int outlength) } char *ENGINE_EXTENSIONS = +"DP_BUTTONCHAT " +"DP_BUTTONUSE " "DP_CL_LOADSKY " "DP_CON_SET " "DP_CON_SETA " @@ -165,6 +167,7 @@ char *ENGINE_EXTENSIONS = "NEH_CMD_PLAY2 " "NEH_RESTOREGAME " "NXQ_GFX_LETTERBOX " +"PRYDON_CLIENTCURSOR " "TENEBRAE_GFX_DLIGHTS " "TW_SV_STEPCONTROL " ; @@ -351,10 +354,10 @@ PF_setmodel setmodel(entity, model) ================= */ +static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16}; void PF_setmodel (void) { edict_t *e; - char *m, **check; model_t *mod; int i; @@ -363,24 +366,19 @@ void PF_setmodel (void) PF_WARNING("setmodel: can not modify world entity\n"); if (e->e->free) PF_WARNING("setmodel: can not modify free entity\n"); - m = G_STRING(OFS_PARM1); - -// check to see if model was properly precached - for (i=0, check = sv.model_precache ; *check ; i++, check++) - if (!strcmp(*check, m)) - break; - - if (!*check) - PF_WARNING(va("setmodel: no precache for model \"%s\"\n", m)); - - - e->v->model = PR_SetString(*check); + i = SV_ModelIndex(G_STRING(OFS_PARM1), 1); + e->v->model = PR_SetString(sv.model_precache[i]); e->v->modelindex = i; - mod = sv.models[ (int)e->v->modelindex]; + mod = sv.models[i]; if (mod) - SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true); + { + if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer) + SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true); + else + SetMinMaxSize (e, quakemins, quakemaxs, true); + } else SetMinMaxSize (e, vec3_origin, vec3_origin, true); } @@ -626,7 +624,6 @@ PF_ambientsound */ void PF_ambientsound (void) { - char **check; char *samp; float *pos; float vol, attenuation; @@ -638,15 +635,9 @@ void PF_ambientsound (void) attenuation = G_FLOAT(OFS_PARM3); // check to see if samp was properly precached - for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++) - if (!strcmp(*check,samp)) - break; - - if (!*check) - { - Con_Printf("no precache: %s\n", samp); + soundnum = SV_SoundIndex(samp, 1); + if (!soundnum) return; - } large = false; if (soundnum >= 256) @@ -1356,59 +1347,17 @@ void PF_precache_file (void) G_INT(OFS_RETURN) = G_INT(OFS_PARM0); } + void PF_precache_sound (void) { - char *s; - int i; - int limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_SOUNDS); - - if (sv.state != ss_loading) - PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions"); - - s = G_STRING(OFS_PARM0); + SV_SoundIndex(G_STRING(OFS_PARM0), 2); G_INT(OFS_RETURN) = G_INT(OFS_PARM0); - PR_CheckEmptyString (s); - - for (i=0 ; ibrush.ishlbsp && ((!s) || (!s[0]))) - return; + SV_ModelIndex(G_STRING(OFS_PARM0), 2); G_INT(OFS_RETURN) = G_INT(OFS_PARM0); - PR_CheckEmptyString (s); - - for (i = 0;i < limit;i++) - { - if (!sv.model_precache[i]) - { - sv.model_precache[i] = s; - sv.models[i] = Mod_ForName (s, true, false, false); - return; - } - if (!strcmp(sv.model_precache[i], s)) - return; - } - PF_ERROR("PF_precache_model: overflow"); } @@ -2250,8 +2199,8 @@ void PF_effect (void) if (!s || !s[0]) PF_WARNING("effect: no model specified\n"); - i = SV_ModelIndex(s); - if (i < 0) + i = SV_ModelIndex(s, 1); + if (!i) PF_WARNING("effect: model not precached\n"); SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4)); } @@ -3145,7 +3094,10 @@ int SV_GetTagIndex (edict_t *e, char *tagname) int tagindex, i; model_t *model; - model = sv.models[(int)e->v->modelindex]; + i = e->v->modelindex; + if (i < 1 || i >= MAX_MODELS) + return -1; + model = sv.models[i]; tagindex = -1; if (model->data_overridetagnamesforskin && (unsigned int)e->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames) @@ -3233,14 +3185,18 @@ int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex) { attachent = EDICT_NUM(val->edict); // to this it entity our entity is attached val = GETEDICTFIELDVALUE(ent, eval_tag_index); - if (val->_float) - {// got tagname on parent entity attachment tag via tag_index (and got it's matrix) + Matrix4x4_CreateIdentity(&attachmatrix); + if (val->_float >= 1 && attachent->v->modelindex >= 1 && attachent->v->modelindex < MAX_MODELS) + { model = sv.models[(int)attachent->v->modelindex]; - reqtag = (val->_float - 1) + attachent->v->frame*model->alias.aliasnum_tags; - Matrix4x4_Copy(&attachmatrix, &model->alias.aliasdata_tags[reqtag].matrix); + if (val->_float < model->alias.aliasnum_tags) + { + // got tagname on parent entity attachment tag via tag_index (and got it's matrix) + model = sv.models[(int)attachent->v->modelindex]; + reqtag = (val->_float - 1) + attachent->v->frame*model->alias.aliasnum_tags; + Matrix4x4_Copy(&attachmatrix, &model->alias.aliasdata_tags[reqtag].matrix); + } } - else - Matrix4x4_CreateIdentity(&attachmatrix); // apply transformation by child entity matrix val = GETEDICTFIELDVALUE(ent, eval_scale); @@ -3264,7 +3220,7 @@ int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex) attachloop += 1; if (attachloop > 255) // prevent runaway looping return 5; - } + } while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict); } diff --git a/pr_edict.c b/pr_edict.c index bbfd1e4d..3e20a98d 100644 --- a/pr_edict.c +++ b/pr_edict.c @@ -92,6 +92,8 @@ int eval_button5; int eval_button6; int eval_button7; int eval_button8; +int eval_buttonuse; +int eval_buttonchat; int eval_glow_size; int eval_glow_trail; int eval_glow_color; @@ -126,6 +128,12 @@ int eval_light_lev; int eval_color; int eval_style; int eval_pflags; +int eval_cursor_active; +int eval_cursor_screen; +int eval_cursor_trace_start; +int eval_cursor_trace_endpos; +int eval_cursor_trace_ent; +int eval_colormod; mfunction_t *SV_PlayerPhysicsQC; mfunction_t *EndFrameQC; @@ -150,6 +158,8 @@ void FindEdictFieldOffsets(void) eval_button6 = FindFieldOffset("button6"); eval_button7 = FindFieldOffset("button7"); eval_button8 = FindFieldOffset("button8"); + eval_buttonuse = FindFieldOffset("buttonuse"); + eval_buttonchat = FindFieldOffset("buttonchat"); eval_glow_size = FindFieldOffset("glow_size"); eval_glow_trail = FindFieldOffset("glow_trail"); eval_glow_color = FindFieldOffset("glow_color"); @@ -184,6 +194,12 @@ void FindEdictFieldOffsets(void) eval_color = FindFieldOffset("color"); eval_style = FindFieldOffset("style"); eval_pflags = FindFieldOffset("pflags"); + eval_cursor_active = FindFieldOffset("cursor_active"); + eval_cursor_screen = FindFieldOffset("cursor_screen"); + eval_cursor_trace_start = FindFieldOffset("cursor_trace_start"); + eval_cursor_trace_endpos = FindFieldOffset("cursor_trace_endpos"); + eval_cursor_trace_ent = FindFieldOffset("cursor_trace_ent"); + eval_colormod = FindFieldOffset("colormod"); // LordHavoc: allowing QuakeC to override the player movement code SV_PlayerPhysicsQC = ED_FindFunction ("SV_PlayerPhysics"); @@ -1205,46 +1221,55 @@ dpfield_t; dpfield_t dpfields[] = { - {ev_float, "gravity"}, + {ev_entity, "cursor_trace_ent"}, + {ev_entity, "drawonlytoclient"}, + {ev_entity, "exteriormodeltoclient"}, + {ev_entity, "nodrawtoclient"}, + {ev_entity, "tag_entity"}, + {ev_entity, "viewmodelforclient"}, + {ev_float, "alpha"}, + {ev_float, "ammo_cells1"}, + {ev_float, "ammo_lava_nails"}, + {ev_float, "ammo_multi_rockets"}, + {ev_float, "ammo_nails1"}, + {ev_float, "ammo_plasma"}, + {ev_float, "ammo_rockets1"}, + {ev_float, "ammo_shells1"}, {ev_float, "button3"}, {ev_float, "button4"}, {ev_float, "button5"}, {ev_float, "button6"}, {ev_float, "button7"}, {ev_float, "button8"}, + {ev_float, "buttonchat"}, + {ev_float, "buttonuse"}, + {ev_float, "clientcolors"}, + {ev_float, "cursor_active"}, + {ev_float, "fullbright"}, + {ev_float, "glow_color"}, {ev_float, "glow_size"}, {ev_float, "glow_trail"}, - {ev_float, "glow_color"}, - {ev_float, "items2"}, - {ev_float, "scale"}, - {ev_float, "alpha"}, - {ev_float, "renderamt"}, - {ev_float, "rendermode"}, - {ev_float, "fullbright"}, - {ev_float, "ammo_shells1"}, - {ev_float, "ammo_nails1"}, - {ev_float, "ammo_lava_nails"}, - {ev_float, "ammo_rockets1"}, - {ev_float, "ammo_multi_rockets"}, - {ev_float, "ammo_cells1"}, - {ev_float, "ammo_plasma"}, + {ev_float, "gravity"}, {ev_float, "idealpitch"}, - {ev_float, "pitch_speed"}, - {ev_entity, "viewmodelforclient"}, - {ev_entity, "nodrawtoclient"}, - {ev_entity, "exteriormodeltoclient"}, - {ev_entity, "drawonlytoclient"}, + {ev_float, "items2"}, + {ev_float, "light_lev"}, + {ev_float, "pflags"}, {ev_float, "ping"}, - {ev_vector, "movement"}, + {ev_float, "pitch_speed"}, {ev_float, "pmodel"}, - {ev_vector, "punchvector"}, - {ev_float, "clientcolors"}, - {ev_entity, "tag_entity"}, + {ev_float, "renderamt"}, // HalfLife support + {ev_float, "rendermode"}, // HalfLife support + {ev_float, "scale"}, + {ev_float, "style"}, {ev_float, "tag_index"}, - {ev_float, "light_lev"}, + {ev_float, "viewzoom"}, {ev_vector, "color"}, - {ev_float, "style"}, - {ev_float, "pflags"} + {ev_vector, "colormod"}, + {ev_vector, "cursor_screen"}, + {ev_vector, "cursor_trace_endpos"}, + {ev_vector, "cursor_trace_start"}, + {ev_vector, "movement"}, + {ev_vector, "punchvector"} }; /* diff --git a/progs.h b/progs.h index 99cf61fc..8e717d3f 100644 --- a/progs.h +++ b/progs.h @@ -89,6 +89,8 @@ extern int eval_button5; extern int eval_button6; extern int eval_button7; extern int eval_button8; +extern int eval_buttonuse; +extern int eval_buttonchat; extern int eval_glow_size; extern int eval_glow_trail; extern int eval_glow_color; @@ -123,6 +125,12 @@ extern int eval_light_lev; extern int eval_color; extern int eval_style; extern int eval_pflags; +extern int eval_cursor_active; +extern int eval_cursor_screen; +extern int eval_cursor_trace_start; +extern int eval_cursor_trace_endpos; +extern int eval_cursor_trace_ent; +extern int eval_colormod; #define GETEDICTFIELDVALUE(ed, fieldoffset) (fieldoffset ? (eval_t *)((qbyte *)ed->v + fieldoffset) : NULL) diff --git a/protocol.c b/protocol.c index b537147a..c044a8df 100644 --- a/protocol.c +++ b/protocol.c @@ -30,9 +30,9 @@ entity_state_t defaultstate = 254,//unsigned char glowcolor; 0,//unsigned char flags; 0,//unsigned char tagindex; - 255,//unsigned char colormod; + {32, 32, 32},//unsigned char colormod[3]; // padding to a multiple of 8 bytes (to align the double time) - {0,0,0,0}//unsigned char unused[4]; // ! + {0,0}//unsigned char unused[2]; // ! }; // keep track of quake entities because they need to be killed if they get stale @@ -100,7 +100,7 @@ void EntityFrameQuake_ReadEntity(int bits) if (bits & U_EFFECTS2) s.effects = (s.effects & 0x00FF) | (MSG_ReadByte() << 8); if (bits & U_GLOWSIZE) s.glowsize = MSG_ReadByte(); if (bits & U_GLOWCOLOR) s.glowcolor = MSG_ReadByte(); - if (bits & U_COLORMOD) s.colormod = MSG_ReadByte(); + if (bits & U_COLORMOD) {int c = MSG_ReadByte();s.colormod[0] = (qbyte)(((c >> 5) & 7) * (32.0f / 7.0f));s.colormod[1] = (qbyte)(((c >> 2) & 7) * (32.0f / 7.0f));s.colormod[2] = (qbyte)((c & 3) * (32.0f / 3.0f));} if (bits & U_GLOWTRAIL) s.flags |= RENDER_GLOWTRAIL; if (bits & U_FRAME2) s.frame = (s.frame & 0x00FF) | (MSG_ReadByte() << 8); if (bits & U_MODEL2) s.modelindex = (s.modelindex & 0x00FF) | (MSG_ReadByte() << 8); @@ -278,7 +278,7 @@ void EntityFrameQuake_WriteFrame(sizebuf_t *msg, int numstates, const entity_sta if (bits & U_EFFECTS2) MSG_WriteByte(&buf, s->effects >> 8); if (bits & U_GLOWSIZE) MSG_WriteByte(&buf, s->glowsize); if (bits & U_GLOWCOLOR) MSG_WriteByte(&buf, s->glowcolor); - if (bits & U_COLORMOD) MSG_WriteByte(&buf, s->colormod); + if (bits & U_COLORMOD) {int c = ((int)bound(0, s->colormod[0] * (7.0f / 32.0f), 7) << 5) | ((int)bound(0, s->colormod[0] * (7.0f / 32.0f), 7) << 2) | ((int)bound(0, s->colormod[0] * (3.0f / 32.0f), 3) << 0);MSG_WriteByte(&buf, c);} if (bits & U_FRAME2) MSG_WriteByte(&buf, s->frame >> 8); if (bits & U_MODEL2) MSG_WriteByte(&buf, s->modelindex >> 8); @@ -385,7 +385,7 @@ void EntityState_WriteFields(const entity_state_t *ent, sizebuf_t *msg, unsigned if (bits & E_ORIGIN3) MSG_WriteCoord16i(msg, ent->origin[2]); } - else if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5) + else if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5 || sv.protocol == PROTOCOL_DARKPLACES6) { // LordHavoc: have to write flags first, as they can modify protocol if (bits & E_FLAGS) @@ -409,7 +409,7 @@ void EntityState_WriteFields(const entity_state_t *ent, sizebuf_t *msg, unsigned MSG_WriteCoord32f(msg, ent->origin[2]); } } - if (sv.protocol == PROTOCOL_DARKPLACES5 && !(ent->flags & RENDER_LOWPRECISION)) + if ((sv.protocol == PROTOCOL_DARKPLACES5 || sv.protocol == PROTOCOL_DARKPLACES6) && !(ent->flags & RENDER_LOWPRECISION)) { if (bits & E_ANGLE1) MSG_WriteAngle16i(msg, ent->angles[0]); @@ -525,7 +525,7 @@ void EntityState_ReadFields(entity_state_t *e, unsigned int bits) if (bits & E_ORIGIN3) e->origin[2] = MSG_ReadCoord16i(); } - else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5) + else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5 || cl.protocol == PROTOCOL_DARKPLACES6) { if (bits & E_FLAGS) e->flags = MSG_ReadByte(); @@ -550,7 +550,7 @@ void EntityState_ReadFields(entity_state_t *e, unsigned int bits) } else Host_Error("EntityState_ReadFields: unknown cl.protocol %i\n", cl.protocol); - if (cl.protocol == PROTOCOL_DARKPLACES5 && !(e->flags & RENDER_LOWPRECISION)) + if ((cl.protocol == PROTOCOL_DARKPLACES5 || cl.protocol == PROTOCOL_DARKPLACES6) && !(e->flags & RENDER_LOWPRECISION)) { if (bits & E_ANGLE1) e->angles[0] = MSG_ReadAngle16i(); @@ -861,7 +861,9 @@ void EntityFrame_CL_ReadFrame(void) // read the frame header info f->time = cl.mtime[0]; number = MSG_ReadLong(); - cl.latestframenum = f->framenum = MSG_ReadLong(); + for (i = 0;i < LATESTFRAMENUMS-1;i++) + cl.latestframenums[i] = cl.latestframenums[i+1]; + cl.latestframenums[LATESTFRAMENUMS-1] = f->framenum = MSG_ReadLong(); f->eye[0] = MSG_ReadFloat(); f->eye[1] = MSG_ReadFloat(); f->eye[2] = MSG_ReadFloat(); @@ -1118,7 +1120,9 @@ void EntityFrame4_CL_ReadFrame(void) // read the number of the frame this refers to referenceframenum = MSG_ReadLong(); // read the number of this frame - cl.latestframenum = framenum = MSG_ReadLong(); + for (i = 0;i < LATESTFRAMENUMS-1;i++) + cl.latestframenums[i] = cl.latestframenums[i+1]; + cl.latestframenums[LATESTFRAMENUMS-1] = framenum = MSG_ReadLong(); // read the start number enumber = (unsigned short) MSG_ReadShort(); if (developer_networkentities.integer >= 1) @@ -1519,6 +1523,12 @@ void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbi MSG_WriteByte(msg, s->glowsize); MSG_WriteByte(msg, s->glowcolor); } + if (bits & E5_COLORMOD) + { + MSG_WriteByte(msg, s->colormod[0]); + MSG_WriteByte(msg, s->colormod[1]); + MSG_WriteByte(msg, s->colormod[2]); + } } } @@ -1623,6 +1633,12 @@ void EntityState5_ReadUpdate(entity_state_t *s) s->glowsize = MSG_ReadByte(); s->glowcolor = MSG_ReadByte(); } + if (bits & E5_COLORMOD) + { + s->colormod[0] = MSG_ReadByte(); + s->colormod[1] = MSG_ReadByte(); + s->colormod[2] = MSG_ReadByte(); + } if (developer_networkentities.integer >= 2) @@ -1674,6 +1690,8 @@ void EntityState5_ReadUpdate(entity_state_t *s) Con_Printf(" E5_LIGHT %i:%i:%i:%i %i:%i", s->light[0], s->light[1], s->light[2], s->light[3], s->lightstyle, s->lightpflags); if (bits & E5_GLOW) Con_Printf(" E5_GLOW %i:%i", s->glowsize * 4, s->glowcolor); + if (bits & E5_COLORMOD) + Con_Printf(" E5_COLORMOD %f:%f:%f", s->colormod[0] / 32.0f, s->colormod[1] / 32.0f, s->colormod[2] / 32.0f); Con_Print("\n"); } } @@ -1711,6 +1729,8 @@ int EntityState5_DeltaBits(const entity_state_t *o, const entity_state_t *n) bits |= E5_LIGHT; if (o->glowsize != n->glowsize || o->glowcolor != n->glowcolor) bits |= E5_GLOW; + if (o->colormod[0] != n->colormod[0] || o->colormod[1] != n->colormod[1] || o->colormod[2] != n->colormod[2]) + bits |= E5_COLORMOD; } else if (o->active) @@ -1720,11 +1740,13 @@ int EntityState5_DeltaBits(const entity_state_t *o, const entity_state_t *n) void EntityFrame5_CL_ReadFrame(void) { - int n, enumber; + int i, n, enumber; entity_t *ent; entity_state_t *s; // read the number of this frame to echo back in next input packet - cl.latestframenum = MSG_ReadLong(); + for (i = 0;i < LATESTFRAMENUMS-1;i++) + cl.latestframenums[i] = cl.latestframenums[i+1]; + cl.latestframenums[LATESTFRAMENUMS-1] = MSG_ReadLong(); // read entity numbers until we find a 0x8000 // (which would be remove world entity, but is actually a terminator) while ((n = (unsigned short)MSG_ReadShort()) != 0x8000 && !msg_badread) @@ -1766,23 +1788,16 @@ void EntityFrame5_CL_ReadFrame(void) } } -void EntityFrame5_AckFrame(entityframe5_database_t *d, int framenum, int viewentnum) +void EntityFrame5_LostFrame(entityframe5_database_t *d, int framenum, int viewentnum) { int i, j, k, l, bits; entityframe5_changestate_t *s, *s2; entityframe5_packetlog_t *p, *p2; - // scan for packets made obsolete by this ack + qbyte statsdeltabits[(MAX_CL_STATS+7)/8]; + // scan for packets that were lost for (i = 0, p = d->packetlog;i < ENTITYFRAME5_MAXPACKETLOGS;i++, p++) { - // skip packets that are empty or in the future - if (p->packetnumber == 0 || p->packetnumber > framenum) - continue; - // if the packetnumber matches it is deleted without any processing - // (since it was received). - // if the packet number is less than this ack it was lost and its - // important information will be repeated in this update if it is not - // already obsolete due to a later update. - if (p->packetnumber < framenum) + if (p->packetnumber && p->packetnumber <= framenum) { // packet was lost - merge deltabits into the main array so they // will be re-sent, but only if there is no newer update of that @@ -1797,7 +1812,7 @@ void EntityFrame5_AckFrame(entityframe5_database_t *d, int framenum, int viewent { if (p2->packetnumber > framenum) { - for (l = 0, s2 = p2->states;l < p2->numstates;l++, p2++) + for (l = 0, s2 = p2->states;l < p2->numstates;l++, s2++) { if (s2->number == s->number) { @@ -1815,16 +1830,37 @@ void EntityFrame5_AckFrame(entityframe5_database_t *d, int framenum, int viewent d->priorities[s->number] = EntityState5_Priority(d, d->states + viewentnum, d->states + s->number, d->deltabits[s->number], d->latestframenum - d->updateframenum[s->number]); } } + // mark lost stats + for (j = 0;j < MAX_CL_STATS;j++) + { + for (l = 0;l < (MAX_CL_STATS+7)/8;l++) + statsdeltabits[l] = p->statsdeltabits[l] & ~d->statsdeltabits[l]; + for (k = 0, p2 = d->packetlog;k < ENTITYFRAME5_MAXPACKETLOGS;k++, p2++) + if (p2->packetnumber > framenum) + for (l = 0;l < (MAX_CL_STATS+7)/8;l++) + statsdeltabits[l] = p->statsdeltabits[l] & ~p2->statsdeltabits[l]; + for (l = 0;l < (MAX_CL_STATS+7)/8;l++) + d->statsdeltabits[l] |= statsdeltabits[l]; + } + // delete this packet log as it is now obsolete + p->packetnumber = 0; } - // delete this packet log as it is now obsolete - p->packetnumber = 0; } } +void EntityFrame5_AckFrame(entityframe5_database_t *d, int framenum) +{ + int i; + // scan for packets made obsolete by this ack and delete them + for (i = 0;i < ENTITYFRAME5_MAXPACKETLOGS;i++) + if (d->packetlog[i].packetnumber <= framenum) + d->packetlog[i].packetnumber = 0; +} + int entityframe5_prioritychaincounts[E5_PROTOCOL_PRIORITYLEVELS]; unsigned short entityframe5_prioritychains[E5_PROTOCOL_PRIORITYLEVELS][ENTITYFRAME5_MAXSTATES]; -void EntityFrame5_WriteFrame(sizebuf_t *msg, entityframe5_database_t *d, int numstates, const entity_state_t *states, int viewentnum) +void EntityFrame5_WriteFrame(sizebuf_t *msg, entityframe5_database_t *d, int numstates, const entity_state_t *states, int viewentnum, int *stats) { const entity_state_t *n; int i, num, l, framenum, packetlognumber, priority; @@ -1834,11 +1870,32 @@ void EntityFrame5_WriteFrame(sizebuf_t *msg, entityframe5_database_t *d, int num framenum = d->latestframenum + 1; + // if packet log is full, mark all frames as lost, this will cause + // it to send the lost data again + for (packetlognumber = 0;packetlognumber < ENTITYFRAME5_MAXPACKETLOGS;packetlognumber++) + if (d->packetlog[packetlognumber].packetnumber == 0) + break; + if (packetlognumber == ENTITYFRAME5_MAXPACKETLOGS) + { + EntityFrame5_LostFrame(d, framenum, viewentnum); + packetlognumber = 0; + } + // prepare the buffer memset(&buf, 0, sizeof(buf)); buf.data = data; buf.maxsize = sizeof(data); + // detect changes in stats + for (i = 0;i < MAX_CL_STATS;i++) + { + if (d->stats[i] != stats[i]) + { + d->statsdeltabits[i>>3] |= (1<<(i&7)); + d->stats[i] = stats[i]; + } + } + // detect changes in states num = 0; for (i = 0, n = states;i < numstates;i++, n++) @@ -1898,52 +1955,64 @@ void EntityFrame5_WriteFrame(sizebuf_t *msg, entityframe5_database_t *d, int num } } - // return early if there are no entities to send this time - if (l == 0) - return; - + // add packetlog entry + packetlog = d->packetlog + packetlognumber; + packetlog->packetnumber = framenum; + packetlog->numstates = 0; + // write stat updates + if (sv.protocol == PROTOCOL_DARKPLACES6) + { + for (i = 0;i < MAX_CL_STATS;i++) + { + if (d->statsdeltabits[i>>3] & (1<<(i&7))) + { + d->statsdeltabits[i>>3] &= ~(1<<(i&7)); + packetlog->statsdeltabits[i>>3] |= (1<<(i&7)); + if (d->stats[i] >= 0 && d->stats[i] < 256) + { + MSG_WriteByte(msg, svc_updatestatubyte); + MSG_WriteByte(msg, i); + MSG_WriteByte(msg, d->stats[i]); + } + else + { + MSG_WriteByte(msg, svc_updatestat); + MSG_WriteByte(msg, i); + MSG_WriteLong(msg, d->stats[i]); + } + } + } + } + // write state updates d->latestframenum = framenum; MSG_WriteByte(msg, svc_entities); MSG_WriteLong(msg, framenum); - - // if packet log is full, an empty update is still written - // (otherwise the client might have nothing to ack to remove packetlogs) - for (packetlognumber = 0, packetlog = d->packetlog;packetlognumber < ENTITYFRAME5_MAXPACKETLOGS;packetlognumber++, packetlog++) - if (packetlog->packetnumber == 0) - break; - if (packetlognumber < ENTITYFRAME5_MAXPACKETLOGS) + for (priority = E5_PROTOCOL_PRIORITYLEVELS - 1;priority >= 0 && packetlog->numstates < ENTITYFRAME5_MAXSTATES;priority--) { - // write to packet and log - packetlog->packetnumber = framenum; - packetlog->numstates = 0; - for (priority = E5_PROTOCOL_PRIORITYLEVELS - 1;priority >= 0 && packetlog->numstates < ENTITYFRAME5_MAXSTATES;priority--) + for (i = 0;i < entityframe5_prioritychaincounts[priority] && packetlog->numstates < ENTITYFRAME5_MAXSTATES;i++) { - for (i = 0;i < entityframe5_prioritychaincounts[priority] && packetlog->numstates < ENTITYFRAME5_MAXSTATES;i++) - { - num = entityframe5_prioritychains[priority][i]; - n = d->states + num; - if (d->deltabits[num] & E5_FULLUPDATE) - d->deltabits[num] = E5_FULLUPDATE | EntityState5_DeltaBits(&defaultstate, n); - buf.cursize = 0; - EntityState5_WriteUpdate(num, n, d->deltabits[num], &buf); - // if the entity won't fit, try the next one - if (msg->cursize + buf.cursize + 2 > msg->maxsize) - continue; - // write entity to the packet - SZ_Write(msg, buf.data, buf.cursize); - // mark age on entity for prioritization - d->updateframenum[num] = framenum; - // log entity so deltabits can be restored later if lost - packetlog->states[packetlog->numstates].number = num; - packetlog->states[packetlog->numstates].bits = d->deltabits[num]; - packetlog->numstates++; - // clear deltabits and priority so it won't be sent again - d->deltabits[num] = 0; - d->priorities[num] = 0; - } + num = entityframe5_prioritychains[priority][i]; + n = d->states + num; + if (d->deltabits[num] & E5_FULLUPDATE) + d->deltabits[num] = E5_FULLUPDATE | EntityState5_DeltaBits(&defaultstate, n); + buf.cursize = 0; + EntityState5_WriteUpdate(num, n, d->deltabits[num], &buf); + // if the entity won't fit, try the next one + if (msg->cursize + buf.cursize + 2 > msg->maxsize) + continue; + // write entity to the packet + SZ_Write(msg, buf.data, buf.cursize); + // mark age on entity for prioritization + d->updateframenum[num] = framenum; + // log entity so deltabits can be restored later if lost + packetlog->states[packetlog->numstates].number = num; + packetlog->states[packetlog->numstates].bits = d->deltabits[num]; + packetlog->numstates++; + // clear deltabits and priority so it won't be sent again + d->deltabits[num] = 0; + d->priorities[num] = 0; } } - MSG_WriteShort(msg, 0x8000); } diff --git a/protocol.h b/protocol.h index c0e96df3..398cf838 100644 --- a/protocol.h +++ b/protocol.h @@ -42,6 +42,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // entityframe5 protocol #define PROTOCOL_DARKPLACES5 3502 +#define PROTOCOL_DARKPLACES6 3503 // model effects #define EF_ROCKET 1 // leave a trail @@ -70,6 +71,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define EF_STARDUST 2048 // LordHavoc: showering sparks #define EF_NOSHADOW 4096 // LordHavoc: does not cast a shadow #define EF_NODEPTHTEST 8192 // LordHavoc: shows through walls +#define EF_SELECTABLE 16384 // LordHavoc: highlights when PRYDON_CLIENTCURSOR mouse is over it #define EF_STEP 0x80000000 // internal client use only - present on MOVETYPE_STEP entities, not QC accessible (too many bits) @@ -107,7 +109,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define U_EFFECTS2 (1<<19) // 1 byte, this is .effects & 0xFF00 (second byte) #define U_GLOWSIZE (1<<20) // 1 byte, encoding is float/4.0, unsigned, not sent if 0 #define U_GLOWCOLOR (1<<21) // 1 byte, palette index, default is 254 (white), this IS used for darklight (allowing colored darklight), however the particles from a darklight are always black, not sent if default value (even if glowsize or glowtrail is set) -// LordHavoc: colormod feature has been removed, because no one used it #define U_COLORMOD (1<<22) // 1 byte, 3 bit red, 3 bit green, 2 bit blue, this lets you tint an object artifically, so you could make a red rocket, or a blue fiend... #define U_EXTEND2 (1<<23) // another byte to follow // LordHavoc: second extend byte @@ -236,10 +237,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // LordHavoc: my svc_ range, 50-59 #define svc_cgame 50 // [short] length [bytes] data -#define svc_unusedlh1 51 +#define svc_updatestatubyte 51 // [byte] stat [byte] value #define svc_effect 52 // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate #define svc_effect2 53 // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate -#define svc_sound2 54 // short soundindex instead of byte +#define svc_sound2 54 // (obsolete in DP6 and later) short soundindex instead of byte +#define svc_precache 54 // [short] precacheindex [string] filename, precacheindex is + 0 for modelindex and +32768 for soundindex #define svc_spawnbaseline2 55 // short modelindex instead of byte #define svc_spawnstatic2 56 // short modelindex instead of byte #define svc_entities 57 // [int] deltaframe [int] thisframe [float vector] eye [variable length] entitydata @@ -256,7 +258,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define clc_stringcmd 4 // [string] message // LordHavoc: my clc_ range, 50-59 -#define clc_ackentities 50 // [int] framenumber +#define clc_ackframe 50 // [int] framenumber #define clc_unusedlh1 51 #define clc_unusedlh2 52 #define clc_unusedlh3 53 @@ -357,9 +359,9 @@ typedef struct unsigned char glowcolor; unsigned char flags; unsigned char tagindex; - unsigned char colormod; + unsigned char colormod[3]; // padding to a multiple of 8 bytes (to align the double time) - unsigned char unused[4]; + unsigned char unused[2]; } entity_state_t; @@ -669,8 +671,8 @@ void EntityFrame4_CL_ReadFrame(void); #define E5_EFFECTS32 (1<<20) // flag #define E5_FRAME16 (1<<21) -// unused -#define E5_UNUSED22 (1<<22) +// byte[3] = s->colormod[0], s->colormod[1], s->colormod[2] +#define E5_COLORMOD (1<<22) // bits >= (1<<24) #define E5_EXTEND3 (1<<23) @@ -706,6 +708,7 @@ typedef struct entityframe5_packetlog_s int packetnumber; int numstates; entityframe5_changestate_t states[ENTITYFRAME5_MAXSTATES]; + qbyte statsdeltabits[(MAX_CL_STATS+7)/8]; } entityframe5_packetlog_t; @@ -733,6 +736,10 @@ typedef struct entityframe5_database_s // (derived from states) qbyte visiblebits[(MAX_EDICTS+7)/8]; + // delta compression of stats + qbyte statsdeltabits[(MAX_CL_STATS+7)/8]; + int stats[MAX_CL_STATS]; + // old notes // this is used to decide which changestates to set each frame @@ -755,8 +762,9 @@ int EntityState5_Priority(entityframe5_database_t *d, entity_state_t *view, enti void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbits, sizebuf_t *msg); int EntityState5_DeltaBitsForState(entity_state_t *o, entity_state_t *n); void EntityFrame5_CL_ReadFrame(void); -void EntityFrame5_AckFrame(entityframe5_database_t *d, int framenum, int viewentnum); -void EntityFrame5_WriteFrame(sizebuf_t *msg, entityframe5_database_t *d, int numstates, const entity_state_t *states, int viewentnum); +void EntityFrame5_LostFrame(entityframe5_database_t *d, int framenum, int viewentnum); +void EntityFrame5_AckFrame(entityframe5_database_t *d, int framenum); +void EntityFrame5_WriteFrame(sizebuf_t *msg, entityframe5_database_t *d, int numstates, const entity_state_t *states, int viewentnum, int *stats); extern cvar_t developer_networkentities; diff --git a/quakedef.h b/quakedef.h index 2f8866df..fe85c4ea 100644 --- a/quakedef.h +++ b/quakedef.h @@ -67,7 +67,7 @@ extern char *buildstring; // // stats are integers communicated to the client by the server // -#define MAX_CL_STATS 32 +#define MAX_CL_STATS 256 #define STAT_HEALTH 0 #define STAT_FRAGS 1 #define STAT_WEAPON 2 @@ -83,6 +83,11 @@ extern char *buildstring; #define STAT_TOTALMONSTERS 12 #define STAT_SECRETS 13 // bumped on client side by svc_foundsecret #define STAT_MONSTERS 14 // bumped by svc_killedmonster +#define STAT_ITEMS 15 // FTE, DP +#define STAT_VIEWHEIGHT 16 // FTE, DP +//#define STAT_TIME 17 // FTE +//#define STAT_VIEW2 20 // FTE +#define STAT_VIEWZOOM 21 // DP // stock defines diff --git a/r_shadow.c b/r_shadow.c index 5a01184e..70e4aab7 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -1533,15 +1533,15 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0); GL_BlendFunc(GL_DST_ALPHA, GL_ONE); VectorScale(lightcolor, colorscale, color2); + GL_LockArrays(0, numverts); for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--) { GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1); - GL_LockArrays(0, numverts); R_Mesh_Draw(numverts, numtriangles, elements); - GL_LockArrays(0, 0); c_rt_lightmeshes++; c_rt_lighttris += numtriangles; } + GL_LockArrays(0, 0); } if (diffusescale) { @@ -1809,15 +1809,15 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0); GL_BlendFunc(GL_DST_ALPHA, GL_ONE); VectorScale(lightcolor, colorscale, color2); + GL_LockArrays(0, numverts); for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--) { GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1); - GL_LockArrays(0, numverts); R_Mesh_Draw(numverts, numtriangles, elements); - GL_LockArrays(0, 0); c_rt_lightmeshes++; c_rt_lighttris += numtriangles; } + GL_LockArrays(0, 0); } if (specularscale && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture))) { @@ -2034,20 +2034,20 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements #endif } } + R_Mesh_State(&m); + GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0); + GL_BlendFunc(GL_DST_ALPHA, GL_ONE); + VectorScale(lightcolor, colorscale, color2); + GL_LockArrays(0, numverts); + for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--) + { + GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1); + R_Mesh_Draw(numverts, numtriangles, elements); + c_rt_lightmeshes++; + c_rt_lighttris += numtriangles; + } + GL_LockArrays(0, 0); } - R_Mesh_State(&m); - GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0); - GL_BlendFunc(GL_DST_ALPHA, GL_ONE); - VectorScale(lightcolor, colorscale, color2); - GL_LockArrays(0, numverts); - for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--) - { - GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1); - R_Mesh_Draw(numverts, numtriangles, elements); - c_rt_lightmeshes++; - c_rt_lighttris += numtriangles; - } - GL_LockArrays(0, 0); } } else @@ -2084,6 +2084,10 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements #endif } } + if (r_textureunits.integer >= 3) + m.pointer_color = NULL; + else + m.pointer_color = varray_color4f; R_Mesh_State(&m); for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--) { @@ -2091,20 +2095,11 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements color[1] = bound(0, color2[1], 1); color[2] = bound(0, color2[2], 1); if (r_textureunits.integer >= 3) - { GL_Color(color[0], color[1], color[2], 1); - m.pointer_color = NULL; - } else if (r_textureunits.integer >= 2) - { R_Shadow_VertexNoShadingWithZAttenuation(numverts, vertex3f, color, matrix_modeltolight); - m.pointer_color = varray_color4f; - } else - { R_Shadow_VertexNoShadingWithXYZAttenuation(numverts, vertex3f, color, matrix_modeltolight); - m.pointer_color = varray_color4f; - } GL_LockArrays(0, numverts); R_Mesh_Draw(numverts, numtriangles, elements); GL_LockArrays(0, 0); @@ -2487,6 +2482,9 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes) ent = &cl_entities[0].render; if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT)) { + lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha; + lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha; + lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha; Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin); Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin); Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix); @@ -2496,10 +2494,10 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes) { R_Mesh_Matrix(&ent->matrix); for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next) - R_Shadow_RenderLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, mesh->map_normal, mesh->map_specular, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale); + R_Shadow_RenderLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, mesh->map_normal, mesh->map_specular, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale); } else - ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist); + ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist); } if (r_drawentities.integer) { @@ -2510,7 +2508,9 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes) // transparent meshes are deferred for later if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & (RENDER_LIGHT | RENDER_TRANSPARENT)) == RENDER_LIGHT) { - VectorScale(lightcolor, ent->alpha, lightcolor2); + lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha; + lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha; + lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha; Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin); Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin); Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix); diff --git a/r_sprites.c b/r_sprites.c index 9868ff48..cf6048d4 100644 --- a/r_sprites.c +++ b/r_sprites.c @@ -98,6 +98,9 @@ void R_DrawSpriteModelCallback(const void *calldata1, int calldata2) R_CompleteLightPoint(color, diffusecolor, diffusenormal, ent->origin, true, NULL); VectorMA(color, 0.5f, diffusecolor, color); } + color[0] *= ent->colormod[0]; + color[1] *= ent->colormod[1]; + color[2] *= ent->colormod[2]; if (fogenabled) { diff --git a/sbar.c b/sbar.c index 09c43cbe..02e3f6ca 100644 --- a/sbar.c +++ b/sbar.c @@ -549,7 +549,7 @@ void Sbar_DrawInventory (void) // weapons for (i=0 ; i<7 ; i++) { - if (cl.items & (IT_SHOTGUN<1)) @@ -651,7 +651,7 @@ void Sbar_DrawInventory (void) if (gamemode == GAME_HIPNOTIC) { for (i=0 ; i<2 ; i++) - if (cl.items & (1<<(24+i))) + if (cl.stats[STAT_ITEMS] & (1<<(24+i))) Sbar_DrawPic (288 + i*16, -16, hsb_items[i]); } @@ -659,14 +659,14 @@ void Sbar_DrawInventory (void) { // new rogue items for (i=0 ; i<2 ; i++) - if (cl.items & (1<<(29+i))) + if (cl.stats[STAT_ITEMS] & (1<<(29+i))) Sbar_DrawPic (288 + i*16, -16, rsb_items[i]); } else { // sigils for (i=0 ; i<4 ; i++) - if (cl.items & (1<<(28+i))) + if (cl.stats[STAT_ITEMS] & (1<<(28+i))) Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]); } } @@ -772,13 +772,13 @@ void Sbar_DrawFace (void) } // PGM 01/19/97 - team color drawing - if ( (cl.items & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) ) + if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) ) Sbar_DrawPic (112, 0, sb_face_invis_invuln); - else if (cl.items & IT_QUAD) + else if (cl.stats[STAT_ITEMS] & IT_QUAD) Sbar_DrawPic (112, 0, sb_face_quad ); - else if (cl.items & IT_INVISIBILITY) + else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY) Sbar_DrawPic (112, 0, sb_face_invis ); - else if (cl.items & IT_INVULNERABILITY) + else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY) Sbar_DrawPic (112, 0, sb_face_invuln); else { @@ -909,11 +909,11 @@ void Sbar_Draw (void) // armor if (cl.stats[STAT_ARMOR]) { - if (cl.items & IT_ARMOR3) + if (cl.stats[STAT_ITEMS] & IT_ARMOR3) Sbar_DrawPic(0, 0, somsb_armor[2]); - else if (cl.items & IT_ARMOR2) + else if (cl.stats[STAT_ITEMS] & IT_ARMOR2) Sbar_DrawPic(0, 0, somsb_armor[1]); - else if (cl.items & IT_ARMOR1) + else if (cl.stats[STAT_ITEMS] & IT_ARMOR1) Sbar_DrawPic(0, 0, somsb_armor[0]); Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25); } @@ -923,13 +923,13 @@ void Sbar_Draw (void) Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25); // ammo icon - if (cl.items & IT_SHELLS) + if (cl.stats[STAT_ITEMS] & IT_SHELLS) Sbar_DrawPic(0, 48, somsb_ammo[0]); - else if (cl.items & IT_NAILS) + else if (cl.stats[STAT_ITEMS] & IT_NAILS) Sbar_DrawPic(0, 48, somsb_ammo[1]); - else if (cl.items & IT_ROCKETS) + else if (cl.stats[STAT_ITEMS] & IT_ROCKETS) Sbar_DrawPic(0, 48, somsb_ammo[2]); - else if (cl.items & IT_CELLS) + else if (cl.stats[STAT_ITEMS] & IT_CELLS) Sbar_DrawPic(0, 48, somsb_ammo[3]); Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false); if (cl.stats[STAT_SHELLS]) @@ -959,12 +959,12 @@ void Sbar_Draw (void) fade *= fade; for (i = 0; i < 8;i++) { - if (!(cl.items & (1 << i))) + if (!(cl.stats[STAT_ITEMS] & (1 << i))) continue; Sbar_DrawWeapon(i + 1, fade, ((1<brush.entities, strlen(sv.worldmodel->brush.entities)); } + /* ============================================================================= @@ -215,15 +211,9 @@ void SV_StartSound (edict_t *entity, int channel, char *sample, int volume, floa return; // find precache number for sound - for (sound_num=1 ; sound_numedict = EDICT_NUM((client - svs.clients) + 1); @@ -287,8 +277,6 @@ void SV_SendServerinfo (client_t *client) // client info that normally requires networking if (!client->netconnection) { - int i; - // set up the edict ED_ClearEdict(client->edict); @@ -306,6 +294,7 @@ void SV_SendServerinfo (client_t *client) } // LordHavoc: clear entityframe tracking + client->latestframenum = 0; if (client->entitydatabase) EntityFrame_FreeDatabase(client->entitydatabase); @@ -318,7 +307,7 @@ void SV_SendServerinfo (client_t *client) client->entitydatabase = EntityFrame_AllocDatabase(sv_clients_mempool); if (sv.protocol == PROTOCOL_DARKPLACES4) client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_clients_mempool); - if (sv.protocol == PROTOCOL_DARKPLACES5) + if (sv.protocol == PROTOCOL_DARKPLACES5 || sv.protocol == PROTOCOL_DARKPLACES6) client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_clients_mempool); MSG_WriteByte (&client->message, svc_print); @@ -336,12 +325,12 @@ void SV_SendServerinfo (client_t *client) MSG_WriteString (&client->message,PR_GetString(sv.edicts->v->message)); - for (s = sv.model_precache+1 ; *s ; s++) - MSG_WriteString (&client->message, *s); + for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++) + MSG_WriteString (&client->message, sv.model_precache[i]); MSG_WriteByte (&client->message, 0); - for (s = sv.sound_precache+1 ; *s ; s++) - MSG_WriteString (&client->message, *s); + for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++) + MSG_WriteString (&client->message, sv.sound_precache[i]); MSG_WriteByte (&client->message, 0); // send music @@ -655,9 +644,12 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s) if (sententities[s->tagentity] != sententitiesmark) return; } + // skip invalid modelindexes to avoid crashes + else if (s->modelindex >= MAX_MODELS) + return; // always send world submodels, they don't generate much traffic // except in PROTOCOL_QUAKE where they hog bandwidth like crazy - else if ((!(isbmodel = (model = sv.models[s->modelindex]) != NULL && model->name[0] == '*') && !(s->effects & EF_NODEPTHTEST)) || sv.protocol == PROTOCOL_QUAKE) + else if (!(s->effects & EF_NODEPTHTEST) && (sv.protocol == PROTOCOL_QUAKE || !(isbmodel = (model = sv.models[s->modelindex]) != NULL && model->name[0] == '*'))) { Mod_CheckLoaded(model); // entity has survived every check so far, check if visible @@ -752,7 +744,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s) entity_state_t sendstates[MAX_EDICTS]; -void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg) +void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg, int *stats) { int i, numsendstates; entity_state_t *s; @@ -800,7 +792,7 @@ void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg) Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, sv_writeentitiestoclient_totalentities, sv_writeentitiestoclient_visibleentities, sv_writeentitiestoclient_culled_pvs + sv_writeentitiestoclient_culled_trace, sv_writeentitiestoclient_culled_pvs, sv_writeentitiestoclient_culled_trace); if (client->entitydatabase5) - EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1); + EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats); else if (client->entitydatabase4) EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates); else if (client->entitydatabase) @@ -831,7 +823,7 @@ SV_WriteClientdataToMessage ================== */ -void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg) +void SV_WriteClientdataToMessage (client_t *client, edict_t *ent, sizebuf_t *msg, int *stats) { int bits; int i; @@ -840,6 +832,7 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg) eval_t *val; vec3_t punchvector; qbyte viewzoom; + int weaponmodelindex; // // send a damage message @@ -871,78 +864,91 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg) 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 + // 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; - - // PROTOCOL_DARKPLACES VectorClear(punchvector); if ((val = GETEDICTFIELDVALUE(ent, eval_punchvector))) VectorCopy(val->vector, punchvector); - i = 255; - if ((val = GETEDICTFIELDVALUE(ent, eval_viewzoom))) + weaponmodelindex = SV_ModelIndex(PR_GetString(ent->v->weaponmodel), 1); + if (!weaponmodelindex) { - i = val->_float * 255.0f; - if (i == 0) - i = 255; - else - i = bound(0, i, 65535); + Con_DPrintf("weaponmodel \"%s\" not precached\n", PR_GetString(ent->v->weaponmodel)); + weaponmodelindex = 0; } - viewzoom = i; - // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom? - if (sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5) - if (viewzoom != 255) - bits |= SU_VIEWZOOM; + viewzoom = 255; + if ((val = GETEDICTFIELDVALUE(ent, eval_viewzoom))) + viewzoom = val->_float * 255.0f; + if (viewzoom == 0) + viewzoom = 255; + + bits = 0; + + if ((int)ent->v->flags & FL_ONGROUND) + bits |= SU_ONGROUND; + if (ent->v->waterlevel >= 2) + bits |= SU_INWATER; + if (ent->v->idealpitch) + bits |= SU_IDEALPITCH; 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; - - bits |= SU_WEAPON; + memset(stats, 0, sizeof(int[MAX_CL_STATS])); + stats[STAT_VIEWHEIGHT] = ent->v->view_ofs[2]; + stats[STAT_ITEMS] = items; + stats[STAT_WEAPONFRAME] = ent->v->weaponframe; + stats[STAT_ARMOR] = ent->v->armorvalue; + stats[STAT_WEAPON] = weaponmodelindex; + stats[STAT_HEALTH] = ent->v->health; + stats[STAT_AMMO] = ent->v->currentammo; + stats[STAT_SHELLS] = ent->v->ammo_shells; + stats[STAT_NAILS] = ent->v->ammo_nails; + stats[STAT_ROCKETS] = ent->v->ammo_rockets; + stats[STAT_CELLS] = ent->v->ammo_cells; + stats[STAT_ACTIVEWEAPON] = ent->v->weapon; + stats[STAT_VIEWZOOM] = viewzoom; + // the QC bumps these itself by sending svc_'s, so we have to keep them + // zero or they'll be corrected by the engine + //stats[STAT_TOTALSECRETS] = pr_global_struct->total_secrets; + //stats[STAT_TOTALMONSTERS] = pr_global_struct->total_monsters; + //stats[STAT_SECRETS] = pr_global_struct->found_secrets; + //stats[STAT_MONSTERS] = pr_global_struct->killed_monsters; + + if (sv.protocol != PROTOCOL_DARKPLACES6) + { + if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT; + bits |= SU_ITEMS; + if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME; + if (stats[STAT_ARMOR]) bits |= SU_ARMOR; + bits |= SU_WEAPON; + // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom? + if (sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5) + if (viewzoom != 255) + bits |= SU_VIEWZOOM; + } if (bits >= 65536) bits |= SU_EXTEND1; if (bits >= 16777216) bits |= SU_EXTEND2; -// send the data - + // send the data MSG_WriteByte (msg, svc_clientdata); MSG_WriteShort (msg, bits); if (bits & SU_EXTEND1) @@ -951,7 +957,7 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg) MSG_WriteByte(msg, bits >> 24); if (bits & SU_VIEWHEIGHT) - MSG_WriteChar (msg, ent->v->view_ofs[2]); + MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]); if (bits & SU_IDEALPITCH) MSG_WriteChar (msg, ent->v->idealpitch); @@ -962,16 +968,16 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg) { if (sv.protocol == PROTOCOL_QUAKE) MSG_WriteChar(msg, ent->v->punchangle[i]); - else if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5) + else if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5 || sv.protocol == PROTOCOL_DARKPLACES6) MSG_WriteAngle16i(msg, ent->v->punchangle[i]); } - if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5) + if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5 || sv.protocol == PROTOCOL_DARKPLACES6) { if (bits & (SU_PUNCHVEC1<v->velocity[i] * (1.0f / 16.0f)); - else if (sv.protocol == PROTOCOL_DARKPLACES5) + else if (sv.protocol == PROTOCOL_DARKPLACES5 || sv.protocol == PROTOCOL_DARKPLACES6) MSG_WriteCoord32f(msg, ent->v->velocity[i]); } } -// [always sent] if (bits & SU_ITEMS) - MSG_WriteLong (msg, items); + if (bits & SU_ITEMS) + MSG_WriteLong (msg, stats[STAT_ITEMS]); if (sv.protocol == PROTOCOL_DARKPLACES5) { if (bits & SU_WEAPONFRAME) - MSG_WriteShort (msg, ent->v->weaponframe); + MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]); if (bits & SU_ARMOR) - MSG_WriteShort (msg, ent->v->armorvalue); + MSG_WriteShort (msg, stats[STAT_ARMOR]); if (bits & SU_WEAPON) - { - i = SV_ModelIndex(PR_GetString(ent->v->weaponmodel)); - if (i < 0) - { - Con_DPrintf("weaponmodel \"%s\" not precached\n", PR_GetString(ent->v->weaponmodel)); - i = 0; - } - MSG_WriteShort (msg, i); - } - - MSG_WriteShort (msg, ent->v->health); - MSG_WriteShort (msg, ent->v->currentammo); - MSG_WriteShort (msg, ent->v->ammo_shells); - MSG_WriteShort (msg, ent->v->ammo_nails); - MSG_WriteShort (msg, ent->v->ammo_rockets); - MSG_WriteShort (msg, ent->v->ammo_cells); - - MSG_WriteShort (msg, ent->v->weapon); - + MSG_WriteShort (msg, stats[STAT_WEAPON]); + MSG_WriteShort (msg, stats[STAT_HEALTH]); + MSG_WriteShort (msg, stats[STAT_AMMO]); + MSG_WriteShort (msg, stats[STAT_SHELLS]); + MSG_WriteShort (msg, stats[STAT_NAILS]); + MSG_WriteShort (msg, stats[STAT_ROCKETS]); + MSG_WriteShort (msg, stats[STAT_CELLS]); + MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]); if (bits & SU_VIEWZOOM) - MSG_WriteShort (msg, viewzoom); + MSG_WriteShort (msg, min(stats[STAT_VIEWZOOM], 65535)); } - else + else if (sv.protocol != PROTOCOL_DARKPLACES6) { if (bits & SU_WEAPONFRAME) - MSG_WriteByte (msg, ent->v->weaponframe); + MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]); if (bits & SU_ARMOR) - MSG_WriteByte (msg, ent->v->armorvalue); + MSG_WriteByte (msg, stats[STAT_ARMOR]); if (bits & SU_WEAPON) - { - i = SV_ModelIndex(PR_GetString(ent->v->weaponmodel)); - if (i < 0) - { - Con_DPrintf("weaponmodel \"%s\" not precached\n", PR_GetString(ent->v->weaponmodel)); - i = 0; - } - MSG_WriteByte (msg, i); - } - - 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); - + MSG_WriteByte (msg, stats[STAT_WEAPON]); + MSG_WriteShort (msg, stats[STAT_HEALTH]); + MSG_WriteByte (msg, stats[STAT_AMMO]); + MSG_WriteByte (msg, stats[STAT_SHELLS]); + MSG_WriteByte (msg, stats[STAT_NAILS]); + MSG_WriteByte (msg, stats[STAT_ROCKETS]); + MSG_WriteByte (msg, stats[STAT_CELLS]); if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ) { - for(i=0;i<32;i++) - { - if ( ((int)ent->v->weapon) & (1<v->weapon); - } - + MSG_WriteByte (msg, stats[STAT_WEAPON]); if (bits & SU_VIEWZOOM) { if (sv.protocol == PROTOCOL_DARKPLACES4) - { - viewzoom = min(viewzoom, 255); - MSG_WriteByte (msg, viewzoom); - } - else if (sv.protocol == PROTOCOL_DARKPLACES5) - MSG_WriteShort (msg, viewzoom); + MSG_WriteByte (msg, min(stats[STAT_VIEWZOOM], 255)); + else if (sv.protocol == PROTOCOL_DARKPLACES5 || sv.protocol == PROTOCOL_DARKPLACES6) + MSG_WriteShort (msg, min(stats[STAT_VIEWZOOM], 65535)); } } } @@ -1079,6 +1054,7 @@ qboolean SV_SendClientDatagram (client_t *client) { int rate, maxrate, maxsize, maxsize2; sizebuf_t msg; + int stats[MAX_CL_STATS]; if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer) { @@ -1086,7 +1062,7 @@ qboolean SV_SendClientDatagram (client_t *client) maxsize = sizeof(sv_sendclientdatagram_buf); maxsize2 = sizeof(sv_sendclientdatagram_buf); } - else if (sv.protocol == PROTOCOL_DARKPLACES5) + else if (sv.protocol == PROTOCOL_DARKPLACES5 || sv.protocol == PROTOCOL_DARKPLACES6) { // PROTOCOL_DARKPLACES5 supports packet size limiting of updates maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE); @@ -1115,9 +1091,8 @@ qboolean SV_SendClientDatagram (client_t *client) MSG_WriteFloat (&msg, sv.time); // add the client specific data to the datagram - SV_WriteClientdataToMessage (client->edict, &msg); - - SV_WriteEntitiesToClient (client, client->edict, &msg); + SV_WriteClientdataToMessage (client, client->edict, &msg, stats); + SV_WriteEntitiesToClient (client, client->edict, &msg, stats); // expand packet size to allow effects to go over the rate limit // (dropping them is FAR too ugly) @@ -1323,22 +1298,111 @@ SV_ModelIndex ================ */ -int SV_ModelIndex (const char *name) +int SV_ModelIndex(char *s, int precachemode) { - int i; - - if (!name || !name[0]) + int i, limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_MODELS); + char filename[MAX_QPATH]; + if (!s || !*s) return 0; - - for (i=0 ; i 0 && entnum <= svs.maxclients) { svent->e->baseline.colormap = entnum; - i = SV_ModelIndex("progs/player.mdl"); - if (i < 0) - i = 0; - svent->e->baseline.modelindex = i; + svent->e->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1); } else { @@ -1576,47 +1637,30 @@ void SV_SpawnServer (const char *server) strlcpy (sv.name, server, sizeof (sv.name)); - // FIXME: cvar + sv.netquakecompatible = false; if (!strcasecmp(sv_protocolname.string, "QUAKE")) { sv.protocol = PROTOCOL_QUAKE; sv.netquakecompatible = true; } else if (!strcasecmp(sv_protocolname.string, "QUAKEDP")) - { sv.protocol = PROTOCOL_QUAKE; - sv.netquakecompatible = false; - } else if (!strcasecmp(sv_protocolname.string, "DARKPLACES1")) - { sv.protocol = PROTOCOL_DARKPLACES1; - sv.netquakecompatible = false; - } else if (!strcasecmp(sv_protocolname.string, "DARKPLACES2")) - { sv.protocol = PROTOCOL_DARKPLACES2; - sv.netquakecompatible = false; - } else if (!strcasecmp(sv_protocolname.string, "DARKPLACES3")) - { sv.protocol = PROTOCOL_DARKPLACES3; - sv.netquakecompatible = false; - } else if (!strcasecmp(sv_protocolname.string, "DARKPLACES4")) - { sv.protocol = PROTOCOL_DARKPLACES4; - sv.netquakecompatible = false; - } else if (!strcasecmp(sv_protocolname.string, "DARKPLACES5")) - { sv.protocol = PROTOCOL_DARKPLACES5; - sv.netquakecompatible = false; - } + else if (!strcasecmp(sv_protocolname.string, "DARKPLACES6")) + sv.protocol = PROTOCOL_DARKPLACES6; else { - sv.protocol = PROTOCOL_DARKPLACES5; - sv.netquakecompatible = false; - Con_Printf("Unknown sv_protocolname \"%s\", valid values are QUAKE, QUAKEDP, DARKPLACES1, DARKPLACES2, DARKPLACES3, DARKPLACES4, DARKPLACES5, falling back to DARKPLACES5 protocol\n", sv_protocolname.string); + sv.protocol = PROTOCOL_DARKPLACES6; + Con_Printf("Unknown sv_protocolname \"%s\", valid values are QUAKE, QUAKEDP, DARKPLACES1, DARKPLACES2, DARKPLACES3, DARKPLACES4, DARKPLACES5, DARKPLACES6, falling back to DARKPLACES6 protocol\n", sv_protocolname.string); } // load progs to get entity field count @@ -1681,14 +1725,14 @@ void SV_SpawnServer (const char *server) // SV_ClearWorld (); - sv.sound_precache[0] = ""; + strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0])); - sv.model_precache[0] = ""; - sv.model_precache[1] = sv.modelname; + strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0])); + strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1])); for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++) { - sv.model_precache[i+1] = localmodels[i]; - sv.models[i+1] = Mod_ForName (localmodels[i], false, false, false); + snprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i); + sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false); } // diff --git a/sv_user.c b/sv_user.c index a2057f07..77102a69 100644 --- a/sv_user.c +++ b/sv_user.c @@ -630,7 +630,7 @@ void SV_ReadClientMove (usercmd_t *move) angle[i] = MSG_ReadAngle8i(); else if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3) angle[i] = MSG_ReadAngle32f(); - else if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5) + else if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5 || sv.protocol == PROTOCOL_DARKPLACES6) angle[i] = MSG_ReadAngle16i(); if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); } @@ -653,7 +653,10 @@ void SV_ReadClientMove (usercmd_t *move) } // read buttons - bits = MSG_ReadByte (); + if (sv.protocol == PROTOCOL_DARKPLACES6) + bits = MSG_ReadLong (); + else + bits = MSG_ReadByte (); if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); host_client->edict->v->button0 = bits & 1; host_client->edict->v->button2 = (bits & 2)>>1; @@ -664,11 +667,50 @@ void SV_ReadClientMove (usercmd_t *move) if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_button6))) val->_float = ((bits >> 5) & 1); if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_button7))) val->_float = ((bits >> 6) & 1); if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_button8))) val->_float = ((bits >> 7) & 1); + if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_buttonuse))) val->_float = ((bits >> 8) & 1); + if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_buttonchat))) val->_float = ((bits >> 9) & 1); + if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_cursor_active))) val->_float = ((bits >> 10) & 1); i = MSG_ReadByte (); if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); if (i) host_client->edict->v->impulse = i; + + // PRYDON_CLIENTCURSOR + if (sv.protocol == PROTOCOL_DARKPLACES6) + { + // 30 bytes + move->cursor_screen[0] = MSG_ReadShort() * (1.0f / 32767.0f); + move->cursor_screen[1] = MSG_ReadShort() * (1.0f / 32767.0f); + move->cursor_start[0] = MSG_ReadFloat(); + move->cursor_start[1] = MSG_ReadFloat(); + move->cursor_start[2] = MSG_ReadFloat(); + move->cursor_impact[0] = MSG_ReadFloat(); + move->cursor_impact[1] = MSG_ReadFloat(); + move->cursor_impact[2] = MSG_ReadFloat(); + move->cursor_entitynumber = MSG_ReadShort(); + if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); + } + if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_cursor_screen))) VectorCopy(move->cursor_screen, val->vector); + if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_cursor_trace_start))) VectorCopy(move->cursor_start, val->vector); + if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_cursor_trace_endpos))) VectorCopy(move->cursor_impact, val->vector); + if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_cursor_trace_ent))) val->edict = EDICT_TO_PROG(EDICT_NUM(move->cursor_entitynumber)); +} + +void SV_FrameLost(int framenum) +{ + if (host_client->entitydatabase5) + EntityFrame5_LostFrame(host_client->entitydatabase5, framenum, host_client - svs.clients + 1); +} + +void SV_FrameAck(int framenum) +{ + if (host_client->entitydatabase) + EntityFrame_AckFrame(host_client->entitydatabase, framenum); + else if (host_client->entitydatabase4) + EntityFrame4_AckFrame(host_client->entitydatabase4, framenum, true); + else if (host_client->entitydatabase5) + EntityFrame5_AckFrame(host_client->entitydatabase5, framenum); } /* @@ -757,18 +799,20 @@ void SV_ReadClientMessage(void) SV_ReadClientMove (&host_client->cmd); break; - case clc_ackentities: + case clc_ackframe: if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); num = MSG_ReadLong(); if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); if (developer_networkentities.integer >= 1) - Con_Printf("recv clc_ackentities %i\n", num); - if (host_client->entitydatabase) - EntityFrame_AckFrame(host_client->entitydatabase, num); - else if (host_client->entitydatabase4) - EntityFrame4_AckFrame(host_client->entitydatabase4, num, true); - else if (host_client->entitydatabase5) - EntityFrame5_AckFrame(host_client->entitydatabase5, num, host_client - svs.clients + 1); + Con_Printf("recv clc_ackframe %i\n", num); + if (host_client->latestframenum < num) + { + int i; + for (i = host_client->latestframenum + 1;i < num;i++) + SV_FrameLost(i); + SV_FrameAck(num); + host_client->latestframenum = num; + } break; } } diff --git a/vid_glx.c b/vid_glx.c index a96e3f9f..46ccdb26 100644 --- a/vid_glx.c +++ b/vid_glx.c @@ -889,10 +889,10 @@ void IN_Commands (void) { } -void IN_Move (usercmd_t *cmd) +void IN_Move (void) { if (mouse_avail) - IN_Mouse(cmd, mouse_x, mouse_y); + IN_Mouse(mouse_x, mouse_y); mouse_x = 0; mouse_y = 0; } diff --git a/vid_null.c b/vid_null.c index 32003e07..7daea1e5 100644 --- a/vid_null.c +++ b/vid_null.c @@ -102,6 +102,6 @@ void IN_Commands(void) { } -void IN_Move(usercmd_t *cmd) +void IN_Move(void) { } diff --git a/vid_sdl.c b/vid_sdl.c index 3acdc478..4dc4d13b 100644 --- a/vid_sdl.c +++ b/vid_sdl.c @@ -218,22 +218,22 @@ void IN_Commands (void) { } -static void IN_MouseMove (usercmd_t *cmd) +static void IN_MouseMove (void) { int x, y; if( !vid_usingmouse ) { - IN_Mouse( cmd, 0, 0 ); + IN_Mouse( 0, 0 ); return; } SDL_GetRelativeMouseState( &x, &y ); - IN_Mouse( cmd, x, y ); + IN_Mouse( x, y ); } -void IN_Move( usercmd_t *cmd ) +void IN_Move( void ) { - IN_MouseMove( cmd ); + IN_MouseMove(); } static void IN_Init( void ) diff --git a/vid_shared.c b/vid_shared.c index aecaaa8a..76cc73d9 100644 --- a/vid_shared.c +++ b/vid_shared.c @@ -732,23 +732,23 @@ void IN_PostMove(void) IN_DoMove =========== */ -void IN_ProcessMove(usercmd_t *cmd) +void IN_ProcessMove(void) { // get basic movement from keyboard - CL_BaseMove(cmd); + CL_BaseMove(); // OS independent code IN_PreMove(); // allow mice or other external controllers to add to the move - IN_Move(cmd); + IN_Move(); // OS independent code IN_PostMove(); } -void IN_Mouse(usercmd_t *cmd, float mx, float my) +void IN_Mouse(float mx, float my) { int mouselook = (in_mlook.state & 1) || freelook.integer; float mouse_x, mouse_y; @@ -776,13 +776,21 @@ void IN_Mouse(usercmd_t *cmd, float mx, float my) if(!in_client_mouse) return; + if (cl_prydoncursor.integer) + { + cl.cmd.cursor_screen[0] += mouse_x / vid.realwidth; + cl.cmd.cursor_screen[1] += mouse_y / vid.realheight; + V_StopPitchDrift(); + return; + } + // LordHavoc: viewzoom affects mouse sensitivity for sniping mouse_x *= sensitivity.value * cl.viewzoom; mouse_y *= sensitivity.value * cl.viewzoom; // Add mouse X/Y movement to cmd if ((in_strafe.state & 1) || (lookstrafe.integer && mouselook)) - cmd->sidemove += m_side.value * mouse_x; + cl.cmd.sidemove += m_side.value * mouse_x; else cl.viewangles[YAW] -= m_yaw.value * mouse_x; @@ -794,9 +802,9 @@ void IN_Mouse(usercmd_t *cmd, float mx, float my) else { if ((in_strafe.state & 1) && noclip_anglehack) - cmd->upmove -= m_forward.value * mouse_y; + cl.cmd.upmove -= m_forward.value * mouse_y; else - cmd->forwardmove -= m_forward.value * mouse_y; + cl.cmd.forwardmove -= m_forward.value * mouse_y; } } diff --git a/vid_wgl.c b/vid_wgl.c index 4649e672..c6e0ff74 100644 --- a/vid_wgl.c +++ b/vid_wgl.c @@ -259,7 +259,7 @@ static DIDATAFORMAT df = { // forward-referenced functions void IN_StartupJoystick (void); void Joy_AdvancedUpdate_f (void); -void IN_JoyMove (usercmd_t *cmd); +void IN_JoyMove (void); void IN_StartupMouse (void); /* @@ -1344,7 +1344,7 @@ void IN_MouseEvent (int mstate) IN_MouseMove =========== */ -void IN_MouseMove (usercmd_t *cmd) +void IN_MouseMove (void) { int i, mx, my; DIDEVICEOBJECTDATA od; @@ -1355,7 +1355,7 @@ void IN_MouseMove (usercmd_t *cmd) { GetCursorPos (¤t_pos); //ui_mouseupdate(current_pos.x - window_x, current_pos.y - window_y); - IN_Mouse( cmd, 0, 0 ); + IN_Mouse( 0, 0 ); return; } @@ -1442,7 +1442,7 @@ void IN_MouseMove (usercmd_t *cmd) my = current_pos.y - window_center_y; } - IN_Mouse(cmd, mx, my); + IN_Mouse(mx, my); // if the mouse has moved, force it to the center, so there's room to move if (!dinput && (mx || my)) @@ -1455,12 +1455,12 @@ void IN_MouseMove (usercmd_t *cmd) IN_Move =========== */ -void IN_Move (usercmd_t *cmd) +void IN_Move (void) { if (vid_activewindow && !vid_hidden) { - IN_MouseMove (cmd); - IN_JoyMove (cmd); + IN_MouseMove (); + IN_JoyMove (); } } @@ -1753,7 +1753,7 @@ qboolean IN_ReadJoystick (void) IN_JoyMove =========== */ -void IN_JoyMove (usercmd_t *cmd) +void IN_JoyMove (void) { float speed, aspeed; float fAxisValue, fTemp; @@ -1848,7 +1848,7 @@ void IN_JoyMove (usercmd_t *cmd) // user wants forward control to be forward control if (fabs(fAxisValue) > joy_forwardthreshold.value) { - cmd->forwardmove += (fAxisValue * joy_forwardsensitivity.value) * speed * cl_forwardspeed.value; + cl.cmd.forwardmove += (fAxisValue * joy_forwardsensitivity.value) * speed * cl_forwardspeed.value; } } break; @@ -1856,7 +1856,7 @@ void IN_JoyMove (usercmd_t *cmd) case AxisSide: if (fabs(fAxisValue) > joy_sidethreshold.value) { - cmd->sidemove += (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value; + cl.cmd.sidemove += (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value; } break; @@ -1866,7 +1866,7 @@ void IN_JoyMove (usercmd_t *cmd) // user wants turn control to become side control if (fabs(fAxisValue) > joy_sidethreshold.value) { - cmd->sidemove -= (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value; + cl.cmd.sidemove -= (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value; } } else diff --git a/view.c b/view.c index 060464ac..de0bf4d5 100644 --- a/view.c +++ b/view.c @@ -397,7 +397,7 @@ void V_CalcRefdef (void) } // origin VectorAdd(vieworg, cl.punchvector, vieworg); - vieworg[2] += cl.viewheight; + vieworg[2] += cl.stats[STAT_VIEWHEIGHT]; if (cl.stats[STAT_HEALTH] > 0 && cl_bob.value && cl_bobcycle.value) { double bob, cycle; @@ -482,28 +482,28 @@ void V_CalcViewBlend(void) if (gamemode != GAME_TRANSFUSION) { - if (cl.items & IT_QUAD) + if (cl.stats[STAT_ITEMS] & IT_QUAD) { cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0; cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 0; cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255; cl.cshifts[CSHIFT_POWERUP].percent = 30; } - else if (cl.items & IT_SUIT) + else if (cl.stats[STAT_ITEMS] & IT_SUIT) { cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0; cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255; cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0; cl.cshifts[CSHIFT_POWERUP].percent = 20; } - else if (cl.items & IT_INVISIBILITY) + else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY) { cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 100; cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 100; cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 100; cl.cshifts[CSHIFT_POWERUP].percent = 100; } - else if (cl.items & IT_INVULNERABILITY) + else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY) { cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 255; cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255; -- 2.39.2