#include "dzip.h" char te_size[] = {8, 8, 8, 8, 8, 16, 16, 8, 8, 16, 8, 8, 10, 16, 8, 8, 14}; int dem_decode_type; void dem_copy_ue() { char mask = inptr[0] & 0x7f; char topmask; int len = 1; topmask = (mask & 0x01)? inptr[len++] : 0x00; if (topmask & 0x40) len += 2; else len++; if (topmask & 0x04) len++; if (mask & 0x40) len++; if (topmask & 0x08) len++; if (topmask & 0x10) len++; if (topmask & 0x20) len++; if (mask & 0x02) len += 2; if (topmask & 0x01) len++; if (mask & 0x04) len += 2; if (mask & 0x10) len++; if (mask & 0x08) len += 2; if (topmask & 0x02) len++; if (topmask & 0x80) Sys_Error("dem_copy_ue(): topmask & 0x80"); copy_msg(len); } void demx_bad() { Sys_Error("bad message %d encountered", *inptr); } void demx_nop() { copy_msg(1); } void demx_disconnect() { copy_msg(1); } void demx_updatestat() { copy_msg(6); } void demx_version() { copy_msg(5); } void demx_setview() { copy_msg(3); } void demx_sound() { int len = 11 - (*inptr > DEM_sound); int entity, c; char mask = inptr[1]; char channel; if (len == 10) mask = *inptr & 3; if (mask & 0x01) len++; if (mask & 0x02) len++; if (dem_decode_type == TYPE_DEMV1) { copy_msg(len); return; } *inptr = DEM_sound; insert_msg(inptr,1); *inptr = mask; channel = inptr[len-9] & 7; inptr[len-9] = (inptr[len-9] & 0xf8) + ((2 - channel) & 7); entity = getshort(inptr+len-9) >> 3; c = getshort(inptr+len-6); c += newent[entity].org0; c = cnvlong(c); memcpy(inptr+len-6,&c,2); c = getshort(inptr+len-4); c += newent[entity].org1; c = cnvlong(c); memcpy(inptr+len-4,&c,2); c = getshort(inptr+len-2); c += newent[entity].org2; c = cnvlong(c); memcpy(inptr+len-2,&c,2); copy_msg(len); } void demx_longtime() { long tmp = getlong(inptr+1); dem_gametime += tmp; tmp = cnvlong(dem_gametime); *inptr = DEM_time; memcpy(inptr+1,&tmp,4); copy_msg(5); } void demx_time() { static char buf[5]; long tmp = getshort(inptr+1) & 0xffff; if (dem_decode_type == TYPE_DEMV1) { demx_longtime(); return; } dem_gametime += tmp; tmp = cnvlong(dem_gametime); buf[0] = DEM_time; memcpy(buf+1,&tmp,4); insert_msg(buf,5); discard_msg(3); } /* used by lots of msgs */ void demx_string() { char *ptr = inptr + 1; while (*ptr++); copy_msg(ptr-inptr); } void demx_setangle() { copy_msg(4); } void demx_serverinfo() { char *ptr = inptr + 7; char *start_ptr; while (*ptr++); do { start_ptr = ptr; while (*ptr++); } while (ptr - start_ptr > 1); do { start_ptr = ptr; while (*ptr++); } while (ptr - start_ptr > 1); copy_msg(ptr-inptr); sble = 0; } void demx_lightstyle() { char *ptr = inptr + 2; while (*ptr++); copy_msg(ptr-inptr); } void demx_updatename() { char *ptr = inptr + 2; while (*ptr++); copy_msg(ptr-inptr); } void demx_updatefrags() { copy_msg(4); } int bplus(int x, int y) { if (x >= 128) x -= 256; return y + x; } void create_clientdata_msg() { static char buf[32]; char *ptr = buf+3; int mask = newcd.invbit? 0 : 0x0200; long tmp; buf[0] = DEM_clientdata; #define CMADD(x,def,bit,bit2) if (newcd.x != def || newcd.force & bit2)\ { mask |= bit; *ptr++ = newcd.x; } CMADD(voz,22,0x0001,0x0800); CMADD(pax,0,0x0002,0x1000); CMADD(ang0,0,0x0004,0x0100); CMADD(vel0,0,0x0020,0x0001); CMADD(ang1,0,0x0008,0x0200); CMADD(vel1,0,0x0040,0x0002); CMADD(ang2,0,0x0010,0x0400); CMADD(vel2,0,0x0080,0x0004); tmp = cnvlong(newcd.items); memcpy(ptr,&tmp,4); ptr += 4; if (newcd.uk10) mask |= 0x0400; if (newcd.uk11) mask |= 0x0800; CMADD(wpf,0,0x1000,0x2000); CMADD(av,0,0x2000,0x4000); CMADD(wpm,0,0x4000,0x8000); tmp = cnvlong(newcd.health); memcpy(ptr,&tmp,2); ptr += 2; *ptr++ = newcd.am; *ptr++ = newcd.sh; *ptr++ = newcd.nl; *ptr++ = newcd.rk; *ptr++ = newcd.ce; *ptr++ = newcd.wp; mask = cnvlong(mask); memcpy(buf+1,&mask,2); insert_msg(buf,ptr-buf); oldcd = newcd; } #define CPLUS(x,bit) if (mask & bit) { newcd.x = bplus(*ptr++,oldcd.x); } void demx_clientdata() { char *ptr = inptr; int mask = *ptr++; newcd = oldcd; if (mask & 0x08) mask += *ptr++ << 8; if (mask & 0x8000) mask += *ptr++ << 16; if (mask & 0x800000) mask += *ptr++ << 24; CPLUS(vel2,0x00000001); CPLUS(vel0,0x00000002); CPLUS(vel1,0x00000004); CPLUS(wpf,0x00000100); if (mask & 0x00000200) newcd.uk10 = !oldcd.uk10; CPLUS(ang0,0x00000400); CPLUS(am,0x00000800); if (mask & 0x00001000) { newcd.health += getshort(ptr); ptr += 2; } if (mask & 0x00002000) { newcd.items ^= getlong(ptr); ptr += 4; } CPLUS(av,0x00004000); CPLUS(pax,0x00010000); CPLUS(sh,0x00020000); CPLUS(nl,0x00040000); CPLUS(rk,0x00080000); CPLUS(wpm,0x00100000); CPLUS(wp,0x00200000); if (mask & 0x00400000) newcd.uk11 = !oldcd.uk11; CPLUS(voz,0x01000000); CPLUS(ce,0x02000000); CPLUS(ang1,0x04000000); CPLUS(ang2,0x08000000); if (mask & 0x10000000) newcd.invbit = !oldcd.invbit; discard_msg(ptr-inptr); if ((*ptr & 0xf0) == 0x50) { mask = *ptr++; if (mask & 0x08) mask |= *ptr++ << 8; newcd.force ^= mask & 0xff07; discard_msg(ptr-inptr); } create_clientdata_msg(); } void demx_stopsound() { copy_msg(3); } void demx_updatecolors() { copy_msg(3); } void demx_particle() { copy_msg(12); } void demx_damage() { copy_msg(9); } void demx_spawnstatic() { copy_msg(14); } void demx_spawnbinary() { copy_msg(1); } void demx_spawnbaseline() { char buf[16], *ptr = inptr+3; ent_t ent; int mask = getshort(inptr+1); sble += (mask & 0x03ff); memset(&ent,0,sizeof(ent_t)); ent.modelindex = *ptr++; if (mask & 0x0400) ent.frame = *ptr++; if (mask & 0x0800) ent.colormap = *ptr++; if (mask & 0x1000) ent.skin = *ptr++; if (mask & 0x2000) { ent.org0 = getshort(ptr); ptr += 2; ent.org1 = getshort(ptr); ptr += 2; ent.org2 = getshort(ptr); ptr += 2; } if (mask & 0x4000) ent.ang1 = *ptr++; if (mask & 0x8000) { ent.ang0 = *ptr++; ent.ang2 = *ptr++; } discard_msg(ptr-inptr); buf[0] = DEM_spawnbaseline; mask = cnvlong(sble); memcpy(buf+1,&mask,2); buf[3] = ent.modelindex; buf[4] = ent.frame; buf[5] = ent.colormap; buf[6] = ent.skin; mask = cnvlong(ent.org0); memcpy(buf+7,&mask,2); buf[9] = ent.ang0; mask = cnvlong(ent.org1); memcpy(buf+10,&mask,2); buf[12] = ent.ang1; mask = cnvlong(ent.org2); memcpy(buf+13,&mask,2); buf[15] = ent.ang2; insert_msg(buf,16); base[sble] = ent; copybaseline = 1; } extern char te_size[]; void demx_temp_entity() { if (inptr[1] == 17) copy_msg(strlen(inptr + 2) + 17); else copy_msg(te_size[inptr[1]]); } void demx_setpause() { copy_msg(2); } void demx_signonnum() { copy_msg(2); } void demx_killedmonster() { copy_msg(1); } void demx_foundsecret() { copy_msg(1); } void demx_spawnstaticsound() { copy_msg(10); } void demx_intermission() { copy_msg(1); } void demx_cdtrack() { copy_msg(3); } void demx_sellscreen() { copy_msg(1); } /* nehahra */ void demx_showlmp(void) { char *ptr = inptr + 1; while (*ptr++); while (*ptr++); ptr += 2; *inptr = DEM_showlmp; copy_msg(ptr-inptr); } void demx_updateentity() { char buf[32], *ptr; int mask, i, entity; int baseval = 0, prev; ent_t n, o; long tmp; lastent = 0; for (ptr = inptr+1; *ptr; ptr++) { if (*ptr == 0xff) { baseval += 0xfe; continue; } entity = baseval + *ptr; newent[entity].active = 1; while (entlink[lastent] <= entity) lastent = entlink[lastent]; if (lastent < entity) { entlink[entity] = entlink[lastent]; entlink[lastent] = entity; } } for (prev = 0, i = entlink[0], ptr++; i < MAX_ENT; i = entlink[i]) { newent[i].org0 += newent[i].od0; newent[i].org1 += newent[i].od1; newent[i].org2 += newent[i].od2; if (!newent[i].active) { prev = i; continue; } mask = *ptr++; if (mask == 0x80) { oldent[i] = newent[i] = base[i]; entlink[prev] = entlink[i]; continue; } prev = i; if (mask == 0x00) { newent[i].active = 0; continue; } if (mask & 0x80) mask += (*ptr++) << 8; if (mask & 0x8000) mask += (*ptr++) << 16; n = newent[i]; o = oldent[i]; if (mask & 0x000001) { n.od2 = bplus(*ptr++,o.od2); n.org2 = o.org2 + n.od2; } if (mask & 0x000800) { n.org2 = getshort(ptr); ptr += 2; n.od2 = n.org2 - o.org2; } if (mask & 0x000002) { n.od1 = bplus(*ptr++,o.od1); n.org1 = o.org1 + n.od1; } if (mask & 0x000400) { n.org1 = getshort(ptr); ptr += 2; n.od1 = n.org1 - o.org1; } if (mask & 0x000004) { n.od0 = bplus(*ptr++,o.od0); n.org0 = o.org0 + n.od0; } if (mask & 0x000200) { n.org0 = getshort(ptr); ptr += 2; n.od0 = n.org0 - o.org0; } if (mask & 0x000008) n.ang0 = bplus(*ptr++,o.ang0); if (mask & 0x000010) n.ang1 = bplus(*ptr++,o.ang1); if (mask & 0x000020) n.ang2 = bplus(*ptr++,o.ang2); if (mask & 0x000040) n.frame = o.frame+1; if (mask & 0x000100) n.frame = bplus(*ptr++,o.frame); if (mask & 0x001000) n.effects = *ptr++; if (mask & 0x002000) n.modelindex = *ptr++; if (mask & 0x004000) n.new = !o.new; if (mask & 0x010000) n.colormap = *ptr++; if (mask & 0x020000) n.skin = *ptr++; // nehahra if (mask & 0x040000) { n.alpha = getfloat(ptr); ptr+= 4; } else n.alpha = o.alpha; if (mask & 0x080000) n.fullbright = *ptr++; else n.fullbright = o.fullbright; newent[i] = n; } if (*ptr == 0x31) { ptr++; while ((mask = getshort(ptr))) { ptr += 2; mask &= 0xffff; if (mask & 0x8000) mask |= *ptr++ << 16; entity = mask & 0x3ff; newent[entity].force ^= mask & 0xfffc00; } ptr += 2; } discard_msg(ptr-inptr); for (i = entlink[0]; i < MAX_ENT; i = entlink[i]) { ent_t n = newent[i], b = base[i]; ptr = buf+2; mask = 0x80; if (i > 0xff || (n.force & 0x400000)) { tmp = cnvlong(i); memcpy(ptr,&tmp,2); ptr += 2; mask |= 0x4000; } else *ptr++ = i; #define BDIFF(x,bit,bit2) \ if (n.x != b.x || n.force & bit2) \ { *ptr++ = n.x; mask |= bit; } BDIFF(modelindex,0x0400,0x040000); BDIFF(frame,0x0040,0x4000); BDIFF(colormap,0x0800,0x080000); BDIFF(skin,0x1000,0x100000); BDIFF(effects,0x2000,0x200000); if (n.org0 != b.org0 || n.force & 0x010000) { mask |= 0x0002; tmp = cnvlong(n.org0); memcpy(ptr,&tmp,2); ptr += 2; } BDIFF(ang0,0x0100,0x0800); if (n.org1 != b.org1 || n.force & 0x0400) { mask |= 0x0004; tmp = cnvlong(n.org1); memcpy(ptr,&tmp,2); ptr += 2; } BDIFF(ang1,0x0010,0x1000); if (n.org2 != b.org2 || n.force & 0x020000) { mask |= 0x0008; tmp = cnvlong(n.org2); memcpy(ptr,&tmp,2); ptr += 2; } BDIFF(ang2,0x0200,0x2000); // nehahra if (n.force & 0x800000) { float f = 1; if (n.fullbright) f = 2; tmp = cnvlong(*(int *)&f); memcpy(ptr, &tmp, 4); tmp = cnvlong(*(int *)&n.alpha); memcpy(ptr + 4, &tmp, 4); ptr += 8; if (f == 2) { f = (char)(n.fullbright - 1); tmp = cnvlong(*(int *)&f); memcpy(ptr, &tmp, 4); ptr += 4; } mask |= 0x8000; } if (n.new) mask |= 0x20; if (mask & 0xff00) mask |= 0x01; buf[0] = mask & 0xff; buf[1] = (mask & 0xff00) >> 8; if (!(mask & 0x01)) { memcpy(buf+1,buf+2,ptr-buf-2); ptr--; } insert_msg(buf,ptr-buf); oldent[i] = newent[i]; } } void (*demx_message[])() = { demx_bad, demx_nop, demx_disconnect, demx_updatestat, demx_version, demx_setview, demx_sound, demx_time, demx_string, demx_string, demx_setangle, demx_serverinfo, demx_lightstyle, demx_updatename, demx_updatefrags, demx_clientdata, demx_stopsound, demx_updatecolors, demx_particle, demx_damage, demx_spawnstatic, demx_spawnbinary, demx_spawnbaseline, demx_temp_entity, demx_setpause, demx_signonnum, demx_string, demx_killedmonster, demx_foundsecret, demx_spawnstaticsound, demx_intermission, demx_string, demx_cdtrack, demx_sellscreen, demx_string, demx_longtime, demx_string, demx_string, demx_showlmp /* nehahra */ }; long cam0, cam1, cam2; char cdstring_char; void dem_uncompress_init (int type) { cdstring_char = 0; dem_decode_type = type; memset(&base,0,sizeof(ent_t)*MAX_ENT); memset(&oldent,0,sizeof(ent_t)*MAX_ENT); memset(&oldcd,0,sizeof(cdata_t)); oldcd.voz = 22; oldcd.items = 0x4001; entlink[0] = MAX_ENT; cam0 = cam1 = cam2 = 0; copybaseline = 0; dem_gametime = 0; maxent = 0; sble = 0; } int dem_uncompress () { long a1; char cfields; int uemask = (dem_decode_type == TYPE_DEMV1)? 0x80 : 0x30; int cdmask = (dem_decode_type == TYPE_DEMV1)? 0xf0 : 0x40; inptr = inblk; if (!cdstring_char) while (cdstring_char != '\n') { cdstring_char = *inptr++; write_output(&cdstring_char,1); } cfields = *inptr++; if (cfields == 0xff) { long len = getlong(inblk+1); write_output(inblk+5,len); return len+5; } if (cfields & 1) { cam0 += getlong(inptr); inptr += 4; } if (cfields & 2) { cam1 += getlong(inptr); inptr += 4; } if (cfields & 4) { cam2 += getlong(inptr); inptr += 4; } outlen = 0; insert_msg(&a1,4); a1 = cnvlong(cam0); insert_msg(&a1,4); a1 = cnvlong(cam1); insert_msg(&a1,4); a1 = cnvlong(cam2); insert_msg(&a1,4); dem_updateframe = 0; while (*inptr) { if ((*inptr & 0xf8) == uemask) demx_updateentity(); else { if (dem_updateframe) { demv1_dxentities(); dem_updateframe = 0; } if (*inptr <= DZ_showlmp) demx_message[(int)(*inptr)](); else if ((*inptr & 0xf0) == cdmask) demx_clientdata(); else if ((*inptr & 0xf8) == 0x38) demx_sound(); else if (*inptr >= 0x80) dem_copy_ue(); else demx_message[DEM_bad](); } } if (dem_updateframe) demv1_dxentities(); outlen -= 16; outlen = cnvlong(outlen); memcpy(outblk,&outlen,4); write_output(outblk,cnvlong(outlen)+16); if (copybaseline) { copybaseline = 0; memcpy(oldent,base,sizeof(ent_t)*MAX_ENT); memcpy(newent,base,sizeof(ent_t)*MAX_ENT); } return inptr-inblk+1; } void demv1_dxentities() { char buf[32]; char *ptr; long tmp; int i, mask; for (i = 1; i <= maxent; i++) { ent_t n = newent[i], b = base[i]; if (!n.present) continue; ptr = buf+2; mask = 0x80; if (i > 0xff || (n.force & 0x400000)) { tmp = cnvlong(i); memcpy(ptr,&tmp,2); ptr += 2; mask |= 0x4000; } else *ptr++ = i; #define BDIFF(x,bit,bit2) \ if (n.x != b.x || n.force & bit2) \ { *ptr++ = n.x; mask |= bit; } BDIFF(modelindex,0x0400,0x040000); BDIFF(frame,0x0040,0x4000); BDIFF(colormap,0x0800,0x080000); BDIFF(skin,0x1000,0x100000); BDIFF(effects,0x2000,0x200000); if (n.org0 != b.org0 || n.force & 0x010000) { mask |= 0x0002; tmp = cnvlong(n.org0); memcpy(ptr,&tmp,2); ptr += 2; } BDIFF(ang0,0x0100,0x0800); if (n.org1 != b.org1 || n.force & 0x0400) { mask |= 0x0004; tmp = cnvlong(n.org1); memcpy(ptr,&tmp,2); ptr += 2; } BDIFF(ang1,0x0010,0x1000); if (n.org2 != b.org2 || n.force & 0x020000) { mask |= 0x0008; tmp = cnvlong(n.org2); memcpy(ptr,&tmp,2); ptr += 2; } BDIFF(ang2,0x0200,0x2000); if (n.new) mask |= 0x20; if (mask & 0xff00) mask |= 0x01; buf[0] = mask & 0xff; buf[1] = (mask & 0xff00) >> 8; if (!(mask & 0x01)) { memcpy(buf+1,buf+2,ptr-buf-2); ptr--; } insert_msg(buf,ptr-buf); memcpy(oldent+i,newent+i,sizeof(ent_t)); } }