+ int num;
+ entity_t *ent;
+ entity_state_t s;
+
+ entityframequake_mtime = cl.mtime[0];
+
+ if (bits & U_MOREBITS)
+ bits |= (MSG_ReadByte()<<8);
+ if ((bits & U_EXTEND1) && cl.protocol != PROTOCOL_NEHAHRAMOVIE)
+ {
+ bits |= MSG_ReadByte() << 16;
+ if (bits & U_EXTEND2)
+ bits |= MSG_ReadByte() << 24;
+ }
+
+ if (bits & U_LONGENTITY)
+ num = (unsigned short) MSG_ReadShort ();
+ else
+ num = MSG_ReadByte ();
+
+ if (num >= MAX_EDICTS)
+ Host_Error("EntityFrameQuake_ReadEntity: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS);
+ if (num < 1)
+ Host_Error("EntityFrameQuake_ReadEntity: invalid entity number (%i)\n", num);
+
+ ent = cl_entities + num;
+
+ // note: this inherits the 'active' state of the baseline chosen
+ // (state_baseline is always active, state_current may not be active if
+ // the entity was missing in the last frame)
+ if (bits & U_DELTA)
+ s = ent->state_current;
+ else
+ {
+ s = ent->state_baseline;
+ s.active = true;
+ }
+
+ s.number = num;
+ s.time = cl.mtime[0];
+ s.flags = 0;
+ if (bits & U_MODEL) s.modelindex = (s.modelindex & 0xFF00) | MSG_ReadByte();
+ if (bits & U_FRAME) s.frame = (s.frame & 0xFF00) | MSG_ReadByte();
+ if (bits & U_COLORMAP) s.colormap = MSG_ReadByte();
+ if (bits & U_SKIN) s.skin = MSG_ReadByte();
+ if (bits & U_EFFECTS) s.effects = (s.effects & 0xFF00) | MSG_ReadByte();
+ if (bits & U_ORIGIN1) s.origin[0] = MSG_ReadCoord13i();
+ if (bits & U_ANGLE1) s.angles[0] = MSG_ReadAngle8i();
+ if (bits & U_ORIGIN2) s.origin[1] = MSG_ReadCoord13i();
+ if (bits & U_ANGLE2) s.angles[1] = MSG_ReadAngle8i();
+ if (bits & U_ORIGIN3) s.origin[2] = MSG_ReadCoord13i();
+ if (bits & U_ANGLE3) s.angles[2] = MSG_ReadAngle8i();
+ if (bits & U_STEP) s.flags |= RENDER_STEP;
+ if (bits & U_ALPHA) s.alpha = MSG_ReadByte();
+ if (bits & U_SCALE) s.scale = MSG_ReadByte();
+ 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_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);
+ if (bits & U_VIEWMODEL) s.flags |= RENDER_VIEWMODEL;
+ if (bits & U_EXTERIORMODEL) s.flags |= RENDER_EXTERIORMODEL;
+
+ // LordHavoc: to allow playback of the Nehahra movie
+ if (cl.protocol == PROTOCOL_NEHAHRAMOVIE && (bits & U_EXTEND1))
+ {
+ // LordHavoc: evil format
+ int i = MSG_ReadFloat();
+ int j = MSG_ReadFloat() * 255.0f;
+ if (i == 2)
+ {
+ i = MSG_ReadFloat();
+ if (i)
+ s.effects |= EF_FULLBRIGHT;
+ }
+ if (j < 0)
+ s.alpha = 0;
+ else if (j == 0 || j >= 255)
+ s.alpha = 255;
+ else
+ s.alpha = j;
+ }
+
+ ent->state_previous = ent->state_current;
+ ent->state_current = s;
+ if (ent->state_current.active)
+ {
+ CL_MoveLerpEntityStates(ent);
+ cl_entities_active[ent->state_current.number] = true;
+ }
+
+ if (msg_badread)
+ Host_Error("EntityFrameQuake_ReadEntity: read error\n");
+}
+
+void EntityFrameQuake_ISeeDeadEntities(void)
+{
+ int i;
+ for (i = 0;i < cl_max_entities;i++)
+ {
+ if (cl_entities_active[i] && cl_entities[i].state_current.time != cl.mtime[0])
+ {
+ cl_entities_active[i] = false;
+ cl_entities[i].state_current = defaultstate;
+ cl_entities[i].state_current.number = i;
+ }
+ }
+}
+
+void EntityFrameQuake_WriteFrame(sizebuf_t *msg, int numstates, const entity_state_t *states)
+{
+ const entity_state_t *s;
+ entity_state_t baseline;
+ int i, bits;
+ sizebuf_t buf;
+ qbyte data[128];
+
+ // prepare the buffer
+ memset(&buf, 0, sizeof(buf));
+ buf.data = data;
+ buf.maxsize = sizeof(data);
+
+ for (i = 0, s = states;i < numstates;i++, s++)
+ {
+ // prepare the buffer
+ SZ_Clear(&buf);
+
+// send an update
+ bits = 0;
+ if (s->number >= 256)
+ bits |= U_LONGENTITY;
+ if (s->flags & RENDER_STEP)
+ bits |= U_STEP;
+ if (s->flags & RENDER_VIEWMODEL)
+ bits |= U_VIEWMODEL;
+ if (s->flags & RENDER_GLOWTRAIL)
+ bits |= U_GLOWTRAIL;
+ if (s->flags & RENDER_EXTERIORMODEL)
+ bits |= U_EXTERIORMODEL;
+
+ // LordHavoc: old stuff, but rewritten to have more exact tolerances
+ baseline = sv.edicts[s->number].e->baseline;
+ if (baseline.origin[0] != s->origin[0])
+ bits |= U_ORIGIN1;
+ if (baseline.origin[1] != s->origin[1])
+ bits |= U_ORIGIN2;
+ if (baseline.origin[2] != s->origin[2])
+ bits |= U_ORIGIN3;
+ if (baseline.angles[0] != s->angles[0])
+ bits |= U_ANGLE1;
+ if (baseline.angles[1] != s->angles[1])
+ bits |= U_ANGLE2;
+ if (baseline.angles[2] != s->angles[2])
+ bits |= U_ANGLE3;
+ if (baseline.colormap != s->colormap)
+ bits |= U_COLORMAP;
+ if (baseline.skin != s->skin)
+ bits |= U_SKIN;
+ if (baseline.frame != s->frame)
+ {
+ bits |= U_FRAME;
+ if (s->frame & 0xFF00)
+ bits |= U_FRAME2;
+ }
+ if (baseline.effects != s->effects)
+ {
+ bits |= U_EFFECTS;
+ if (s->effects & 0xFF00)
+ bits |= U_EFFECTS2;
+ }
+ if (baseline.modelindex != s->modelindex)
+ {
+ bits |= U_MODEL;
+ if (s->modelindex & 0xFF00)
+ bits |= U_MODEL2;
+ }
+ if (baseline.alpha != s->alpha)
+ bits |= U_ALPHA;
+ if (baseline.scale != s->scale)
+ bits |= U_SCALE;
+ if (baseline.glowsize != s->glowsize)
+ bits |= U_GLOWSIZE;
+ if (baseline.glowcolor != s->glowcolor)
+ bits |= U_GLOWCOLOR;
+
+ // if extensions are disabled, clear the relevant update flags
+ if (sv.netquakecompatible)
+ bits &= 0x7FFF;
+
+ // write the message
+ if (bits >= 16777216)
+ bits |= U_EXTEND2;
+ if (bits >= 65536)
+ bits |= U_EXTEND1;
+ if (bits >= 256)
+ bits |= U_MOREBITS;
+ bits |= U_SIGNAL;
+
+ MSG_WriteByte (&buf, bits);
+ if (bits & U_MOREBITS) MSG_WriteByte(&buf, bits>>8);
+ if (bits & U_EXTEND1) MSG_WriteByte(&buf, bits>>16);
+ if (bits & U_EXTEND2) MSG_WriteByte(&buf, bits>>24);
+ if (bits & U_LONGENTITY) MSG_WriteShort(&buf, s->number);
+ else MSG_WriteByte(&buf, s->number);
+
+ if (bits & U_MODEL) MSG_WriteByte(&buf, s->modelindex);
+ if (bits & U_FRAME) MSG_WriteByte(&buf, s->frame);
+ if (bits & U_COLORMAP) MSG_WriteByte(&buf, s->colormap);
+ if (bits & U_SKIN) MSG_WriteByte(&buf, s->skin);
+ if (bits & U_EFFECTS) MSG_WriteByte(&buf, s->effects);
+ if (bits & U_ORIGIN1) MSG_WriteCoord13i(&buf, s->origin[0]);
+ if (bits & U_ANGLE1) MSG_WriteAngle8i(&buf, s->angles[0]);
+ if (bits & U_ORIGIN2) MSG_WriteCoord13i(&buf, s->origin[1]);
+ if (bits & U_ANGLE2) MSG_WriteAngle8i(&buf, s->angles[1]);
+ if (bits & U_ORIGIN3) MSG_WriteCoord13i(&buf, s->origin[2]);
+ if (bits & U_ANGLE3) MSG_WriteAngle8i(&buf, s->angles[2]);
+ if (bits & U_ALPHA) MSG_WriteByte(&buf, s->alpha);
+ if (bits & U_SCALE) MSG_WriteByte(&buf, s->scale);
+ 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_FRAME2) MSG_WriteByte(&buf, s->frame >> 8);
+ if (bits & U_MODEL2) MSG_WriteByte(&buf, s->modelindex >> 8);
+
+ // if the commit is full, we're done this frame
+ if (msg->cursize + buf.cursize > msg->maxsize)
+ {
+ // next frame we will continue where we left off
+ break;
+ }
+ // write the message to the packet
+ SZ_Write(msg, buf.data, buf.cursize);
+ }