diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 9d9445dbe..7fde8f883 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -1769,6 +1769,11 @@ void CL_SendCmd (double frametime, qboolean mainloop) if (fullsend) { + if (!cls.state) + { + msecs -= (double)msecstouse; + return; + } switch (cls.protocol) { #ifdef NQPROT diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index ecde001c1..b9ff48bef 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -142,6 +142,7 @@ cvar_t cl_gunanglex = CVAR("cl_gunanglex", "0"); cvar_t cl_gunangley = CVAR("cl_gunangley", "0"); cvar_t cl_gunanglez = CVAR("cl_gunanglez", "0"); +cvar_t cl_sendguid = CVARD("cl_sendguid", "0", "Send a randomly generated 'globally unique' id to servers, which can be used by servers for score rankings and stuff. Different servers will see different guids. Delete the 'qkey' file in order to appear as a different user."); cvar_t cl_download_csprogs = CVARFD("cl_download_csprogs", "1", CVAR_NOTFROMSERVER, "Download updated client gamecode if available. Warning: If you clear this to avoid downloading vm code, you should also clear cl_download_packages."); cvar_t cl_download_redirection = CVARFD("cl_download_redirection", "2", CVAR_NOTFROMSERVER, "Follow download redirection to download packages instead of individual files. 2 allows redirection only to named packages files. Also allows the server to send nearly arbitary download commands."); cvar_t cl_download_mapsrc = CVARD("cl_download_mapsrc", "", "Specifies an http location prefix for map downloads. EG: \"http://bigfoot.morphos-team.net/misc/quakemaps/\""); @@ -225,7 +226,7 @@ static struct qboolean istransfer; //ignore the user's desired server (don't change connect.adr). netadr_t adr; //address that we're trying to transfer to. int mtu; - qboolean compress; + unsigned int compresscrc; int protocol; //tracked as part of guesswork based upon what replies we get. int challenge; //tracked as part of guesswork based upon what replies we get. double time; //for connection retransmits @@ -395,6 +396,9 @@ char *CL_GUIDString(netadr_t *adr) void *blocks[2]; int lens[2]; + if (!cl_sendguid.ival) + return NULL; + if (*connectinfo.guid && connectinfo.istransfer) return connectinfo.guid; @@ -606,11 +610,11 @@ void CL_SendConnectPacket (netadr_t *to, int mtu, if (compressioncrc && net_compress.ival && Huff_CompressionCRC(compressioncrc)) { Q_strncatz(data, va("0x%x 0x%x\n", PROTOCOL_VERSION_HUFFMAN, LittleLong(compressioncrc)), sizeof(data)); - connectinfo.compress = true; + connectinfo.compresscrc = compressioncrc; } else #endif - connectinfo.compress = false; + connectinfo.compresscrc = 0; info = CL_GUIDString(to); if (info) @@ -790,7 +794,12 @@ void CL_CheckForResend (void) connectinfo.trying = false; } else + { + if (!connectinfo.challenge) + connectinfo.challenge = rand(); + cls.challenge = connectinfo.challenge; CL_SendConnectPacket (NULL, 8192-16, pext1, pext2, false); + } return; } #endif @@ -1339,6 +1348,7 @@ void CL_ClearState (void) cl.oldgametime = 0; cl.gametime = 0; cl.gametimemark = 0; + cl.splitclients = 1; } /* @@ -1490,6 +1500,8 @@ void CL_Disconnect_f (void) #endif CL_Disconnect (); + + connectinfo.trying = false; } /* @@ -2735,7 +2747,11 @@ client_connect: //fixme: make function cls.challenge = connectinfo.challenge; Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, cls.qport); cls.netchan.fragmentsize = connectinfo.mtu; - cls.netchan.compress = connectinfo.compress; +#ifdef HUFFNETWORK + cls.netchan.compresstable = Huff_CompressionCRC(connectinfo.compresscrc); +#else + cls.netchan.compresstable = NULL; +#endif CL_ParseEstablished(); #ifdef Q3CLIENT if (cls.protocol != CP_QUAKE3) @@ -2885,7 +2901,7 @@ void CLNQ_ConnectionlessPacket(void) Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, cls.qport); CL_ParseEstablished(); cls.netchan.isnqprotocol = true; - cls.netchan.compress = 0; + cls.netchan.compresstable = NULL; cls.protocol = CP_NETQUAKE; cls.state = ca_connected; Con_TPrintf ("Connected.\n"); @@ -3422,6 +3438,7 @@ void CL_Init (void) Cvar_Register (&cfg_save_name, cl_controlgroup); + Cvar_Register (&cl_sendguid, cl_controlgroup); Cvar_Register (&cl_defaultport, cl_controlgroup); Cvar_Register (&cl_servername, cl_controlgroup); Cvar_Register (&cl_serveraddress, cl_controlgroup); @@ -3696,6 +3713,7 @@ void VARGS Host_EndGame (char *message, ...) CL_Disconnect (); SV_UnspawnServer(); + connectinfo.trying = false; Cvar_Set(&cl_shownet, "0"); @@ -4422,7 +4440,8 @@ double Host_Frame (double time) // resend a connection request if necessary if (cls.state == ca_disconnected) { - IN_Move(NULL, 0, time); + CL_SendCmd (host_frametime, true); +// IN_Move(NULL, 0, time); CL_CheckForResend (); #ifdef VOICECHAT diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index b9cac3558..0544c9819 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -4540,41 +4540,41 @@ void CLQ2_ParseMuzzleFlash (void) switch (weapon) { case Q2MZ_BLASTER: - dl->color[0] = 0.2;dl->color[1] = 0.2;dl->color[2] = 0; + dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0; Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0); break; case Q2MZ_BLUEHYPERBLASTER: - dl->color[0] = 0;dl->color[1] = 0;dl->color[2] = 0.2; + dl->color[0] = 0;dl->color[1] = 0;dl->color[2] = 1; Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0); break; case Q2MZ_HYPERBLASTER: - dl->color[0] = 0.2;dl->color[1] = 0.2;dl->color[2] = 0; + dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0; Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0); break; case Q2MZ_MACHINEGUN: - dl->color[0] = 0.2;dl->color[1] = 0.2;dl->color[2] = 0; + dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0; Q_snprintfz(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1); Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound(soundname), volume, ATTN_NORM, 0); break; case Q2MZ_SHOTGUN: - dl->color[0] = 0.2;dl->color[1] = 0.2;dl->color[2] = 0; + dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0; Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/shotgf1b.wav"), volume, ATTN_NORM, 0); Q2S_StartSound (NULL, i, CHAN_AUTO, S_PrecacheSound("weapons/shotgr1b.wav"), volume, ATTN_NORM, 0.1); break; case Q2MZ_SSHOTGUN: - dl->color[0] = 0.2;dl->color[1] = 0.2;dl->color[2] = 0; + dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0; Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/sshotf1b.wav"), volume, ATTN_NORM, 0); break; case Q2MZ_CHAINGUN1: dl->radius = 200 + (rand()&31); - dl->color[0] = 0.2;dl->color[1] = 0.05;dl->color[2] = 0; + dl->color[0] = 1;dl->color[1] = 0.25;dl->color[2] = 0; Q_snprintfz(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1); Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound(soundname), volume, ATTN_NORM, 0); break; case Q2MZ_CHAINGUN2: dl->radius = 225 + (rand()&31); - dl->color[0] = 0.2;dl->color[1] = 0.1;dl->color[2] = 0; + dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0; dl->die = cl.time + 0.1; // long delay Q_snprintfz(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1); Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound(soundname), volume, ATTN_NORM, 0); @@ -4583,7 +4583,7 @@ void CLQ2_ParseMuzzleFlash (void) break; case Q2MZ_CHAINGUN3: dl->radius = 250 + (rand()&31); - dl->color[0] = 0.2;dl->color[1] = 0.2;dl->color[2] = 0; + dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0; dl->die = cl.time + 0.1; // long delay Q_snprintfz(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1); Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound(soundname), volume, ATTN_NORM, 0); @@ -4594,92 +4594,92 @@ void CLQ2_ParseMuzzleFlash (void) break; case Q2MZ_RAILGUN: - dl->color[0] = 0.1;dl->color[1] = 0.1;dl->color[2] = 0.2; + dl->color[0] = 0.5;dl->color[1] = 0.5;dl->color[2] = 1; Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/railgf1a.wav"), volume, ATTN_NORM, 0); break; case Q2MZ_ROCKET: - dl->color[0] = 0.2;dl->color[1] = 0.1;dl->color[2] = 0.04; + dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2; Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/rocklf1a.wav"), volume, ATTN_NORM, 0); Q2S_StartSound (NULL, i, CHAN_AUTO, S_PrecacheSound("weapons/rocklr1b.wav"), volume, ATTN_NORM, 0.1); break; case Q2MZ_GRENADE: - dl->color[0] = 0.2;dl->color[1] = 0.1;dl->color[2] = 0; + dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0; Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/grenlf1a.wav"), volume, ATTN_NORM, 0); Q2S_StartSound (NULL, i, CHAN_AUTO, S_PrecacheSound("weapons/grenlr1b.wav"), volume, ATTN_NORM, 0.1); break; case Q2MZ_BFG: - dl->color[0] = 0;dl->color[1] = 0.2;dl->color[2] = 0; + dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0; Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/bfg__f1y.wav"), volume, ATTN_NORM, 0); break; case Q2MZ_LOGIN: - dl->color[0] = 0;dl->color[1] = 0.2; dl->color[2] = 0; + dl->color[0] = 0;dl->color[1] = 1; dl->color[2] = 0; dl->die = cl.time + 1.0; Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0); // CL_LogoutEffect (pl->current.origin, weapon); break; case Q2MZ_LOGOUT: - dl->color[0] = 0.2;dl->color[1] = 0; dl->color[2] = 0; + dl->color[0] = 1;dl->color[1] = 0; dl->color[2] = 0; dl->die = cl.time + 1.0; Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0); // CL_LogoutEffect (pl->current.origin, weapon); break; case Q2MZ_RESPAWN: - dl->color[0] = 0.2;dl->color[1] = 0.2; dl->color[2] = 0; + dl->color[0] = 1;dl->color[1] = 1; dl->color[2] = 0; dl->die = cl.time + 1.0; Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0); // CL_LogoutEffect (pl->current.origin, weapon); break; // RAFAEL case Q2MZ_PHALANX: - dl->color[0] = 0.2;dl->color[1] = 0.1; dl->color[2] = 0.1; + dl->color[0] = 1;dl->color[1] = 0.5; dl->color[2] = 0.5; Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/plasshot.wav"), volume, ATTN_NORM, 0); break; // RAFAEL case Q2MZ_IONRIPPER: - dl->color[0] = 0.2;dl->color[1] = 0.1; dl->color[2] = 0.1; + dl->color[0] = 1;dl->color[1] = 0.5; dl->color[2] = 0.5; Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/rippfire.wav"), volume, ATTN_NORM, 0); break; // ====================== // PGM case Q2MZ_ETF_RIFLE: - dl->color[0] = 0.18;dl->color[1] = 0.14;dl->color[2] = 0; + dl->color[0] = 0.9;dl->color[1] = 0.7;dl->color[2] = 0; Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/nail1.wav"), volume, ATTN_NORM, 0); break; case Q2MZ_SHOTGUN2: - dl->color[0] = 0.2;dl->color[1] = 0.2;dl->color[2] = 0; + dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0; Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/shotg2.wav"), volume, ATTN_NORM, 0); break; case Q2MZ_HEATBEAM: - dl->color[0] = 0.2;dl->color[1] = 0.2;dl->color[2] = 0; + dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0; dl->die = cl.time + 100; // Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/bfg__l1a.wav"), volume, ATTN_NORM, 0); break; case Q2MZ_BLASTER2: - dl->color[0] = 0;dl->color[1] = 0.2;dl->color[2] = 0; + dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0; // FIXME - different sound for blaster2 ?? Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0); break; case Q2MZ_TRACKER: // negative flashes handled the same in gl/soft until CL_AddDLights - dl->color[0] = -0.2;dl->color[1] = -0.2;dl->color[2] = -0.2; + dl->color[0] = -1;dl->color[1] = -1;dl->color[2] = -1; Q2S_StartSound (NULL, i, CHAN_WEAPON, S_PrecacheSound("weapons/disint2.wav"), volume, ATTN_NORM, 0); break; case Q2MZ_NUKE1: - dl->color[0] = 0.2;dl->color[1] = 0;dl->color[2] = 0; + dl->color[0] = 1;dl->color[1] = 0;dl->color[2] = 0; dl->die = cl.time + 100; break; case Q2MZ_NUKE2: - dl->color[0] = 0.2;dl->color[1] = 0.2;dl->color[2] = 0; + dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0; dl->die = cl.time + 100; break; case Q2MZ_NUKE4: - dl->color[0] = 0;dl->color[1] = 0;dl->color[2] = 0.2; + dl->color[0] = 0;dl->color[1] = 0;dl->color[2] = 1; dl->die = cl.time + 100; break; case Q2MZ_NUKE8: - dl->color[0] = 0;dl->color[1] = 0.2;dl->color[2] = 0.2; + dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 1; dl->die = cl.time + 100; break; // PGM diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index f3c842ead..b6f561b3c 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -170,7 +170,7 @@ q2trace_t VARGS CLQ2_PMTrace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end trace_t t; // check against world - t = CM_BoxTrace (cl.worldmodel, start, end, mins, maxs, MASK_PLAYERSOLID); + cl.worldmodel->funcs.NativeTrace(cl.worldmodel, 0, 0, NULL, start, end, mins, maxs, MASK_PLAYERSOLID, &t); if (t.fraction < 1.0) t.ent = (struct edict_s *)1; @@ -535,7 +535,9 @@ short LerpAngles16(short to, short from, float frac) void CL_CalcClientTime(void) { extern float demtime; - if (cls.protocol != CP_QUAKE3) + if (!cls.state) + cl.servertime += host_frametime; + else if (cls.protocol != CP_QUAKE3) { float oldst = realtime; diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index af0cc21a5..462700704 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -1719,12 +1719,13 @@ void SCR_SetUpToDrawConsole (void) //go fullscreen if we're not doing anything #ifdef VM_UI if (UI_MenuState() || UI_OpenMenu()) - ; + scr_con_current = scr_conlines = 0; else #endif if (cls.state < ca_demostart) Key_Dest_Add(kdm_console); - scr_con_current = scr_conlines = vid.height * fullscreenpercent; + if (Key_Dest_Has(kdm_console)) + scr_con_current = scr_conlines = vid.height * fullscreenpercent; } else if (Key_Dest_Has(kdm_console) || scr_chatmode) { diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index dd6da0ae9..0da79954a 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -461,14 +461,28 @@ void CL_RegisterParticles(void) ptqw_blood = P_FindParticleType("TE_BLOOD"); ptqw_lightningblood = P_FindParticleType("TE_LIGHTNINGBLOOD"); - ptq2_blood = P_FindParticleType("TE_BLOOD"); - rtq2_railtrail = P_FindParticleType("TR_RAILTRAIL"); - rtq2_blastertrail = P_FindParticleType("TR_BLASTERTRAIL"); - ptq2_blasterparticles = P_FindParticleType("TE_BLASTERPARTICLES"); - rtq2_bubbletrail = P_FindParticleType("TE_BUBBLETRAIL"); - rtq2_gib = P_FindParticleType("TR_GIB"); - rtq2_rocket = P_FindParticleType("TR_ROCKET"); - rtq2_grenade = P_FindParticleType("TR_GRENADE"); + if (cls.protocol == CP_QUAKE2) + { + ptq2_blood = P_FindParticleType("q2part.TEQ2_BLOOD"); + rtq2_railtrail = P_FindParticleType("q2part.TR_RAILTRAIL"); + rtq2_blastertrail = P_FindParticleType("q2part.TR_BLASTERTRAIL"); + ptq2_blasterparticles = P_FindParticleType("TE_BLASTERPARTICLES"); + rtq2_bubbletrail = P_FindParticleType("TE_BUBBLETRAIL"); + rtq2_gib = P_FindParticleType("TR_GIB"); + rtq2_rocket = P_FindParticleType("TR_ROCKET"); + rtq2_grenade = P_FindParticleType("TR_GRENADE"); + } + else + { + ptq2_blood = P_INVALID; + rtq2_railtrail = P_INVALID; + rtq2_blastertrail = P_INVALID; + ptq2_blasterparticles = P_INVALID; + rtq2_bubbletrail = P_INVALID; + rtq2_gib = P_INVALID; + rtq2_rocket = P_INVALID; + rtq2_grenade = P_INVALID; + } rtqw_railtrail = P_FindParticleType("TE_RAILTRAIL"); rtfte_lightning1 = P_FindParticleType("TE_LIGHTNING1"); @@ -2162,11 +2176,9 @@ void CL_ParseParticleEffect4 (void) P_RunParticleEffect4 (org, radius, color, effect, msgcount); } -void CL_SpawnSpriteEffect(vec3_t org, vec3_t dir, model_t *model, int startframe, int framecount, float framerate, float alpha, float randspin, float gravity, int traileffect) +void CL_SpawnSpriteEffect(vec3_t org, vec3_t dir, vec3_t orientationup, model_t *model, int startframe, int framecount, float framerate, float alpha, float randspin, float gravity, int traileffect, unsigned int renderflags) { explosion_t *ex; - vec3_t spos; - float dlen; ex = CL_AllocExplosion (org); ex->start = cl.time; @@ -2177,14 +2189,16 @@ void CL_SpawnSpriteEffect(vec3_t org, vec3_t dir, model_t *model, int startframe ex->skinnum = 0; ex->traileffect = traileffect; - if (alpha >= -1 && alpha < 1) - ex->flags |= RF_TRANSLUCENT; + ex->flags |= renderflags; //sprites always use a fixed alpha. models can too if the alpha is < 0 if (model->type == mod_sprite || alpha < 0) ex->endalpha = fabs(alpha); ex->startalpha = fabs(alpha); + if (ex->endalpha < 1 || ex->startalpha < 1) + ex->flags |= RF_TRANSLUCENT; + if (randspin) { ex->angles[0] = frandom()*360; @@ -2197,12 +2211,30 @@ void CL_SpawnSpriteEffect(vec3_t org, vec3_t dir, model_t *model, int startframe } ex->gravity = gravity; + if (orientationup) + { + ex->angles[0] = acos(orientationup[2])/M_PI*180; + if (orientationup[0]) + ex->angles[1] = atan2(orientationup[1], orientationup[0])/M_PI*180; + else if (orientationup[1] > 0) + ex->angles[1] = 90; + else if (orientationup[1] < 0) + ex->angles[1] = 270; + else + ex->angles[1] = 0; + ex->angles[0]*=-1; + } + + if (dir) { +// vec3_t spos; +// float dlen; +// dlen = -10/VectorLength(dir); +// VectorMA(ex->origin, dlen, dir, spos); +// TraceLineN(spos, org, ex->origin, NULL); + VectorCopy(dir, ex->velocity); - dlen = -10/VectorLength(dir); - VectorMA(ex->origin, dlen, dir, spos); - TraceLineN(spos, org, ex->origin, NULL); } else VectorClear(ex->velocity); @@ -2237,7 +2269,7 @@ void CL_ParseEffect (qboolean effect2) framerate = MSG_ReadByte(); mod = cl.model_precache[modelindex]; - CL_SpawnSpriteEffect(org, vec3_origin, mod, startframe, framecount, framerate, mod->type==mod_sprite?-1:1, 0, 0, P_INVALID); + CL_SpawnSpriteEffect(org, NULL, NULL, mod, startframe, framecount, framerate, mod->type==mod_sprite?-1:1, 0, 0, P_INVALID, 0); } #ifdef Q2CLIENT @@ -2302,6 +2334,43 @@ void CLQ2_ParseTEnt (void) switch (type) { + case Q2TE_GUNSHOT: + MSG_ReadPos (pos); + MSG_ReadDir (dir); + P_RunParticleEffectTypeString(pos, dir, 1, "q2part.teq2_gunshot"); + break; + case Q2TE_BLOOD: + MSG_ReadPos (pos); + MSG_ReadDir (dir); + P_RunParticleEffectTypeString(pos, dir, 1, "q2part.teq2_blood"); + break; + case Q2TE_SHOTGUN: + MSG_ReadPos (pos); + MSG_ReadDir (dir); + P_RunParticleEffectTypeString(pos, dir, 1, "q2part.teq2_shotgun"); + break; + case Q2TE_BLASTER: + MSG_ReadPos (pos); + MSG_ReadDir (dir); + P_RunParticleEffectTypeString(pos, dir, 1, "q2part.teq2_blaster"); + break; + + case Q2TE_RAILTRAIL: // railgun effect + MSG_ReadPos (pos); + MSG_ReadPos (pos2); + if (P_ParticleTrail(pos, pos2, rtq2_railtrail, 0, NULL)) + P_ParticleTrailIndex(pos, pos2, 0x74, 8, NULL); + Q2S_StartSound (pos, 0, 0, S_PrecacheSound ("weapons/railgf1a.wav"), 1, ATTN_NORM, 0); + break; + default: + goto fixme; +// Host_EndGame ("CLQ2_ParseTEnt: bad/non-implemented type %i", type); +// break; + } + return; +fixme: + switch(type) + { case Q2TE_BLOOD: // bullet hitting flesh MSG_ReadPos (pos); MSG_ReadDir (dir); diff --git a/engine/client/client.h b/engine/client/client.h index e3951c210..73967d31e 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -909,7 +909,6 @@ extern unsigned int cl_maxstris; extern char emodel_name[], pmodel_name[], prespawn_name[], modellist_name[], soundlist_name[]; qboolean TraceLineN (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal); -qboolean Q2TraceLineN (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal); // // cl_input @@ -1086,7 +1085,7 @@ void CL_ParseParticleEffect4 (void); int CL_TranslateParticleFromServer(int sveffect); void CL_ParseTrailParticles(void); void CL_ParsePointParticles(qboolean compact); -void CL_SpawnSpriteEffect(vec3_t org, vec3_t dir, struct model_s *model, int startframe, int framecount, float framerate, float alpha, float randspin, float gravity, int traileffect); /*called from the particlesystem*/ +void CL_SpawnSpriteEffect(vec3_t org, vec3_t dir, vec3_t orientationup, struct model_s *model, int startframe, int framecount, float framerate, float alpha, float randspin, float gravity, int traileffect, unsigned int renderflags); /*called from the particlesystem*/ // // cl_ents.c diff --git a/engine/client/clq2_ents.c b/engine/client/clq2_ents.c index 39a13e407..31382d318 100644 --- a/engine/client/clq2_ents.c +++ b/engine/client/clq2_ents.c @@ -118,11 +118,6 @@ void CLQ2_ClearState(void) memset(cl_entities, 0, sizeof(cl_entities)); } -//extern struct model_s *cl_mod_powerscreen; - -//PGM -int vidref_val; -//PGM #include "q2m_flash.c" void CLQ2_RunMuzzleFlash2 (int ent, int flash_number) { @@ -130,12 +125,25 @@ void CLQ2_RunMuzzleFlash2 (int ent, int flash_number) dlight_t *dl; vec3_t forward, right, up; char soundname[64]; + int ef; + + if (flash_number < 0 || flash_number >= sizeof(monster_flash_offset)/sizeof(monster_flash_offset[0])) + return; // locate the origin AngleVectors (cl_entities[ent].current.angles, forward, right, up); - origin[0] = cl_entities[ent].current.origin[0] + forward[0] * monster_flash_offset[flash_number][0] + right[0] * monster_flash_offset[flash_number][1]; - origin[1] = cl_entities[ent].current.origin[1] + forward[1] * monster_flash_offset[flash_number][0] + right[1] * monster_flash_offset[flash_number][1]; - origin[2] = cl_entities[ent].current.origin[2] + forward[2] * monster_flash_offset[flash_number][0] + right[2] * monster_flash_offset[flash_number][1] + monster_flash_offset[flash_number][2]; + origin[0] = cl_entities[ent].current.origin[0] + forward[0] * monster_flash_offset[flash_number].offset[0] + right[0] * monster_flash_offset[flash_number].offset[1]; + origin[1] = cl_entities[ent].current.origin[1] + forward[1] * monster_flash_offset[flash_number].offset[0] + right[1] * monster_flash_offset[flash_number].offset[1]; + origin[2] = cl_entities[ent].current.origin[2] + forward[2] * monster_flash_offset[flash_number].offset[0] + right[2] * monster_flash_offset[flash_number].offset[1] + monster_flash_offset[flash_number].offset[2]; + + ef = P_FindParticleType(monster_flash_offset[flash_number].name); + if (ef != P_INVALID) + { + P_RunParticleEffectType(origin, NULL, 1, ef); + return; + } + + //the rest of the function is legacy code. dl = CL_AllocDlight (ent); VectorCopy (origin, dl->origin); @@ -491,9 +499,6 @@ void CLQ2_RunMuzzleFlash2 (int ent, int flash_number) //hmm... he must take AGES on the loo.... :p } - dl->color[0] /= 5; - dl->color[1] /= 5; - dl->color[2] /= 5; } /* @@ -1310,9 +1315,6 @@ void CLQ2_AddPacketEntities (q2frame_t *frame) ent.model = player->model; if (!ent.model || ent.model->needload) //we need to do better than this { - char *pmodel = Info_ValueForKey(player->userinfo, "model"); - if (*pmodel) - ent.model = Mod_ForName(va("players/%s/tris.md2", pmodel), MLV_WARN); if (!ent.model || ent.model->needload) ent.model = Mod_ForName("players/male/tris.md2", MLV_SILENT); } diff --git a/engine/client/clq3_parse.c b/engine/client/clq3_parse.c index be9f92242..7cf73c18b 100644 --- a/engine/client/clq3_parse.c +++ b/engine/client/clq3_parse.c @@ -568,7 +568,7 @@ void CLQ3_ParseGameState(void) switch(c) { default: - Host_EndGame("CLQ3_ParseGameState: bad command byte"); + Host_EndGame("CLQ3_ParseGameState: bad command byte %i", c); break; case svcq3_configstring: @@ -753,7 +753,7 @@ qboolean CLQ3_Netchan_Process(void) { c = '.'; } - bitmask ^= c << (i & 1); + bitmask ^= c << ((i-msg_readcount) & 1); net_message.data[i] ^= bitmask; } #endif @@ -1060,8 +1060,14 @@ void CLQ3_SendConnectPacket(netadr_t *to) msg.maxsize = sizeof(data); MSG_WriteLong(&msg, -1); MSG_WriteString(&msg, va("connect \"\\challenge\\%i\\qport\\%i\\protocol\\%i\\ip\\%s%s\"", cls.challenge, cls.qport, PROTOCOL_VERSION_Q3, NET_AdrToString (adrbuf, sizeof(adrbuf), &net_local_cl_ipadr), cls.userinfo[0])); +#ifdef HUFFNETWORK Huff_EncryptPacket(&msg, 12); - Huff_PreferedCompressionCRC(); + if (!Huff_CompressionCRC(HUFFCRC_QUAKE3)) + { + Con_Printf("Huffman compression error\n"); + return; + } +#endif NET_SendPacket (NS_CLIENT, msg.cursize, msg.data, to); } #endif diff --git a/engine/client/in_win.c b/engine/client/in_win.c index 9f9614955..5ae301a1f 100644 --- a/engine/client/in_win.c +++ b/engine/client/in_win.c @@ -528,7 +528,7 @@ void INS_UpdateGrabs(int fullscreen, int activeapp) grabmouse = false; //visiblity - if (grabmouse) + if (grabmouse || (mousecursor_x > 0 && mousecursor_y > 0 && mousecursor_x < vid.pixelwidth && mousecursor_y < vid.pixelheight)) INS_HideMouse(); else INS_ShowMouse(); diff --git a/engine/client/keys.c b/engine/client/keys.c index db8b6b947..3186306da 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -1995,7 +1995,7 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down) { #ifdef VM_UI #ifdef TEXTEDITOR - if (!Key_Dest_Has(~kdm_game)) + if (!Key_Dest_Has(~kdm_game) && !Key_Dest_Has(kdm_console)) #endif { if (down && Media_PlayingFullScreen()) @@ -2013,9 +2013,8 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down) if (Key_Dest_Has(kdm_console)) { - if (cls.state || Key_Dest_Has(~(kdm_console|kdm_game))) - Key_Dest_Remove(kdm_console); - else + Key_Dest_Remove(kdm_console); + if (!cls.state && !Key_Dest_Has(~kdm_game)) M_ToggleMenu_f (); } #ifdef TEXTEDITOR diff --git a/engine/client/menu.c b/engine/client/menu.c index 7b74068c4..53e0c4ed9 100644 --- a/engine/client/menu.c +++ b/engine/client/menu.c @@ -377,6 +377,7 @@ void M_Menu_Keys_f (void) menu_t *menu; int mgt; extern cvar_t cl_splitscreen, cl_forcesplitclient; + vfsfile_t *bindslist; Key_Dest_Add(kdm_menu); m_state = m_complex; @@ -428,6 +429,20 @@ void M_Menu_Keys_f (void) y+=8; } + bindslist = FS_OpenVFS("bindlist.lst", "rb", FS_GAME); + if (bindslist) + { + char line[1024]; + while(VFS_GETS(bindslist, line, sizeof(line))) + { + Cmd_TokenizeString(line, false, false); + MC_AddBind(menu, 16, 170, y, Cmd_Argv(1), Cmd_Argv(0)); + y += 8; + } + VFS_CLOSE(bindslist); + return; + } + while (bindnames->name) { MC_AddBind(menu, 16, 170, y, bindnames->name, bindnames->command); diff --git a/engine/client/p_script.c b/engine/client/p_script.c index 604af5f56..5d65884d2 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -178,7 +178,17 @@ typedef struct { float framerate; float alpha; int traileffect; + unsigned int rflags; +#define RF_USEORIENTATION Q2RF_CUSTOMSKIN //private flag } partmodels_t; +typedef struct { + char name[MAX_QPATH]; + float vol; + float atten; + float delay; + float pitch; + float weight; +} partsounds_t; // TODO: merge in alpha with rgb to gain benefit of vector opts typedef struct part_type_s { char name[MAX_QPATH]; @@ -188,11 +198,8 @@ typedef struct part_type_s { int nummodels; partmodels_t *models; - char soundname[MAX_QPATH]; - float soundvol; - float soundattn; - float sounddelay; - float soundpitch; + int numsounds; + partsounds_t *sounds; vec3_t rgb; //initial colour float alpha; @@ -208,8 +215,8 @@ typedef struct part_type_s { float scalerand; //with up to this much extra float die, randdie; //how long it lasts (plus some rand) float randomvel, randomvelvert, randomvelvertbias; //random velocity (unaligned=worldspace) - float veladd; //scale the incoming velocity by this much - float orgadd; //spawn the particle this far along its velocity direction + float veladd, randomveladd; //scale the incoming velocity by this much + float orgadd, randomorgadd; //spawn the particle this far along its velocity direction float spawnvel, spawnvelvert; //spawn the particle with a velocity based upon its spawn type (generally so it flies outwards) vec3_t orgbias; //static 3d world-coord bias @@ -836,6 +843,8 @@ static void P_ResetToDefaults(part_type_t *ptype) BZ_Free(ptype->ramp); if (ptype->models) BZ_Free(ptype->models); + if (ptype->sounds) + BZ_Free(ptype->sounds); //reset everything we're too lazy to specifically set memset(ptype, 0, sizeof(*ptype)); @@ -1189,9 +1198,19 @@ static void P_ParticleEffect_f(void) } } else if (!strcmp(var, "veladd")) + { ptype->veladd = atof(value); + ptype->randomveladd = 0; + if (Cmd_Argc()>2) + ptype->randomveladd = atof(Cmd_Argv(2)) - ptype->veladd; + } else if (!strcmp(var, "orgadd")) + { ptype->orgadd = atof(value); + ptype->randomorgadd = 0; + if (Cmd_Argc()>2) + ptype->randomorgadd = atof(Cmd_Argv(2)) - ptype->orgadd; + } else if (!strcmp(var, "friction")) { ptype->friction[2] = ptype->friction[1] = ptype->friction[0] = atof(value); @@ -1225,28 +1244,102 @@ static void P_ParticleEffect_f(void) } else if (!strcmp(var, "model")) { - if (*Cmd_Argv(6)) - { - assoc = P_AllocateParticleType(config, Cmd_Argv(6));//careful - this can realloc all the particle types - ptype = &part_type[pnum]; - } - else - assoc = -1; + partmodels_t *mod; + char *e; ptype->models = BZ_Realloc(ptype->models, sizeof(partmodels_t)*(ptype->nummodels+1)); Q_strncpyz(ptype->models[ptype->nummodels].name, Cmd_Argv(1), sizeof(ptype->models[ptype->nummodels].name)); - ptype->models[ptype->nummodels].framestart = atof(Cmd_Argv(2)); - ptype->models[ptype->nummodels].frameend = atof(Cmd_Argv(3)); - ptype->models[ptype->nummodels].framerate = atof(Cmd_Argv(4)); - ptype->models[ptype->nummodels].alpha = atof(Cmd_Argv(5)); - ptype->models[ptype->nummodels].traileffect = assoc; - ptype->nummodels++; + mod = &ptype->models[ptype->nummodels++]; + + mod->framestart = 0; + mod->frameend = 1; + mod->framerate = 10; + mod->alpha = 1; + mod->traileffect = P_INVALID; + mod->rflags = RF_NOSHADOW; + + strtoul(Cmd_Argv(2), &e, 0); + while(*e == ' ' || *e == '\t') + e++; + if (*e) + { + int p; + for(p = 2; p < Cmd_Argc(); p++) + { + e = Cmd_Argv(p); + + if (!Q_strncasecmp(e, "framestart=", 11)) + mod->framestart = atof(e+11); + else if (!Q_strncasecmp(e, "frameend=", 9)) + mod->frameend = atof(e+9); + else if (!Q_strncasecmp(e, "framerate=", 10)) + mod->framerate = atof(e+10); + else if (!Q_strncasecmp(e, "alpha=", 6)) + mod->alpha = atof(e+6); + else if (!Q_strncasecmp(e, "trail=", 6)) + { + mod->traileffect = P_AllocateParticleType(config, e+6);//careful - this can realloc all the particle types + ptype = &part_type[pnum]; + } + else if (!Q_strncasecmp(e, "orient", 6)) + mod->rflags |= RF_USEORIENTATION; //use the dir to orient the model, instead of always facing up. + else if (!Q_strncasecmp(e, "additive", 8)) + mod->rflags |= RF_ADDITIVE; //additive blend + else if (!Q_strncasecmp(e, "transparent", 11)) + mod->rflags |= RF_TRANSLUCENT; //force blend + else if (!Q_strncasecmp(e, "fullbright", 10)) + mod->rflags |= Q2RF_FULLBRIGHT; //fullbright, woo + else if (!Q_strncasecmp(e, "shadow", 6)) + mod->rflags &= ~RF_NOSHADOW; //clear noshadow + else if (!Q_strncasecmp(e, "noshadow", 8)) + mod->rflags |= RF_NOSHADOW; //set noshadow (cos... you know...) + else + Con_Printf("Bad named argument: %s\n", e); + } + } + else + { + mod->framestart = atof(Cmd_Argv(2)); + mod->frameend = atof(Cmd_Argv(3)); + mod->framerate = atof(Cmd_Argv(4)); + mod->alpha = atof(Cmd_Argv(5)); + if (*Cmd_Argv(6)) + { + mod->traileffect = P_AllocateParticleType(config, Cmd_Argv(6));//careful - this can realloc all the particle types + ptype = &part_type[pnum]; + } + else + mod->traileffect = P_INVALID; + } + } + else if (!strcmp(var, "sound")) + { + ptype->sounds = BZ_Realloc(ptype->sounds, sizeof(partsounds_t)*(ptype->numsounds+1)); + Q_strncpyz(ptype->sounds[ptype->numsounds].name, Cmd_Argv(1), sizeof(ptype->sounds[ptype->numsounds].name)); + if (*ptype->sounds[ptype->numsounds].name) + S_PrecacheSound(ptype->sounds[ptype->numsounds].name); + ptype->sounds[ptype->numsounds].vol = atof(Cmd_Argv(2)); + if (!ptype->sounds[ptype->numsounds].vol) + ptype->sounds[ptype->numsounds].vol = 1; + ptype->sounds[ptype->numsounds].atten = atof(Cmd_Argv(3)); + if (!ptype->sounds[ptype->numsounds].atten) + ptype->sounds[ptype->numsounds].atten = 1; + ptype->sounds[ptype->numsounds].pitch = atof(Cmd_Argv(4)); + if (!ptype->sounds[ptype->numsounds].pitch) + ptype->sounds[ptype->numsounds].pitch = 100; + ptype->sounds[ptype->numsounds].delay = atof(Cmd_Argv(5)); + if (!ptype->sounds[ptype->numsounds].delay) + ptype->sounds[ptype->numsounds].delay = 0; + ptype->sounds[ptype->numsounds].weight = atof(Cmd_Argv(6)); + if (!ptype->sounds[ptype->numsounds].weight) + ptype->sounds[ptype->numsounds].weight = 1; + ptype->numsounds++; } else if (!strcmp(var, "colorindex")) { if (Cmd_Argc()>2) - ptype->colorrand = atof(Cmd_Argv(2)); - ptype->colorindex = atoi(value); + ptype->colorrand = strtoul(Cmd_Argv(2), NULL, 0); + ptype->colorindex = strtoul(value, NULL, 0); } else if (!strcmp(var, "colorrand")) ptype->colorrand = atoi(value); // now obsolete @@ -1624,23 +1717,6 @@ static void P_ParticleEffect_f(void) else if (!strcmp(var, "nospreadlast")) ptype->flags |= PT_NOSPREADLAST; - else if (!strcmp(var, "sound")) - { - Q_strncpyz(ptype->soundname, value, sizeof(ptype->soundname)); - ptype->soundvol = atof(Cmd_Argv(2)); - if (!ptype->soundvol) - ptype->soundvol = 1; - ptype->soundattn = atof(Cmd_Argv(3)); - if (!ptype->soundattn) - ptype->soundattn = 1; - ptype->soundpitch = atof(Cmd_Argv(4)); - if (!ptype->soundpitch) - ptype->soundpitch = 100; - ptype->sounddelay = atof(Cmd_Argv(5)); - if (!ptype->sounddelay) - ptype->sounddelay = 0; - } - else if (!strcmp(var, "lightradius")) ptype->dl_radius = atof(value); else if (!strcmp(var, "lightradiusfade")) @@ -1827,7 +1903,11 @@ qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen) for (i = 0; i < ptype->nummodels; i++) { - Q_strncatz(outstr, va("model \"%s\" %g %g %g %g \"%s\"\n", ptype->models[i].name, ptype->models[i].framestart, ptype->models[i].frameend, ptype->models[i].framerate, ptype->models[i].alpha, ptype->assoc==P_INVALID?"":part_type[ptype->assoc].name), outstrlen); + Q_strncatz(outstr, va("model \"%s\" %g %g %g %g \"%s\"\n", ptype->models[i].name, ptype->models[i].framestart, ptype->models[i].frameend, ptype->models[i].framerate, ptype->models[i].alpha, ptype->models[i].traileffect==P_INVALID?"":part_type[ptype->models[i].traileffect].name), outstrlen); + } + for (i = 0; i < ptype->numsounds; i++) + { + Q_strncatz(outstr, va("sound \"%s\" %g %g %g %g %g\n", ptype->sounds[i].name, ptype->sounds[i].vol, ptype->sounds[i].atten, ptype->sounds[i].pitch, ptype->sounds[i].delay, ptype->sounds[i].weight), outstrlen); } if (*ptype->texname) @@ -1910,10 +1990,10 @@ qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen) if (ptype->areaspread || ptype->areaspreadvert) Q_strncatz(outstr, va("spawnorg %g %g\n", ptype->areaspread, ptype->areaspreadvert), outstrlen); - if (ptype->veladd) - Q_strncatz(outstr, va("veladd %g\n", ptype->veladd), outstrlen); - if (ptype->orgadd) - Q_strncatz(outstr, va("orgadd %g\n", ptype->orgadd), outstrlen); + if (ptype->veladd || ptype->randomveladd) + Q_strncatz(outstr, va(ptype->randomveladd?"veladd %g %g\n":"veladd %g\n", ptype->veladd, ptype->veladd+ptype->randomveladd), outstrlen); + if (ptype->orgadd || ptype->randomorgadd) + Q_strncatz(outstr, va(ptype->randomorgadd?"orgadd %g %g\n":"orgadd %g\n", ptype->orgadd, ptype->orgadd+ptype->randomorgadd), outstrlen); if (ptype->randomvel || ptype->randomvelvert || ptype->randomvelvertbias) Q_strncatz(outstr, va("randomvel %g %g %g\n", ptype->randomvel, ptype->randomvelvertbias - ptype->randomvelvert, ptype->randomvelvertbias + ptype->randomvelvert), outstrlen); @@ -1923,9 +2003,6 @@ qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen) Q_strncatz(outstr, va("rotationstart %g %g\n", ptype->rotationstartmin*180/M_PI, (ptype->rotationstartmin+ptype->rotationstartrand)*180/M_PI), outstrlen); Q_strncatz(outstr, va("rotationspeed %g %g\n", ptype->rotationmin*180/M_PI, (ptype->rotationmin+ptype->rotationrand)*180/M_PI), outstrlen); - if (ptype->soundvol) - Q_strncatz(outstr, va("sound \"%s\" %g %g %g %g\n", ptype->soundname, ptype->soundvol, ptype->soundattn, ptype->soundpitch, ptype->sounddelay), outstrlen); - if (ptype->dl_radius) { Q_strncatz(outstr, va("lightradius %g\n", ptype->dl_radius), outstrlen); @@ -2688,6 +2765,8 @@ static void PScript_Shutdown (void) numparticletypes--; if (part_type[numparticletypes].models) BZ_Free(part_type[numparticletypes].models); + if (part_type[numparticletypes].sounds) + BZ_Free(part_type[numparticletypes].sounds); if (part_type[numparticletypes].ramp) BZ_Free(part_type[numparticletypes].ramp); } @@ -3447,24 +3526,27 @@ static void PScript_ApplyOrgVel(vec3_t oorg, vec3_t ovel, vec3_t eforg, vec3_t e oorg[1] = eforg[1] + arsvec[1]; oorg[2] = eforg[2] + arsvec[2]; + k = ptype->orgadd + frandom()*ptype->randomorgadd; + l = ptype->veladd + frandom()*ptype->randomveladd; + // apply arsvec+ofsvec if (efdir) { - ovel[0] += efdir[0]*ptype->veladd+ofsvec[0]*ptype->spawnvel; - ovel[1] += efdir[1]*ptype->veladd+ofsvec[1]*ptype->spawnvel; - ovel[2] += efdir[2]*ptype->veladd+ofsvec[2]*ptype->spawnvelvert; + ovel[0] += efdir[0]*l+ofsvec[0]*ptype->spawnvel; + ovel[1] += efdir[1]*l+ofsvec[1]*ptype->spawnvel; + ovel[2] += efdir[2]*l+ofsvec[2]*ptype->spawnvelvert; - oorg[0] += efdir[0]*ptype->orgadd; - oorg[1] += efdir[1]*ptype->orgadd; - oorg[2] += efdir[2]*ptype->orgadd; + oorg[0] += efdir[0]*k; + oorg[1] += efdir[1]*k; + oorg[2] += efdir[2]*k; } else {//efdir is effectively up - '0 0 -1' ovel[0] += ofsvec[0]*ptype->spawnvel; ovel[1] += ofsvec[1]*ptype->spawnvel; - ovel[2] += ofsvec[2]*ptype->spawnvelvert - ptype->veladd; + ovel[2] += ofsvec[2]*ptype->spawnvelvert - l; - oorg[2] -= ptype->orgadd; + oorg[2] -= k; } VectorAdd(oorg, ptype->orgbias, oorg); } @@ -3487,7 +3569,7 @@ static void PScript_EffectSpawned(part_type_t *ptype, vec3_t org, vec3_t dir, in { vec3_t morg, mdir; PScript_ApplyOrgVel(morg, mdir, org, dir, i, count, ptype); - CL_SpawnSpriteEffect(morg, mdir, mod->model, mod->framestart, (mod->frameend?mod->frameend:(mod->model->numframes - mod->framestart)), mod->framerate?mod->framerate:10, mod->alpha?mod->alpha:1, ptype->rotationmin*180/M_PI, ptype->gravity, mod->traileffect); + CL_SpawnSpriteEffect(morg, mdir, (mod->rflags&RF_USEORIENTATION)?dir:NULL, mod->model, mod->framestart, (mod->frameend?mod->frameend:(mod->model->numframes - mod->framestart)), mod->framerate?mod->framerate:10, mod->alpha?mod->alpha:1, ptype->rotationmin*180/M_PI, ptype->gravity, mod->traileffect, mod->rflags & ~RF_USEORIENTATION); } } } @@ -3510,9 +3592,24 @@ static void PScript_EffectSpawned(part_type_t *ptype, vec3_t org, vec3_t dir, in if (ptype->dl_cubemapnum) snprintf(dl->cubemapname, sizeof(dl->cubemapname), "cubemaps/%i", ptype->dl_cubemapnum); } - if (*ptype->soundname) + if (ptype->numsounds) { - S_StartSound(0, 0, S_PrecacheSound(ptype->soundname), org, ptype->soundvol, ptype->soundattn, ptype->sounddelay, ptype->soundpitch); + int i; + float w,tw; + for (i = 0, tw = 0; i < ptype->numsounds; i++) + tw += ptype->sounds[i].weight; + w = frandom() * tw; //select the sound by weight + //and figure out which one that weight corresponds to + for (i = 0, tw = 0; i < ptype->numsounds; i++) + { + tw += ptype->sounds[i].weight; + if (w <= tw) + { + if (*ptype->sounds[i].name && ptype->sounds[i].vol > 0) + S_StartSound(0, 0, S_PrecacheSound(ptype->sounds[i].name), org, ptype->sounds[i].vol, ptype->sounds[i].atten, ptype->sounds[i].delay, ptype->sounds[i].pitch); + break; + } + } } if (ptype->stain_radius) Surf_AddStain(org, ptype->stain_rgb[0], ptype->stain_rgb[1], ptype->stain_rgb[2], ptype->stain_radius); @@ -3523,7 +3620,7 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, { part_type_t *ptype = &part_type[typenum]; int i, j, k, l, spawnspc; - float m, pcount; + float m, pcount, orgadd, veladd; particle_t *p; beamseg_t *b, *bfirst; vec3_t ofsvec, arsvec; // offsetspread vec, areaspread vec @@ -4036,23 +4133,25 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, p->org[2] = org[2] + arsvec[2]; // apply arsvec+ofsvec + orgadd = ptype->orgadd + frandom()*ptype->randomorgadd; + veladd = ptype->veladd + frandom()*ptype->randomveladd; if (dir) { - p->vel[0] += dir[0]*ptype->veladd+ofsvec[0]*ptype->spawnvel; - p->vel[1] += dir[1]*ptype->veladd+ofsvec[1]*ptype->spawnvel; - p->vel[2] += dir[2]*ptype->veladd+ofsvec[2]*ptype->spawnvelvert; + p->vel[0] += dir[0]*veladd+ofsvec[0]*ptype->spawnvel; + p->vel[1] += dir[1]*veladd+ofsvec[1]*ptype->spawnvel; + p->vel[2] += dir[2]*veladd+ofsvec[2]*ptype->spawnvelvert; - p->org[0] += dir[0]*ptype->orgadd; - p->org[1] += dir[1]*ptype->orgadd; - p->org[2] += dir[2]*ptype->orgadd; + p->org[0] += dir[0]*orgadd; + p->org[1] += dir[1]*orgadd; + p->org[2] += dir[2]*orgadd; } else { p->vel[0] += ofsvec[0]*ptype->spawnvel; p->vel[1] += ofsvec[1]*ptype->spawnvel; - p->vel[2] += ofsvec[2]*ptype->spawnvelvert - ptype->veladd; + p->vel[2] += ofsvec[2]*ptype->spawnvelvert - veladd; - p->org[2] -= ptype->orgadd; + p->org[2] -= orgadd; } VectorAdd(p->org, ptype->orgbias, p->org); @@ -5607,12 +5706,7 @@ static void PScript_DrawParticleTypes (void) VectorScale (vup, 1.5, pup); VectorScale (vright, 1.5, pright); -#ifdef Q2BSPS - if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3) - tr = Q2TraceLineN; - else -#endif - tr = TraceLineN; + tr = TraceLineN; kill_list = kill_first = NULL; diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 9fcbd042a..615908ffe 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -2954,7 +2954,7 @@ void QCBUILTIN PF_cl_effect(pubprogfuncs_t *prinst, struct globalvars_s *pr_glob mdl = Mod_ForName(name, MLV_WARN); if (mdl) - CL_SpawnSpriteEffect(org, NULL, mdl, startframe, endframe, framerate, mdl->type==mod_sprite?-1:1, 0, 0, P_INVALID); + CL_SpawnSpriteEffect(org, NULL, NULL, mdl, startframe, endframe, framerate, mdl->type==mod_sprite?-1:1, 0, 0, P_INVALID, 0); else Con_Printf("PF_cl_effect: Couldn't load model %s\n", name); } @@ -5658,12 +5658,12 @@ void CSQC_Breakpoint_f(void) else Con_Printf("Breakpoint has been cleared\n"); - Cvar_Set(Cvar_FindVar("debugger"), "1"); + Cvar_Set(Cvar_FindVar("pr_debugger"), "1"); } static void CSQC_Poke_f(void) { - if (!csqc_singlecheats) + if (!csqc_singlecheats && cls.state) Con_Printf("%s is a cheat command\n", Cmd_Argv(0)); else if (csqcprogs) Con_Printf("Result: %s\n", csqcprogs->EvaluateDebugString(csqcprogs, Cmd_Args())); diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index dab774d4a..337debdcc 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -2109,7 +2109,7 @@ void MP_Breakpoint_f(void) else Con_Printf("Breakpoint has been cleared\n"); - Cvar_Set(Cvar_FindVar("debugger"), "1"); + Cvar_Set(Cvar_FindVar("pr_debugger"), "1"); } void MP_RegisterCvarsAndCmds(void) diff --git a/engine/client/q2m_flash.c b/engine/client/q2m_flash.c index 9dd914022..9762dbf12 100644 --- a/engine/client/q2m_flash.c +++ b/engine/client/q2m_flash.c @@ -23,307 +23,308 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // this file is included in both the game dll and quake2, // the game needs it to source shot locations, the client // needs it to position muzzle flashes -vec3_t monster_flash_offset [] = +struct { + const char *name; + vec3_t offset; +} monster_flash_offset [] = { -// flash 0 is not used - { 0.0, 0.0, 0.0 }, - -// MZ2_TANK_BLASTER_1 1 - { 20.7, -18.5, 28.7 }, -// MZ2_TANK_BLASTER_2 2 - { 16.6, -21.5, 30.1 }, + {"MZ2_INVALID", {0.0, 0.0, 0.0}}, +// MZ2_TANK_BLASTER_1 + {"MZ2_TANK_BLASTER", {20.7, -18.5, 28.7}}, +// MZ2_TANK_BLASTER_2 + {"MZ2_TANK_BLASTER", {16.6, -21.5, 30.1}}, // MZ2_TANK_BLASTER_3 3 - { 11.8, -23.9, 32.1 }, + {"MZ2_TANK_BLASTER", {11.8, -23.9, 32.1}}, // MZ2_TANK_MACHINEGUN_1 4 - { 22.9, -0.7, 25.3 }, + {"MZ2_TANK_MACHINEGUN", {22.9, -0.7, 25.3}}, // MZ2_TANK_MACHINEGUN_2 5 - { 22.2, 6.2, 22.3 }, + {"MZ2_TANK_MACHINEGUN", {22.2, 6.2, 22.3}}, // MZ2_TANK_MACHINEGUN_3 6 - { 19.4, 13.1, 18.6 }, + {"MZ2_TANK_MACHINEGUN", {19.4, 13.1, 18.6}}, // MZ2_TANK_MACHINEGUN_4 7 - { 19.4, 18.8, 18.6 }, + {"MZ2_TANK_MACHINEGUN", {19.4, 18.8, 18.6}}, // MZ2_TANK_MACHINEGUN_5 8 - { 17.9, 25.0, 18.6 }, + {"MZ2_TANK_MACHINEGUN", {17.9, 25.0, 18.6}}, // MZ2_TANK_MACHINEGUN_6 9 - { 14.1, 30.5, 20.6 }, + {"MZ2_TANK_MACHINEGUN", {14.1, 30.5, 20.6}}, // MZ2_TANK_MACHINEGUN_7 10 - { 9.3, 35.3, 22.1 }, + {"MZ2_TANK_MACHINEGUN", {9.3, 35.3, 22.1}}, // MZ2_TANK_MACHINEGUN_8 11 - { 4.7, 38.4, 22.1 }, + {"MZ2_TANK_MACHINEGUN", {4.7, 38.4, 22.1}}, // MZ2_TANK_MACHINEGUN_9 12 - { -1.1, 40.4, 24.1 }, + {"MZ2_TANK_MACHINEGUN", {-1.1, 40.4, 24.1}}, // MZ2_TANK_MACHINEGUN_10 13 - { -6.5, 41.2, 24.1 }, + {"MZ2_TANK_MACHINEGUN", {-6.5, 41.2, 24.1}}, // MZ2_TANK_MACHINEGUN_11 14 - { 3.2, 40.1, 24.7 }, + {"MZ2_TANK_MACHINEGUN", {3.2, 40.1, 24.7}}, // MZ2_TANK_MACHINEGUN_12 15 - { 11.7, 36.7, 26.0 }, + {"MZ2_TANK_MACHINEGUN", {11.7, 36.7, 26.0}}, // MZ2_TANK_MACHINEGUN_13 16 - { 18.9, 31.3, 26.0 }, + {"MZ2_TANK_MACHINEGUN", {18.9, 31.3, 26.0}}, // MZ2_TANK_MACHINEGUN_14 17 - { 24.4, 24.4, 26.4 }, + {"MZ2_TANK_MACHINEGUN", {24.4, 24.4, 26.4}}, // MZ2_TANK_MACHINEGUN_15 18 - { 27.1, 17.1, 27.2 }, + {"MZ2_TANK_MACHINEGUN", {27.1, 17.1, 27.2}}, // MZ2_TANK_MACHINEGUN_16 19 - { 28.5, 9.1, 28.0 }, + {"MZ2_TANK_MACHINEGUN", {28.5, 9.1, 28.0}}, // MZ2_TANK_MACHINEGUN_17 20 - { 27.1, 2.2, 28.0 }, + {"MZ2_TANK_MACHINEGUN", {27.1, 2.2, 28.0}}, // MZ2_TANK_MACHINEGUN_18 21 - { 24.9, -2.8, 28.0 }, + {"MZ2_TANK_MACHINEGUN", {24.9, -2.8, 28.0}}, // MZ2_TANK_MACHINEGUN_19 22 - { 21.6, -7.0, 26.4 }, + {"MZ2_TANK_MACHINEGUN", {21.6, -7.0, 26.4}}, // MZ2_TANK_ROCKET_1 23 - { 6.2, 29.1, 49.1 }, + {"MZ2_TANK_ROCKET", {6.2, 29.1, 49.1}}, // MZ2_TANK_ROCKET_2 24 - { 6.9, 23.8, 49.1 }, + {"MZ2_TANK_ROCKET", {6.9, 23.8, 49.1}}, // MZ2_TANK_ROCKET_3 25 - { 8.3, 17.8, 49.5 }, + {"MZ2_TANK_ROCKET", {8.3, 17.8, 49.5}}, // MZ2_INFANTRY_MACHINEGUN_1 26 - { 26.6, 7.1, 13.1 }, + {"MZ2_INFANTRY_MACHINEGUN", {26.6, 7.1, 13.1}}, // MZ2_INFANTRY_MACHINEGUN_2 27 - { 18.2, 7.5, 15.4 }, + {"MZ2_INFANTRY_MACHINEGUN", {18.2, 7.5, 15.4}}, // MZ2_INFANTRY_MACHINEGUN_3 28 - { 17.2, 10.3, 17.9 }, + {"MZ2_INFANTRY_MACHINEGUN", {17.2, 10.3, 17.9}}, // MZ2_INFANTRY_MACHINEGUN_4 29 - { 17.0, 12.8, 20.1 }, + {"MZ2_INFANTRY_MACHINEGUN", {17.0, 12.8, 20.1}}, // MZ2_INFANTRY_MACHINEGUN_5 30 - { 15.1, 14.1, 21.8 }, + {"MZ2_INFANTRY_MACHINEGUN", {15.1, 14.1, 21.8}}, // MZ2_INFANTRY_MACHINEGUN_6 31 - { 11.8, 17.2, 23.1 }, + {"MZ2_INFANTRY_MACHINEGUN", {11.8, 17.2, 23.1}}, // MZ2_INFANTRY_MACHINEGUN_7 32 - { 11.4, 20.2, 21.0 }, + {"MZ2_INFANTRY_MACHINEGUN", {11.4, 20.2, 21.0}}, // MZ2_INFANTRY_MACHINEGUN_8 33 - { 9.0, 23.0, 18.9 }, + {"MZ2_INFANTRY_MACHINEGUN", {9.0, 23.0, 18.9}}, // MZ2_INFANTRY_MACHINEGUN_9 34 - { 13.9, 18.6, 17.7 }, + {"MZ2_INFANTRY_MACHINEGUN", {13.9, 18.6, 17.7}}, // MZ2_INFANTRY_MACHINEGUN_10 35 - { 15.4, 15.6, 15.8 }, + {"MZ2_INFANTRY_MACHINEGUN", {15.4, 15.6, 15.8}}, // MZ2_INFANTRY_MACHINEGUN_11 36 - { 10.2, 15.2, 25.1 }, + {"MZ2_INFANTRY_MACHINEGUN", {10.2, 15.2, 25.1}}, // MZ2_INFANTRY_MACHINEGUN_12 37 - { -1.9, 15.1, 28.2 }, + {"MZ2_INFANTRY_MACHINEGUN", {-1.9, 15.1, 28.2}}, // MZ2_INFANTRY_MACHINEGUN_13 38 - { -12.4, 13.0, 20.2 }, + {"MZ2_INFANTRY_MACHINEGUN", {-12.4, 13.0, 20.2}}, // MZ2_SOLDIER_BLASTER_1 39 - { 10.6 * 1.2, 7.7 * 1.2, 7.8 * 1.2 }, + {"MZ2_SOLDIER_BLASTER", {10.6 * 1.2, 7.7 * 1.2, 7.8 * 1.2}}, // MZ2_SOLDIER_BLASTER_2 40 - { 21.1 * 1.2, 3.6 * 1.2, 19.0 * 1.2 }, + {"MZ2_SOLDIER_BLASTER", {21.1 * 1.2, 3.6 * 1.2, 19.0 * 1.2}}, // MZ2_SOLDIER_SHOTGUN_1 41 - { 10.6 * 1.2, 7.7 * 1.2, 7.8 * 1.2 }, + {"MZ2_SOLDIER_SHOTGUN", {10.6 * 1.2, 7.7 * 1.2, 7.8 * 1.2}}, // MZ2_SOLDIER_SHOTGUN_2 42 - { 21.1 * 1.2, 3.6 * 1.2, 19.0 * 1.2 }, + {"MZ2_SOLDIER_SHOTGUN", {21.1 * 1.2, 3.6 * 1.2, 19.0 * 1.2}}, // MZ2_SOLDIER_MACHINEGUN_1 43 - { 10.6 * 1.2, 7.7 * 1.2, 7.8 * 1.2 }, + {"MZ2_SOLDIER_MACHINEGUN", {10.6 * 1.2, 7.7 * 1.2, 7.8 * 1.2}}, // MZ2_SOLDIER_MACHINEGUN_2 44 - { 21.1 * 1.2, 3.6 * 1.2, 19.0 * 1.2 }, + {"MZ2_SOLDIER_MACHINEGUN", {21.1 * 1.2, 3.6 * 1.2, 19.0 * 1.2}}, // MZ2_GUNNER_MACHINEGUN_1 45 - { 30.1 * 1.15, 3.9 * 1.15, 19.6 * 1.15 }, + {"MZ2_GUNNER_MACHINEGUN", {30.1 * 1.15, 3.9 * 1.15, 19.6 * 1.15}}, // MZ2_GUNNER_MACHINEGUN_2 46 - { 29.1 * 1.15, 2.5 * 1.15, 20.7 * 1.15 }, + {"MZ2_GUNNER_MACHINEGUN", {29.1 * 1.15, 2.5 * 1.15, 20.7 * 1.15}}, // MZ2_GUNNER_MACHINEGUN_3 47 - { 28.2 * 1.15, 2.5 * 1.15, 22.2 * 1.15 }, + {"MZ2_GUNNER_MACHINEGUN", {28.2 * 1.15, 2.5 * 1.15, 22.2 * 1.15}}, // MZ2_GUNNER_MACHINEGUN_4 48 - { 28.2 * 1.15, 3.6 * 1.15, 22.0 * 1.15 }, + {"MZ2_GUNNER_MACHINEGUN", {28.2 * 1.15, 3.6 * 1.15, 22.0 * 1.15}}, // MZ2_GUNNER_MACHINEGUN_5 49 - { 26.9 * 1.15, 2.0 * 1.15, 23.4 * 1.15 }, + {"MZ2_GUNNER_MACHINEGUN", {26.9 * 1.15, 2.0 * 1.15, 23.4 * 1.15}}, // MZ2_GUNNER_MACHINEGUN_6 50 - { 26.5 * 1.15, 0.6 * 1.15, 20.8 * 1.15 }, + {"MZ2_GUNNER_MACHINEGUN", {26.5 * 1.15, 0.6 * 1.15, 20.8 * 1.15}}, // MZ2_GUNNER_MACHINEGUN_7 51 - { 26.9 * 1.15, 0.5 * 1.15, 21.5 * 1.15 }, + {"MZ2_GUNNER_MACHINEGUN", {26.9 * 1.15, 0.5 * 1.15, 21.5 * 1.15}}, // MZ2_GUNNER_MACHINEGUN_8 52 - { 29.0 * 1.15, 2.4 * 1.15, 19.5 * 1.15 }, + {"MZ2_GUNNER_MACHINEGUN", {29.0 * 1.15, 2.4 * 1.15, 19.5 * 1.15}}, // MZ2_GUNNER_GRENADE_1 53 - { 4.6 * 1.15, -16.8 * 1.15, 7.3 * 1.15 }, + {"MZ2_GUNNER_GRENADE", {4.6 * 1.15, -16.8 * 1.15, 7.3 * 1.15}}, // MZ2_GUNNER_GRENADE_2 54 - { 4.6 * 1.15, -16.8 * 1.15, 7.3 * 1.15 }, + {"MZ2_GUNNER_GRENADE", {4.6 * 1.15, -16.8 * 1.15, 7.3 * 1.15}}, // MZ2_GUNNER_GRENADE_3 55 - { 4.6 * 1.15, -16.8 * 1.15, 7.3 * 1.15 }, + {"MZ2_GUNNER_GRENADE", {4.6 * 1.15, -16.8 * 1.15, 7.3 * 1.15}}, // MZ2_GUNNER_GRENADE_4 56 - { 4.6 * 1.15, -16.8 * 1.15, 7.3 * 1.15 }, + {"MZ2_GUNNER_GRENADE", {4.6 * 1.15, -16.8 * 1.15, 7.3 * 1.15}}, // MZ2_CHICK_ROCKET_1 57 // -24.8, -9.0, 39.0, - { 24.8, -9.0, 39.0 }, // PGM - this was incorrect in Q2 + {"MZ2_CHICK_ROCKET", {24.8, -9.0, 39.0}}, // PGM - this was incorrect in Q2 // MZ2_FLYER_BLASTER_1 58 - { 12.1, 13.4, -14.5 }, + {"MZ2_FLYER_BLASTER", {12.1, 13.4, -14.5}}, // MZ2_FLYER_BLASTER_2 59 - { 12.1, -7.4, -14.5 }, + {"MZ2_FLYER_BLASTER", {12.1, -7.4, -14.5}}, // MZ2_MEDIC_BLASTER_1 60 - { 12.1, 5.4, 16.5 }, + {"MZ2_MEDIC_BLASTER", {12.1, 5.4, 16.5}}, // MZ2_GLADIATOR_RAILGUN_1 61 - { 30.0, 18.0, 28.0 }, + {"MZ2_GLADIATOR_RAILGUN", {30.0, 18.0, 28.0}}, // MZ2_HOVER_BLASTER_1 62 - { 32.5, -0.8, 10.0 }, + {"MZ2_HOVER_BLASTER", {32.5, -0.8, 10.0}}, // MZ2_ACTOR_MACHINEGUN_1 63 - { 18.4, 7.4, 9.6 }, + {"MZ2_ACTOR_MACHINEGUN", {18.4, 7.4, 9.6}}, // MZ2_SUPERTANK_MACHINEGUN_1 64 - { 30.0, 30.0, 88.5 }, + {"MZ2_SUPERTANK_MACHINEGUN", {30.0, 30.0, 88.5}}, // MZ2_SUPERTANK_MACHINEGUN_2 65 - { 30.0, 30.0, 88.5 }, + {"MZ2_SUPERTANK_MACHINEGUN", {30.0, 30.0, 88.5}}, // MZ2_SUPERTANK_MACHINEGUN_3 66 - { 30.0, 30.0, 88.5 }, + {"MZ2_SUPERTANK_MACHINEGUN", {30.0, 30.0, 88.5}}, // MZ2_SUPERTANK_MACHINEGUN_4 67 - { 30.0, 30.0, 88.5 }, + {"MZ2_SUPERTANK_MACHINEGUN", {30.0, 30.0, 88.5}}, // MZ2_SUPERTANK_MACHINEGUN_5 68 - { 30.0, 30.0, 88.5 }, + {"MZ2_SUPERTANK_MACHINEGUN", {30.0, 30.0, 88.5}}, // MZ2_SUPERTANK_MACHINEGUN_6 69 - { 30.0, 30.0, 88.5 }, + {"MZ2_SUPERTANK_MACHINEGUN", {30.0, 30.0, 88.5}}, // MZ2_SUPERTANK_ROCKET_1 70 - { 16.0, -22.5, 91.2 }, + {"MZ2_SUPERTANK_ROCKET", {16.0, -22.5, 91.2}}, // MZ2_SUPERTANK_ROCKET_2 71 - { 16.0, -33.4, 86.7 }, + {"MZ2_SUPERTANK_ROCKET", {16.0, -33.4, 86.7}}, // MZ2_SUPERTANK_ROCKET_3 72 - { 16.0, -42.8, 83.3 }, + {"MZ2_SUPERTANK_ROCKET", {16.0, -42.8, 83.3}}, // --- Start Xian Stuff --- // MZ2_BOSS2_MACHINEGUN_L1 73 - { 32, -40, 70 }, + {"MZ2_BOSS2_MACHINEGUN_L", {32, -40, 70}}, // MZ2_BOSS2_MACHINEGUN_L2 74 - { 32, -40, 70 }, + {"MZ2_BOSS2_MACHINEGUN_L", {32, -40, 70}}, // MZ2_BOSS2_MACHINEGUN_L3 75 - { 32, -40, 70 }, + {"MZ2_BOSS2_MACHINEGUN_L", {32, -40, 70}}, // MZ2_BOSS2_MACHINEGUN_L4 76 - { 32, -40, 70 }, + {"MZ2_BOSS2_MACHINEGUN_L", {32, -40, 70}}, // MZ2_BOSS2_MACHINEGUN_L5 77 - { 32, -40, 70 }, + {"MZ2_BOSS2_MACHINEGUN_L", {32, -40, 70}}, // --- End Xian Stuff // MZ2_BOSS2_ROCKET_1 78 - { 22.0, 16.0, 10.0 }, + {"MZ2_BOSS2_ROCKET", {22.0, 16.0, 10.0}}, // MZ2_BOSS2_ROCKET_2 79 - { 22.0, 8.0, 10.0 }, + {"MZ2_BOSS2_ROCKET", {22.0, 8.0, 10.0}}, // MZ2_BOSS2_ROCKET_3 80 - { 22.0, -8.0, 10.0 }, + {"MZ2_BOSS2_ROCKET", {22.0, -8.0, 10.0}}, // MZ2_BOSS2_ROCKET_4 81 - { 22.0, -16.0, 10.0 }, + {"MZ2_BOSS2_ROCKET", {22.0, -16.0, 10.0}}, // MZ2_FLOAT_BLASTER_1 82 - { 32.5, -0.8, 10 }, + {"MZ2_FLOAT_BLASTER", {32.5, -0.8, 10}}, // MZ2_SOLDIER_BLASTER_3 83 - { 20.8 * 1.2, 10.1 * 1.2, -2.7 * 1.2 }, + {"MZ2_SOLDIER_BLASTER", {20.8 * 1.2, 10.1 * 1.2, -2.7 * 1.2}}, // MZ2_SOLDIER_SHOTGUN_3 84 - { 20.8 * 1.2, 10.1 * 1.2, -2.7 * 1.2 }, + {"MZ2_SOLDIER_SHOTGUN", {20.8 * 1.2, 10.1 * 1.2, -2.7 * 1.2}}, // MZ2_SOLDIER_MACHINEGUN_3 85 - { 20.8 * 1.2, 10.1 * 1.2, -2.7 * 1.2 }, + {"MZ2_SOLDIER_MACHINEGUN", {20.8 * 1.2, 10.1 * 1.2, -2.7 * 1.2}}, // MZ2_SOLDIER_BLASTER_4 86 - { 7.6 * 1.2, 9.3 * 1.2, 0.8 * 1.2 }, + {"MZ2_SOLDIER_BLASTER", {7.6 * 1.2, 9.3 * 1.2, 0.8 * 1.2}}, // MZ2_SOLDIER_SHOTGUN_4 87 - { 7.6 * 1.2, 9.3 * 1.2, 0.8 * 1.2 }, + {"MZ2_SOLDIER_SHOTGUN", {7.6 * 1.2, 9.3 * 1.2, 0.8 * 1.2}}, // MZ2_SOLDIER_MACHINEGUN_4 88 - { 7.6 * 1.2, 9.3 * 1.2, 0.8 * 1.2 }, + {"MZ2_SOLDIER_MACHINEGUN", {7.6 * 1.2, 9.3 * 1.2, 0.8 * 1.2}}, // MZ2_SOLDIER_BLASTER_5 89 - { 30.5 * 1.2, 9.9 * 1.2, -18.7 * 1.2 }, + {"MZ2_SOLDIER_BLASTER", {30.5 * 1.2, 9.9 * 1.2, -18.7 * 1.2}}, // MZ2_SOLDIER_SHOTGUN_5 90 - { 30.5 * 1.2, 9.9 * 1.2, -18.7 * 1.2 }, -// MZ2_SOLDIER_MACHINEGUN_5 91 - { 30.5 * 1.2, 9.9 * 1.2, -18.7 * 1.2 }, + {"MZ2_SOLDIER_SHOTGUN", {30.5 * 1.2, 9.9 * 1.2, -18.7 * 1.2}}, +// MZ2_SOLDIER_MACHINEGUN 91 + {"MZ2_SOLDIER_MACHINEGUN", {30.5 * 1.2, 9.9 * 1.2, -18.7 * 1.2}}, // MZ2_SOLDIER_BLASTER_6 92 - { 27.6 * 1.2, 3.4 * 1.2, -10.4 * 1.2 }, + {"MZ2_SOLDIER_BLASTER", {27.6 * 1.2, 3.4 * 1.2, -10.4 * 1.2}}, // MZ2_SOLDIER_SHOTGUN_6 93 - { 27.6 * 1.2, 3.4 * 1.2, -10.4 * 1.2 }, + {"MZ2_SOLDIER_SHOTGUN", {27.6 * 1.2, 3.4 * 1.2, -10.4 * 1.2}}, // MZ2_SOLDIER_MACHINEGUN_6 94 - { 27.6 * 1.2, 3.4 * 1.2, -10.4 * 1.2 }, + {"MZ2_SOLDIER_MACHINEGUN", {27.6 * 1.2, 3.4 * 1.2, -10.4 * 1.2}}, // MZ2_SOLDIER_BLASTER_7 95 - { 28.9 * 1.2, 4.6 * 1.2, -8.1 * 1.2 }, + {"MZ2_SOLDIER_BLASTER", {28.9 * 1.2, 4.6 * 1.2, -8.1 * 1.2}}, // MZ2_SOLDIER_SHOTGUN_7 96 - { 28.9 * 1.2, 4.6 * 1.2, -8.1 * 1.2 }, + {"MZ2_SOLDIER_SHOTGUN", {28.9 * 1.2, 4.6 * 1.2, -8.1 * 1.2}}, // MZ2_SOLDIER_MACHINEGUN_7 97 - { 28.9 * 1.2, 4.6 * 1.2, -8.1 * 1.2 }, + {"MZ2_SOLDIER_MACHINEGUN", {28.9 * 1.2, 4.6 * 1.2, -8.1 * 1.2}}, // MZ2_SOLDIER_BLASTER_8 98 // 34.5 * 1.2, 9.6 * 1.2, 6.1 * 1.2, - { 31.5 * 1.2, 9.6 * 1.2, 10.1 * 1.2 }, + {"MZ2_SOLDIER_BLASTER", {31.5 * 1.2, 9.6 * 1.2, 10.1 * 1.2}}, // MZ2_SOLDIER_SHOTGUN_8 99 - { 34.5 * 1.2, 9.6 * 1.2, 6.1 * 1.2 }, + {"MZ2_SOLDIER_SHOTGUN", {34.5 * 1.2, 9.6 * 1.2, 6.1 * 1.2}}, // MZ2_SOLDIER_MACHINEGUN_8 100 - { 34.5 * 1.2, 9.6 * 1.2, 6.1 * 1.2 }, + {"MZ2_SOLDIER_MACHINEGUN", {34.5 * 1.2, 9.6 * 1.2, 6.1 * 1.2}}, // --- Xian shit below --- // MZ2_MAKRON_BFG 101 - { 17, -19.5, 62.9 }, + {"MZ2_MAKRON_BFG", {17, -19.5, 62.9}}, // MZ2_MAKRON_BLASTER_1 102 - { -3.6, -24.1, 59.5 }, + {"MZ2_MAKRON_BLASTER", {-3.6, -24.1, 59.5}}, // MZ2_MAKRON_BLASTER_2 103 - { -1.6, -19.3, 59.5 }, + {"MZ2_MAKRON_BLASTER", {-1.6, -19.3, 59.5}}, // MZ2_MAKRON_BLASTER_3 104 - { -0.1, -14.4, 59.5, }, + {"MZ2_MAKRON_BLASTER", {-0.1, -14.4, 59.5, }}, // MZ2_MAKRON_BLASTER_4 105 - { 2.0, -7.6, 59.5, }, + {"MZ2_MAKRON_BLASTER", {2.0, -7.6, 59.5, }}, // MZ2_MAKRON_BLASTER_5 106 - { 3.4, 1.3, 59.5 }, + {"MZ2_MAKRON_BLASTER", {3.4, 1.3, 59.5}}, // MZ2_MAKRON_BLASTER_6 107 - { 3.7, 11.1, 59.5, }, + {"MZ2_MAKRON_BLASTER", {3.7, 11.1, 59.5, }}, // MZ2_MAKRON_BLASTER_7 108 - { -0.3, 22.3, 59.5 }, + {"MZ2_MAKRON_BLASTER", {-0.3, 22.3, 59.5}}, // MZ2_MAKRON_BLASTER_8 109 - { -6, 33, 59.5 }, + {"MZ2_MAKRON_BLASTER", {-6, 33, 59.5}}, // MZ2_MAKRON_BLASTER_9 110 - { -9.3, 36.4, 59.5 }, + {"MZ2_MAKRON_BLASTER", {-9.3, 36.4, 59.5}}, // MZ2_MAKRON_BLASTER_10 111 - { -7, 35, 59.5 }, + {"MZ2_MAKRON_BLASTER", {-7, 35, 59.5}}, // MZ2_MAKRON_BLASTER_11 112 - { -2.1, 29, 59.5 }, + {"MZ2_MAKRON_BLASTER", {-2.1, 29, 59.5}}, // MZ2_MAKRON_BLASTER_12 113 - { 3.9, 17.3, 59.5 }, + {"MZ2_MAKRON_BLASTER", {3.9, 17.3, 59.5}}, // MZ2_MAKRON_BLASTER_13 114 - { 6.1, 5.8, 59.5 }, + {"MZ2_MAKRON_BLASTER", {6.1, 5.8, 59.5}}, // MZ2_MAKRON_BLASTER_14 115 - { 5.9, -4.4, 59.5 }, + {"MZ2_MAKRON_BLASTER", {5.9, -4.4, 59.5}}, // MZ2_MAKRON_BLASTER_15 116 - { 4.2, -14.1, 59.5, }, + {"MZ2_MAKRON_BLASTER", {4.2, -14.1, 59.5, }}, // MZ2_MAKRON_BLASTER_16 117 - { 2.4, -18.8, 59.5 }, + {"MZ2_MAKRON_BLASTER", {2.4, -18.8, 59.5}}, // MZ2_MAKRON_BLASTER_17 118 - { -1.8, -25.5, 59.5 }, + {"MZ2_MAKRON_BLASTER", {-1.8, -25.5, 59.5}}, // MZ2_MAKRON_RAILGUN_1 119 - { -17.3, 7.8, 72.4 }, + {"MZ2_MAKRON_RAILGUN", {-17.3, 7.8, 72.4}}, // MZ2_JORG_MACHINEGUN_L1 120 - { 78.5, -47.1, 96, }, + {"MZ2_JORG_MACHINEGUN_L", {78.5, -47.1, 96, }}, // MZ2_JORG_MACHINEGUN_L2 121 - { 78.5, -47.1, 96, }, + {"MZ2_JORG_MACHINEGUN_L", {78.5, -47.1, 96, }}, // MZ2_JORG_MACHINEGUN_L3 122 - { 78.5, -47.1, 96, }, + {"MZ2_JORG_MACHINEGUN_L", {78.5, -47.1, 96, }}, // MZ2_JORG_MACHINEGUN_L4 123 - { 78.5, -47.1, 96, }, + {"MZ2_JORG_MACHINEGUN_L", {78.5, -47.1, 96, }}, // MZ2_JORG_MACHINEGUN_L5 124 - { 78.5, -47.1, 96, }, + {"MZ2_JORG_MACHINEGUN_L", {78.5, -47.1, 96, }}, // MZ2_JORG_MACHINEGUN_L6 125 - { 78.5, -47.1, 96, }, + {"MZ2_JORG_MACHINEGUN_L", {78.5, -47.1, 96, }}, // MZ2_JORG_MACHINEGUN_R1 126 - { 78.5, 46.7, 96, }, + {"MZ2_JORG_MACHINEGUN_R", {78.5, 46.7, 96, }}, // MZ2_JORG_MACHINEGUN_R2 127 - { 78.5, 46.7, 96, }, + {"MZ2_JORG_MACHINEGUN_R", {78.5, 46.7, 96, }}, // MZ2_JORG_MACHINEGUN_R3 128 - { 78.5, 46.7, 96, }, + {"MZ2_JORG_MACHINEGUN_R", {78.5, 46.7, 96, }}, // MZ2_JORG_MACHINEGUN_R4 129 - { 78.5, 46.7, 96, }, + {"MZ2_JORG_MACHINEGUN_R", {78.5, 46.7, 96, }}, // MZ2_JORG_MACHINEGUN_R5 130 - { 78.5, 46.7, 96, }, + {"MZ2_JORG_MACHINEGUN_R", {78.5, 46.7, 96, }}, // MZ2_JORG_MACHINEGUN_R6 131 - { 78.5, 46.7, 96, }, + {"MZ2_JORG_MACHINEGUN_R", {78.5, 46.7, 96, }}, // MZ2_JORG_BFG_1 132 - { 6.3, -9, 111.2 }, + {"MZ2_JORG_BFG_1", {6.3, -9, 111.2}}, // MZ2_BOSS2_MACHINEGUN_R1 73 - { 32, 40, 70 }, + {"MZ2_BOSS2_MACHINEGUN_R", {32, 40, 70}}, // MZ2_BOSS2_MACHINEGUN_R2 74 - { 32, 40, 70 }, + {"MZ2_BOSS2_MACHINEGUN_R", {32, 40, 70}}, // MZ2_BOSS2_MACHINEGUN_R3 75 - { 32, 40, 70 }, + {"MZ2_BOSS2_MACHINEGUN_R", {32, 40, 70}}, // MZ2_BOSS2_MACHINEGUN_R4 76 - { 32, 40, 70 }, + {"MZ2_BOSS2_MACHINEGUN_R", {32, 40, 70}}, // MZ2_BOSS2_MACHINEGUN_R5 77 - { 32, 40, 70 }, + {"MZ2_BOSS2_MACHINEGUN_R", {32, 40, 70}}, // --- End Xian Shit --- @@ -331,157 +332,154 @@ vec3_t monster_flash_offset [] = // note that the above really ends at 137 // carrier machineguns // MZ2_CARRIER_MACHINEGUN_L1 - { 56, -32, 32 }, + {"MZ2_CARRIER_MACHINEGUN_L", {56, -32, 32}}, // MZ2_CARRIER_MACHINEGUN_R1 - { 56, 32, 32 }, + {"MZ2_CARRIER_MACHINEGUN_R", {56, 32, 32}}, // MZ2_CARRIER_GRENADE - { 42, 24, 50 }, + {"MZ2_CARRIER_GRENADE", {42, 24, 50}}, // MZ2_TURRET_MACHINEGUN 141 - { 16, 0, 0 }, + {"MZ2_TURRET_MACHINEGUN", {16, 0, 0}}, // MZ2_TURRET_ROCKET 142 - { 16, 0, 0 }, + {"MZ2_TURRET_ROCKET", {16, 0, 0}}, // MZ2_TURRET_BLASTER 143 - { 16, 0, 0 }, + {"MZ2_TURRET_BLASTER", {16, 0, 0}}, // MZ2_STALKER_BLASTER 144 - { 24, 0, 6 }, + {"MZ2_STALKER_BLASTER", {24, 0, 6}}, // MZ2_DAEDALUS_BLASTER 145 - { 32.5, -0.8, 10.0 }, + {"MZ2_DAEDALUS_BLASTER", {32.5, -0.8, 10.0}}, // MZ2_MEDIC_BLASTER_2 146 - { 12.1, 5.4, 16.5 }, + {"MZ2_MEDIC_BLASTER", {12.1, 5.4, 16.5}}, // MZ2_CARRIER_RAILGUN 147 - { 32, 0, 6, }, + {"MZ2_CARRIER_RAILGUN", {32, 0, 6, }}, // MZ2_WIDOW_DISRUPTOR 148 - { 57.72, 14.50, 88.81 }, + {"MZ2_WIDOW_DISRUPTOR", {57.72, 14.50, 88.81}}, // MZ2_WIDOW_BLASTER 149 - { 56, 32, 32 }, + {"MZ2_WIDOW_BLASTER", {56, 32, 32}}, // MZ2_WIDOW_RAIL 150 - { 62, -20, 84, }, + {"MZ2_WIDOW_RAIL", {62, -20, 84, }}, // MZ2_WIDOW_PLASMABEAM 151 // PMM - not used! - { 32, 0, 6, }, + {"MZ2_WIDOW_PLASMABEAM", {32, 0, 6, }}, // MZ2_CARRIER_MACHINEGUN_L2 152 - { 61, -32, 12 }, + {"MZ2_CARRIER_MACHINEGUN_L", {61, -32, 12}}, // MZ2_CARRIER_MACHINEGUN_R2 153 - { 61, 32, 12 }, + {"MZ2_CARRIER_MACHINEGUN_R", {61, 32, 12}}, // MZ2_WIDOW_RAIL_LEFT 154 - { 17, -62, 91, }, + {"MZ2_WIDOW_RAIL_LEFT", {17, -62, 91, }}, // MZ2_WIDOW_RAIL_RIGHT 155 - { 68, 12, 86, }, + {"MZ2_WIDOW_RAIL_RIGHT", {68, 12, 86, }}, // MZ2_WIDOW_BLASTER_SWEEP1 156 pmm - the sweeps need to be in sequential order - { 47.5, 56, 89 }, + {"MZ2_WIDOW_BLASTER_SWEEP", {47.5, 56, 89}}, // MZ2_WIDOW_BLASTER_SWEEP2 157 - { 54, 52, 91 }, + {"MZ2_WIDOW_BLASTER_SWEEP", {54, 52, 91}}, // MZ2_WIDOW_BLASTER_SWEEP3 158 - { 58, 40, 91 }, + {"MZ2_WIDOW_BLASTER_SWEEP", {58, 40, 91}}, // MZ2_WIDOW_BLASTER_SWEEP4 159 - { 68, 30, 88 }, + {"MZ2_WIDOW_BLASTER_SWEEP", {68, 30, 88}}, // MZ2_WIDOW_BLASTER_SWEEP5 160 - { 74, 20, 88 }, + {"MZ2_WIDOW_BLASTER_SWEEP", {74, 20, 88}}, // MZ2_WIDOW_BLASTER_SWEEP6 161 - { 73, 11, 87 }, + {"MZ2_WIDOW_BLASTER_SWEEP", {73, 11, 87}}, // MZ2_WIDOW_BLASTER_SWEEP7 162 - { 73, 3, 87 }, + {"MZ2_WIDOW_BLASTER_SWEEP", {73, 3, 87}}, // MZ2_WIDOW_BLASTER_SWEEP8 163 - { 70, -12, 87 }, + {"MZ2_WIDOW_BLASTER_SWEEP", {70, -12, 87}}, // MZ2_WIDOW_BLASTER_SWEEP9 164 - { 67, -20, 90 }, + {"MZ2_WIDOW_BLASTER_SWEEP", {67, -20, 90}}, // MZ2_WIDOW_BLASTER_100 165 - { -20, 76, 90 }, + {"MZ2_WIDOW_BLASTER", {-20, 76, 90}}, // MZ2_WIDOW_BLASTER_90 166 - { -8, 74, 90 }, + {"MZ2_WIDOW_BLASTER", {-8, 74, 90}}, // MZ2_WIDOW_BLASTER_80 167 - { 0, 72, 90 }, + {"MZ2_WIDOW_BLASTER", {0, 72, 90}}, // MZ2_WIDOW_BLASTER_70 168 d06 - { 10, 71, 89 }, + {"MZ2_WIDOW_BLASTER", {10, 71, 89}}, // MZ2_WIDOW_BLASTER_60 169 d07 - { 23, 70, 87 }, + {"MZ2_WIDOW_BLASTER", {23, 70, 87}}, // MZ2_WIDOW_BLASTER_50 170 d08 - { 32, 64, 85 }, + {"MZ2_WIDOW_BLASTER", {32, 64, 85}}, // MZ2_WIDOW_BLASTER_40 171 - { 40, 58, 84 }, + {"MZ2_WIDOW_BLASTER", {40, 58, 84}}, // MZ2_WIDOW_BLASTER_30 172 d10 - { 48, 50, 83 }, + {"MZ2_WIDOW_BLASTER", {48, 50, 83}}, // MZ2_WIDOW_BLASTER_20 173 - { 54, 42, 82 }, + {"MZ2_WIDOW_BLASTER", {54, 42, 82}}, // MZ2_WIDOW_BLASTER_10 174 d12 - { 56, 34, 82 }, + {"MZ2_WIDOW_BLASTER", {56, 34, 82}}, // MZ2_WIDOW_BLASTER_0 175 - { 58, 26, 82 }, + {"MZ2_WIDOW_BLASTER", {58, 26, 82}}, // MZ2_WIDOW_BLASTER_10L 176 d14 - { 60, 16, 82 }, + {"MZ2_WIDOW_BLASTER", {60, 16, 82}}, // MZ2_WIDOW_BLASTER_20L 177 - { 59, 6, 81 }, + {"MZ2_WIDOW_BLASTER", {59, 6, 81}}, // MZ2_WIDOW_BLASTER_30L 178 d16 - { 58, -2, 80 }, + {"MZ2_WIDOW_BLASTER", {58, -2, 80}}, // MZ2_WIDOW_BLASTER_40L 179 - { 57, -10, 79 }, + {"MZ2_WIDOW_BLASTER", {57, -10, 79}}, // MZ2_WIDOW_BLASTER_50L 180 d18 - { 54, -18, 78 }, + {"MZ2_WIDOW_BLASTER", {54, -18, 78}}, // MZ2_WIDOW_BLASTER_60L 181 - { 42, -32, 80 }, + {"MZ2_WIDOW_BLASTER", {42, -32, 80}}, // MZ2_WIDOW_BLASTER_70L 182 d20 - { 36, -40, 78 }, + {"MZ2_WIDOW_BLASTER", {36, -40, 78}}, // MZ2_WIDOW_RUN_1 183 - { 68.4, 10.88, 82.08 }, + {"MZ2_WIDOW_RUN", {68.4, 10.88, 82.08}}, // MZ2_WIDOW_RUN_2 184 - { 68.51, 8.64, 85.14 }, + {"MZ2_WIDOW_RUN_2", {68.51, 8.64, 85.14}}, // MZ2_WIDOW_RUN_3 185 - { 68.66, 6.38, 88.78 }, + {"MZ2_WIDOW_RUN", {68.66, 6.38, 88.78}}, // MZ2_WIDOW_RUN_4 186 - { 68.73, 5.1, 84.47 }, + {"MZ2_WIDOW_RUN", {68.73, 5.1, 84.47}}, // MZ2_WIDOW_RUN_5 187 - { 68.82, 4.79, 80.52 }, + {"MZ2_WIDOW_RUN", {68.82, 4.79, 80.52}}, // MZ2_WIDOW_RUN_6 188 - { 68.77, 6.11, 85.37 }, + {"MZ2_WIDOW_RUN", {68.77, 6.11, 85.37}}, // MZ2_WIDOW_RUN_7 189 - { 68.67, 7.99, 90.24 }, + {"MZ2_WIDOW_RUN", {68.67, 7.99, 90.24}}, // MZ2_WIDOW_RUN_8 190 - { 68.55, 9.54, 87.36 }, + {"MZ2_WIDOW_RUN", {68.55, 9.54, 87.36}}, // MZ2_CARRIER_ROCKET_1 191 - { 0, 0, -5 }, + {"MZ2_CARRIER_ROCKET", {0, 0, -5}}, // MZ2_CARRIER_ROCKET_2 192 - { 0, 0, -5 }, + {"MZ2_CARRIER_ROCKET", {0, 0, -5}}, // MZ2_CARRIER_ROCKET_3 193 - { 0, 0, -5 }, + {"MZ2_CARRIER_ROCKET", {0, 0, -5}}, // MZ2_CARRIER_ROCKET_4 194 - { 0, 0, -5 }, + {"MZ2_CARRIER_ROCKET", {0, 0, -5}}, // MZ2_WIDOW2_BEAMER_1 195 // 72.13, -17.63, 93.77, - { 69.00, -17.63, 93.77 }, + {"MZ2_WIDOW2_BEAMER", {69.00, -17.63, 93.77}}, // MZ2_WIDOW2_BEAMER_2 196 // 71.46, -17.08, 89.82, - { 69.00, -17.08, 89.82 }, + {"MZ2_WIDOW2_BEAMER", {69.00, -17.08, 89.82}}, // MZ2_WIDOW2_BEAMER_3 197 // 71.47, -18.40, 90.70, - { 69.00, -18.40, 90.70 }, + {"MZ2_WIDOW2_BEAMER", {69.00, -18.40, 90.70}}, // MZ2_WIDOW2_BEAMER_4 198 // 71.96, -18.34, 94.32, - { 69.00, -18.34, 94.32 }, + {"MZ2_WIDOW2_BEAMER", {69.00, -18.34, 94.32}}, // MZ2_WIDOW2_BEAMER_5 199 // 72.25, -18.30, 97.98, - { 69.00, -18.30, 97.98 }, + {"MZ2_WIDOW2_BEAMER", {69.00, -18.30, 97.98}}, // MZ2_WIDOW2_BEAM_SWEEP_1 200 - { 45.04, -59.02, 92.24 }, + {"MZ2_WIDOW2_BEAM_SWEEP", {45.04, -59.02, 92.24}}, // MZ2_WIDOW2_BEAM_SWEEP_2 201 - { 50.68, -54.70, 91.96 }, + {"MZ2_WIDOW2_BEAM_SWEEP", {50.68, -54.70, 91.96}}, // MZ2_WIDOW2_BEAM_SWEEP_3 202 - { 56.57, -47.72, 91.65 }, + {"MZ2_WIDOW2_BEAM_SWEEP", {56.57, -47.72, 91.65}}, // MZ2_WIDOW2_BEAM_SWEEP_4 203 - { 61.75, -38.75, 91.38 }, + {"MZ2_WIDOW2_BEAM_SWEEP", {61.75, -38.75, 91.38}}, // MZ2_WIDOW2_BEAM_SWEEP_5 204 - { 65.55, -28.76, 91.24 }, + {"MZ2_WIDOW2_BEAM_SWEEP", {65.55, -28.76, 91.24}}, // MZ2_WIDOW2_BEAM_SWEEP_6 205 - { 67.79, -18.90, 91.22 }, + {"MZ2_WIDOW2_BEAM_SWEEP", {67.79, -18.90, 91.22}}, // MZ2_WIDOW2_BEAM_SWEEP_7 206 - { 68.60, -9.52, 91.23 }, + {"MZ2_WIDOW2_BEAM_SWEEP", {68.60, -9.52, 91.23}}, // MZ2_WIDOW2_BEAM_SWEEP_8 207 - { 68.08, 0.18, 91.32 }, + {"MZ2_WIDOW2_BEAM_SWEEP", {68.08, 0.18, 91.32}}, // MZ2_WIDOW2_BEAM_SWEEP_9 208 - { 66.14, 9.79, 91.44 }, + {"MZ2_WIDOW2_BEAM_SWEEP", {66.14, 9.79, 91.44}}, // MZ2_WIDOW2_BEAM_SWEEP_10 209 - { 62.77, 18.91, 91.65 }, + {"MZ2_WIDOW2_BEAM_SWEEP", {62.77, 18.91, 91.65}}, // MZ2_WIDOW2_BEAM_SWEEP_11 210 - { 58.29, 27.11, 92.00 }, - -// end of table - { 0.0, 0.0, 0.0 }, + {"MZ2_WIDOW2_BEAM_SWEEP", {58.29, 27.11, 92.00}} }; diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index 197063c90..842be0262 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -210,6 +210,8 @@ void R2D_Init(void) draw_backtile->defaulttextures.base = R_LoadHiResTexture("gfx/backtile", NULL, IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP); if (!TEXVALID(draw_backtile->defaulttextures.base)) draw_backtile->defaulttextures.base = R_LoadHiResTexture("gfx/menu/backtile", NULL, IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP); + if (!TEXVALID(draw_backtile->defaulttextures.base)) + draw_backtile->defaulttextures.base = R_LoadHiResTexture("pics/backtile", NULL, IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP); shader_draw_fill = R_RegisterShader("fill_opaque", SUF_NONE, "{\n" diff --git a/engine/client/r_part.c b/engine/client/r_part.c index 6eb838797..da7508878 100644 --- a/engine/client/r_part.c +++ b/engine/client/r_part.c @@ -195,22 +195,6 @@ void P_Shutdown(void) pe = NULL; } -#ifdef Q2BSPS -qboolean Q2TraceLineN (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal) -{ - vec3_t nul = {0,0,0}; - trace_t trace = CM_BoxTrace(pmove.physents[0].model, start, end, nul, nul, MASK_WORLDSOLID); - - if (trace.fraction < 1) - { - VectorCopy (trace.plane.normal, normal); - VectorCopy (trace.endpos, impact); - return true; - } - return false; -} -#endif - qboolean TraceLineN (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal) { trace_t trace; diff --git a/engine/client/r_partset.c b/engine/client/r_partset.c index c7f33df8e..8f0680488 100644 --- a/engine/client/r_partset.c +++ b/engine/client/r_partset.c @@ -1491,6 +1491,34 @@ char *particle_set_high = "assoc gunshotsmoke\n" "}\n" +"r_part te_superspike\n" +"{\n" +"type sparkfan\n" +"count 20\n" +"scale 1\n" +"scalefactor 1\n" +"alpha 0.5\n" +"die 0.2\n" +"rgb 255 128 0\n" +"blend add\n" +"spawnmode ball\n" +"spawnorg 12\n" +"spawnvel 300\n" +"}\n" +"r_part +te_superspike\n" +"{\n" +"texture \"particles/fteparticlefont.tga\"\n" +"tcoords 1 97 95 191 256\n" +"count 1\n" +"scale 1\n" +"scalefactor 1\n" +"scaledelta 190\n" +"die 0.1\n" +"alpha 0.6\n" +"rgb 255 128 0\n" +"blend add\n" +"assoc gunshotsmoke\n" +"}\n" //////////////////////////////////////////////// //explosion @@ -1559,9 +1587,10 @@ char *particle_set_high = //hide lights in explosions. //r_explosionlight 0 -//hide the explosion sprite in nq+qw - WARNING: some mods use this sprite as a flame thrower. +//hide the explosion sprite in qw "cl_expsprite 0\n" -"r_effect \"progs/s_explod.spr\" hidden 1\n" +//hide it in nq - WARNING: some mods use this sprite as a flame thrower. +//r_effect "progs/s_explod.spr" hidden 1 ////////////////////////////////////////// //r_part te_tarexplosion @@ -1574,6 +1603,7 @@ char *particle_set_high = //} ////////////////////////////////////////// +//FIXME: what if we don't have glsl support? "r_part te_teleport\n" "{\n" "scale 250\n" @@ -1651,6 +1681,22 @@ char *particle_set_high = "lightrgb 0.75 0.37 0.18\n" "}\n" +"r_part te_knightspike\n" +"{\n" +"type sparkfan\n" +"count 200\n" +"scale 3\n" +"scalefactor 1\n" +"alpha 0.5\n" +"die 0.5\n" +"rgb 192 96 48\n" +"blend add\n" +"spawnmode ball\n" +"spawnorg 12\n" +"spawnvel 100\n" +"stretchfactor 10\n" +"}\n" + ///////////////////////////////////////// //vore missiles "r_part tr_vorespike\n" @@ -1705,13 +1751,13 @@ char *particle_set_high = "r_trail \"progs/laser.mdl\" tr_enforcerlaser\n" ///////////////////////////////////////// -//scrag missiles. just use the default trail cos we're lazy +//scrag missiles. "r_part tr_wizspike\n" "{\n" "texture \"particles/fteparticlefont.tga\"\n" "tcoords 1 97 95 191 256\n" "scale 15\n" -"step 1\n" +"step 4\n" "alpha 0.6\n" "die 0.2\n" "rgb 25 200 25\n" @@ -1722,12 +1768,54 @@ char *particle_set_high = "spawnmode spiral\n" "spawnvel 25\n" "blend add\n" -"lighttime 0\n" +"lighttime 2\n" +"lightradiusfade 75\n" "lightshadows 0\n" "lightradius 150\n" "lightrgb 0.1 0.7 0.1\n" "}\n" +"r_part tr_wizspike2\n" +"{\n" +"texture \"particles/fteparticlefont.tga\"\n" +"tcoords 1 97 95 191 256\n" +"scale 4\n" +"step 1\n" +"alpha 0.6\n" +"die 0.2\n" +"rgb 25 200 25\n" +"veladd 64\n" +"randomvel 64\n" +"friction 4\n" +"scalefactor 0.825\n" +"spawnmode spiral\n" +"spawnvel 25\n" +"blend add\n" +"}\n" +//scrag impact +"r_part te_wizspike\n" +"{\n" +"texture \"particles/fteparticlefont.tga\"\n" +"tcoords 1 97 95 191 256\n" +"scale 15\n" +"alpha 0.6\n" +"rgb 25 200 25\n" +"friction 0\n" +"scalefactor 0.825\n" +"blend add\n" +"count 5\n" +"veladd -256\n" +"randomvel 256\n" +"die 1\n" +"diesubrand 0.5\n" +"gravity 800\n" +"emit tr_wizspike2\n" +"emitinterval -1\n" +"bounce 1.5\n" +"}\n" + +///////////////////////////////////////// +//shambler stuff "r_part shambercharging\n" "{\n" "spawnmode ball\n" @@ -1753,7 +1841,8 @@ char *particle_set_high = "}\n" "r_effect progs/s_light.mdl shambercharging 0\n" - +///////////////////////////////////////// +//blood effects "r_part te_blood\n" "{\n" "texture fte_bloodparticle\n" @@ -3118,6 +3207,172 @@ char *particle_set_h2part = +////////////////////////////////////////////////////// + + +char *particle_set_q2part = + +"r_part pe_default\n" +"{\n" +"texture \"classicparticle\"\n" +"tcoords 0 0 16 16 32\n" +"count 1\n" +"scale 1\n" +"alpha 1\n" +"die 0.3 0.8\n" +"randomvel 20\n" +"orgadd 0 31\n" +"spawnorg 4\n" +"gravity 40\n" +"scalefactor 0.8\n" +"}\n" + + +"r_part q2_smoke\n" +"{\n" +"count 0 0 1\n" +"model \"models/objects/smoke/tris.md2\" framestart=0 frameend=4 framerate=10 alpha=1\n" +"}\n" +"r_part q2_smokeandflash\n" +"{\n" +"count 0 0 1\n" +"model \"models/objects/flash/tris.md2\" framestart=0 frameend=2 framerate=10 alpha=-1 fullbright\n" +"assoc q2_smoke\n" +"}\n" + +"r_part teq2_gunshot /*machinegun*/\n" +"{\n" +"texture \"classicparticle\"\n" +"tcoords 0 0 16 16 32\n" +"count 40\n" +"scale 1\n" +"alpha 1\n" +"die 0.3 0.8\n" +"randomvel 20\n" +"orgadd 0 31\n" +"spawnorg 4\n" +"gravity 40\n" +"scalefactor 0.8\n" +"colorindex 0 7\n" +/*smoke puff models*/ +"assoc q2_smokeandflash\n" +/*low chance of various sounds*/ +"sound world/ric1.wav 1 1 0 0 1\n" +"sound world/ric2.wav 1 1 0 0 1\n" +"sound world/ric3.wav 1 1 0 0 1\n" +"sound \"\" 1 1 0 0 12\n" +"}\n" + +"r_part teq2_shotgun /*shotgun... duh*/\n" +"{\n" +"texture \"classicparticle\"\n" +"tcoords 0 0 16 16 32\n" +"count 20\n" +"scale 1\n" +"alpha 1\n" +"die 0.3 0.8\n" +"randomvel 20\n" +"orgadd 0 31\n" +"spawnorg 4\n" +"gravity 40\n" +"scalefactor 0.8\n" +"colorindex 0 7\n" +/*smoke puff models*/ +"assoc q2_smokeandflash\n" +"}\n" + +"r_part teq2_blood\n" +"{\n" +"texture \"classicparticle\"\n" +"tcoords 0 0 16 16 32\n" +"count 60\n" +"scale 1\n" +"alpha 1\n" +"die 0.3 0.8\n" +"randomvel 20\n" +"orgadd 0 31\n" +"spawnorg 4\n" +"gravity 40\n" +"scalefactor 0.8\n" +"colorindex 232 7\n" +"}\n" + +"r_part q2_blasterpuff\n" +"{\n" +"count 0 0 1\n" +"model \"models/objects/explode/tris.md2\" framestart=0 frameend=4 framerate=10 alpha=1 orient additive fullbright noshadow\n" +"}\n" +"r_part teq2_blaster\n" +"{\n" +"texture \"classicparticle\"\n" +"tcoords 0 0 16 16 32\n" +"count 60\n" +"scale 1\n" +"alpha 1\n" +"die 0.3 0.8\n" +"randomvel 40\n" +"orgadd 0 15\n" +"veladd 30\n" +"spawnorg 4\n" +"gravity 40\n" +"scalefactor 0.8\n" +"colorindex 0xe0 7\n" +"assoc q2_blasterpuff /*the model*/\n" +"lightradius 150\n" +"lightradiusfade 400\n" +"lightrgb 1 1 0\n" +"lightshadows 0\n" +"sound \"weapons/lashit.wav\" 1 1 0 0\n" +"}\n" +"r_part TR_BLASTERTRAIL\n" +"{\n" +"texture \"classicparticle\"\n" +"tcoords 0 0 16 16 32\n" +"scale 0.5\n" +"alpha 1\n" +"scalefactor 0.8\n" +"step 5\n" +"spawnorg 1\n" +"randomvel 5\n" +"die 0.3 0.5\n" +"colorindex 0xe0\n" +"}\n" + +"r_part TR_RAILTRAIL\n" +"{\n" +/*blue spiral*/ +"texture \"classicparticle\"\n" +"tcoords 0 0 16 16 32\n" +"scale 0.5\n" +"alpha 1\n" +"scalefactor 0.8\n" +"step 1\n" +"spawnmode spiral 64\n" +"spawnorg 3\n" +"spawnvel 6\n" +"die 1 1.2\n" +"colorindex 116 7\n" + +"sound \"weapons/railgf1a.wav\" 1 1 0 0\n" +"}\n" +"r_part +TR_RAILTRAIL\n" +"{\n" +/*grey filler*/ +"texture \"classicparticle\"\n" +"tcoords 0 0 16 16 32\n" +"scale 0.5\n" +"alpha 1\n" +"scalefactor 0.8\n" +"step 0.75\n" +"spawnorg 3\n" +"spawnvel 3\n" +"die 0.6 0.8\n" +"colorindex 0 15\n" +"}\n" +; + + + ////////////////////////////////////////////////////// diff --git a/engine/client/r_partset.h b/engine/client/r_partset.h index cfe0f8d75..098ef26d4 100644 --- a/engine/client/r_partset.h +++ b/engine/client/r_partset.h @@ -4,5 +4,6 @@ extern char *particle_set_highfps; extern char *particle_set_high; extern char *particle_set_minimal; extern char *particle_set_h2part; +extern char *particle_set_q2part; extern char *particle_set_tsshaft; -#define R_PARTSET_BUILTINS {"spikeset", &particle_set_spikeset},{"faithful", &particle_set_faithful},{"highfps", &particle_set_highfps},{"high", &particle_set_high},{"minimal", &particle_set_minimal},{"h2part", &particle_set_h2part},{"tsshaft", &particle_set_tsshaft}, +#define R_PARTSET_BUILTINS {"spikeset", &particle_set_spikeset},{"faithful", &particle_set_faithful},{"highfps", &particle_set_highfps},{"high", &particle_set_high},{"minimal", &particle_set_minimal},{"h2part", &particle_set_h2part},{"q2part", &particle_set_q2part},{"tsshaft", &particle_set_tsshaft}, diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 8a5bf04c9..cd55e5984 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -209,7 +209,7 @@ void Surf_AddStain(vec3_t org, float red, float green, float blue, float radius) parms[6] = blue; - cl.worldmodel->funcs.StainNode(cl.worldmodel->nodes+cl.worldmodel->hulls[0].firstclipnode, parms); + cl.worldmodel->funcs.StainNode(cl.worldmodel->rootnode, parms); //now stain bsp models other than world. @@ -233,7 +233,7 @@ void Surf_AddStain(vec3_t org, float red, float green, float blue, float radius) } - pe->model->funcs.StainNode(pe->model->nodes+pe->model->hulls[0].firstclipnode, parms); + pe->model->funcs.StainNode(pe->model->rootnode, parms); } } } @@ -2173,8 +2173,7 @@ void Surf_GenBrushBatches(batch_t **batches, entity_t *ent) if (!(cl_dlights[k].flags & LFLAG_LIGHTMAP)) continue; - model->funcs.MarkLights (&cl_dlights[k], 1<nodes + model->hulls[0].firstclipnode); + model->funcs.MarkLights (&cl_dlights[k], 1<rootnode); } } diff --git a/engine/client/renderer.c b/engine/client/renderer.c index cc9109db9..a0a83a1cb 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -2475,7 +2475,7 @@ void R_InitParticleTexture (void) } } - particlecqtexture = R_LoadTexture32("", 32, 32, data, IF_NOMIPMAP|IF_NOPICMIP); + particlecqtexture = R_LoadTexture32("classicparticle", 32, 32, data, IF_NOMIPMAP|IF_NOPICMIP); diff --git a/engine/client/sbar.c b/engine/client/sbar.c index 9c6dd6e4c..b929d4ce4 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -388,7 +388,6 @@ void Sbar_ExecuteLayoutString (char *s) value = atoi(com_token); if (value >= MAX_CLIENTS || value < 0) Host_EndGame ("client >= MAX_CLIENTS"); -// ci = &cl.clientinfo[value]; s = COM_Parse (s); score = atoi(com_token); @@ -405,9 +404,10 @@ void Sbar_ExecuteLayoutString (char *s) Draw_FunString (x+32, y+16, va("Ping: %i", ping)); Draw_FunString (x+32, y+24, va("Time: %i", time)); -// if (!ci->icon) -// ci = &cl.baseclientinfo; -// Draw_Pic (x, y, R2D_SafeCachePic(ci->iconname)); + p = R2D_SafeCachePic(va("players/%s_i.pcx", cl.players[value].skin->name)); + if (!p) //display a default if the icon couldn't be found. + p = R2D_SafeCachePic(va("players/male/grunt_i.pcx", cl.players[value].skin->name)); + R2D_ScalePic (x, y, 32, 32, p); continue; } @@ -427,7 +427,6 @@ void Sbar_ExecuteLayoutString (char *s) value = atoi(com_token); if (value >= MAX_CLIENTS || value < 0) Host_EndGame ("client >= MAX_CLIENTS"); -// ci = &cl.clientinfo[value]; s = COM_Parse (s); score = atoi(com_token); @@ -437,7 +436,7 @@ void Sbar_ExecuteLayoutString (char *s) if (ping > 999) ping = 999; - sprintf(block, "%3d %3d %-12.12s", score, ping, "Player"/*ci->name*/); + sprintf(block, "%3d %3d %-12.12s", score, ping, cl.players[value].name); // if (value == cl.playernum) // Draw_Alt_String (x, y, block); diff --git a/engine/client/skin.c b/engine/client/skin.c index 4fa1c41ea..610f74c1e 100644 --- a/engine/client/skin.c +++ b/engine/client/skin.c @@ -121,36 +121,21 @@ void Skin_Find (player_info_t *sc) { skin_t *skin; int i; - char name[128], *s, *mn; + char name[128], *s; model_t *model; - mn = Info_ValueForKey (sc->userinfo, "model"); - while((s = strchr(mn, '/'))) - *mn = '\0'; - if (allskins[0]) s = allskins; else s = Info_ValueForKey (sc->userinfo, "skin"); - if (strstr (mn, "..") || *mn == '.') - mn = ""; - if (!*s) s = baseskin.string; if (!*s) s = "default"; - if (*mn) - { - mn = va("%s/%s", mn, s); - COM_StripExtension (mn, name, sizeof(name)); - } - else - { - s = Skin_FindName(sc); - COM_StripExtension (s, name, sizeof(name)); - } + s = Skin_FindName(sc); + COM_StripExtension (s, name, sizeof(name)); s = strchr(name, '/'); if (s) diff --git a/engine/client/textedit.c b/engine/client/textedit.c index ca081c19c..41d213906 100644 --- a/engine/client/textedit.c +++ b/engine/client/textedit.c @@ -31,7 +31,7 @@ F11 will step through. static cvar_t editstripcr = CVARD("edit_stripcr", "1", "remove \\r from eols (on load)"); static cvar_t editaddcr = CVARD("edit_addcr", editaddcr_default, "make sure that each line ends with a \\r (on save)"); static cvar_t edittabspacing = CVARD("edit_tabsize", "4", "How wide tab alignment is"); -cvar_t debugger = CVARD("debugger", debugger_default, "When enabled, QC errors and debug events will enable step-by-step tracing."); +cvar_t pr_debugger = CVARAD("pr_debugger", debugger_default, "debugger", "When enabled, QC errors and debug events will enable step-by-step tracing."); extern cvar_t pr_sourcedir; static pubprogfuncs_t *editprogfuncs; @@ -1199,7 +1199,7 @@ void Editor_Draw(void) int QCLibEditor(pubprogfuncs_t *prfncs, char *filename, int line, int statement, int nump, char **parms) { char *f1, *f2; - if (editormodal || (line < 0 && !statement) || !debugger.ival) + if (editormodal || (line < 0 && !statement) || !pr_debugger.ival) return line; //whoops if (qrenderer == QR_NONE) @@ -1360,6 +1360,6 @@ void Editor_Init(void) Cvar_Register(&editstripcr, "Text editor"); Cvar_Register(&editaddcr, "Text editor"); Cvar_Register(&edittabspacing, "Text editor"); - Cvar_Register(&debugger, "Text editor"); + Cvar_Register(&pr_debugger, "Text editor"); } #endif diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 50368c30a..ebb7a95de 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -171,6 +171,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #undef USE_MADLIB //no internal mp3 playing #define NOMEDIA //NO playing of avis/cins/roqs + #define SPRMODELS //quake1 sprite models #define MD3MODELS //we DO want to use quake3 alias models. This might be a minimal build, but we still want this. #define PLUGINS @@ -194,6 +195,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define SIDEVIEWS 4 //enable secondary/reverse views. + #define DSPMODELS //doom sprites (only needs DOOMWADS to generate the right wad file names) + #define SPRMODELS //quake1 sprite models #define SP2MODELS //quake2 sprite models #define MD2MODELS //quake2 alias models #define MD3MODELS //quake3 alias models @@ -378,6 +381,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #undef WEBCLIENT #undef TEXTEDITOR #undef RUNTIMELIGHTING + #undef DSPMODELS + #undef SPRMODELS + #undef SP2MODELS #undef PSET_SCRIPT #undef PSET_CLASSIC diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index a5465daa4..77eb6407c 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -1876,28 +1876,29 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in -/* static float PlaneNearest(vec3_t normal, vec3_t mins, vec3_t maxs) { float result; - return 128; -#if 1 +#if 0 result = fabs(normal[0] * maxs[0]); result += fabs(normal[1] * maxs[1]); result += fabs(normal[2] * maxs[2]); +#elif 0 + result = normal[0] * ((normal[0] > 0)?-16:16); + result += normal[1] * ((normal[1] > 0)?-16:16); + result += normal[2] * ((normal[2] > 0)?-24:32); #else - result = normal[0] * ((normal[0] < 0)?mins[0]:maxs[0]); - result += normal[1] * ((normal[1] < 0)?mins[1]:maxs[1]); - result += normal[2] * ((normal[2] < 0)?mins[2]:maxs[2]); + result = normal[0] * ((normal[0] > 0)?mins[0]:maxs[0]); + result += normal[1] * ((normal[1] > 0)?mins[1]:maxs[1]); + result += normal[2] * ((normal[2] > 0)?mins[2]:maxs[2]); #endif return result; } -*/ -static qboolean Mod_Trace_Trisoup(vecV_t *posedata, index_t *indexes, int numindexes, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, trace_t *trace) +qboolean Mod_Trace_Trisoup(vecV_t *posedata, index_t *indexes, int numindexes, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, trace_t *trace) { qboolean impacted = false; - int i; + int i, j; float *p1, *p2, *p3; vec3_t edge1, edge2, edge3; @@ -1906,10 +1907,10 @@ static qboolean Mod_Trace_Trisoup(vecV_t *posedata, index_t *indexes, int numind float planedist; float diststart, distend; -// float expand; + float mn,mx; + float extend; float frac; -// float temp; vec3_t impactpoint; @@ -1922,47 +1923,107 @@ static qboolean Mod_Trace_Trisoup(vecV_t *posedata, index_t *indexes, int numind VectorSubtract(p1, p2, edge1); VectorSubtract(p3, p2, edge2); CrossProduct(edge1, edge2, normal); + VectorNormalize(normal); -// expand = PlaneNearest(normal, mins, maxs); - planedist = DotProduct(p1, normal); - diststart = DotProduct(start, normal); - if (diststart <= planedist) - continue; //start on back side. - distend = DotProduct(end, normal); - if (distend >= planedist) - continue; //end on front side (as must start - doesn't cross). - - frac = (diststart - planedist - 1) / (diststart-distend); - if (frac < 0) - frac = 0; - - if (frac >= trace->fraction) //already found one closer. + //degenerate triangle + if (!normal[0] && !normal[1] && !normal[2]) continue; - impactpoint[0] = start[0] + frac*(end[0] - start[0]); - impactpoint[1] = start[1] + frac*(end[1] - start[1]); - impactpoint[2] = start[2] + frac*(end[2] - start[2]); + //debugging +// if (normal[2] != 1) +// continue; -// temp = DotProduct(impactpoint, normal)-planedist; +#define DIST_EPSILON (0.03125) +#define DIST_SOLID (3/8.0) //the plane must be at least this thick, or player prediction will try jittering through it to correct the player's origin + extend = PlaneNearest(normal, mins, maxs); + planedist = DotProduct(p1, normal)-extend; + diststart = DotProduct(start, normal); + if (diststart/*+extend+DIST_SOLID*/ < planedist) + continue; //start on back side (or slightly inside). + distend = DotProduct(end, normal); + if (distend > planedist) + continue; //end on front side. + //figure out the precise frac + if (diststart > planedist) + { + //if we're not stuck inside it + if (distend >= diststart) + continue; //trace moves away from or along the surface. don't block the trace if we're sliding along the front of it. + } + frac = (diststart - planedist) / (diststart-distend); + if (frac >= trace->truefraction) //already found one closer. + continue; + + //an impact outside of the surface's bounding box (expanded by the trace bbox) is not a valid impact. + //this solves extrusion issues. + for (j = 0; j < 3; j++) + { + impactpoint[j] = start[j] + frac*(end[j] - start[j]); + //make sure the impact point is within the triangle's bbox. + //primarily, this serves to prevent the edge extruding off to infinity or so + mx = mn = p1[j]; + if (mn > p2[j]) + mn = p2[j]; + if (mx < p2[j]) + mx = p2[j]; + if (mn > p3[j]) + mn = p3[j]; + if (mx < p3[j]) + mx = p3[j]; + mx-=mins[j]-DIST_EPSILON; + mn-=maxs[j]+DIST_EPSILON; + if (impactpoint[j] > mx) + break; + if (impactpoint[j] < mn) + break; + } + if (j < 3) + continue; + + + //make sure the impact point is actually within the triangle CrossProduct(edge1, normal, edgenormal); -// temp = DotProduct(impactpoint, edgenormal)-DotProduct(p2, edgenormal); - if (DotProduct(impactpoint, edgenormal) > DotProduct(p2, edgenormal)) + VectorNormalize(edgenormal); + if (DotProduct(impactpoint, edgenormal) > DotProduct(p2, edgenormal)-PlaneNearest(edgenormal, mins, maxs)+DIST_EPSILON) continue; CrossProduct(normal, edge2, edgenormal); - if (DotProduct(impactpoint, edgenormal) > DotProduct(p3, edgenormal)) + VectorNormalize(edgenormal); + if (DotProduct(impactpoint, edgenormal) > DotProduct(p3, edgenormal)-PlaneNearest(edgenormal, mins, maxs)+DIST_EPSILON) continue; VectorSubtract(p1, p3, edge3); CrossProduct(normal, edge3, edgenormal); - if (DotProduct(impactpoint, edgenormal) > DotProduct(p1, edgenormal)) + VectorNormalize(edgenormal); + if (DotProduct(impactpoint, edgenormal) > DotProduct(p1, edgenormal)-PlaneNearest(edgenormal, mins, maxs)+DIST_EPSILON) continue; - trace->fraction = frac; - VectorCopy(impactpoint, trace->endpos); + //okay, its a valid impact + trace->truefraction = frac; + + //move back from the impact point. this should keep the point slightly outside of the solid triangle. + frac = (diststart - (planedist+DIST_EPSILON)) / (diststart-distend); + if (frac < 0) + { //we're inside, apparently + trace->startsolid = trace->allsolid = (diststart < planedist); + trace->fraction = 0; + VectorCopy(start, trace->endpos); + } + else + { + //we made progress + trace->fraction = frac; + trace->endpos[0] = start[0] + frac*(end[0] - start[0]); + trace->endpos[1] = start[1] + frac*(end[1] - start[1]); + trace->endpos[2] = start[2] + frac*(end[2] - start[2]); + } VectorCopy(normal, trace->plane.normal); + trace->plane.dist = planedist; impacted = true; + +// if (fabs(normal[0]) != 1 && fabs(normal[1]) != 1 && fabs(normal[2]) != 1) +// Con_Printf("Non-axial impact\n"); } return impacted; } diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index db9f97e72..06027ef9b 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -18,9 +18,27 @@ #define MAX_CM_LEAFFACES (MAX_Q2MAP_LEAFFACES) #define MAX_CM_AREAS MAX_Q2MAP_AREAS -#define Q3SURF_NODRAW 0x80 // don't generate a drawsurface at all -#define Q3SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes -#define Q3SURF_NONSOLID 0x4000 // don't collide against curves with this set +//#define Q3SURF_NODAMAGE 0x00000001 +//#define Q3SURF_SLICK 0x00000002 +//#define Q3SURF_SKY 0x00000004 +//#define Q3SURF_LADDER 0x00000008 +//#define Q3SURF_NOIMPACT 0x00000010 +//#define Q3SURF_NOMARKS 0x00000020 +//#define Q3SURF_FLESH 0x00000040 +#define Q3SURF_NODRAW 0x00000080 // don't generate a drawsurface at all +//#define Q3SURF_HINT 0x00000100 +#define Q3SURF_SKIP 0x00000200 // completely ignore, allowing non-closed brushes +//#define Q3SURF_NOLIGHTMAP 0x00000400 +//#define Q3SURF_POINTLIGHT 0x00000800 +//#define Q3SURF_METALSTEPS 0x00001000 +//#define Q3SURF_NOSTEPS 0x00002000 +#define Q3SURF_NONSOLID 0x00004000 // don't collide against curves with this set +//#define Q3SURF_LIGHTFILTER 0x00008000 +//#define Q3SURF_ALPHASHADOW 0x00010000 +//#define Q3SURF_NODLIGHT 0x00020000 +//#define Q3SURF_DUST 0x00040000 +cvar_t q3bsp_surf_meshcollision_flag = CVARD("q3bsp_surf_meshcollision_flag", "0x80000000", "The surfaceparm flag(s) that enables q3bsp trisoup collision"); +cvar_t q3bsp_surf_meshcollision_force = CVARD("q3bsp_surf_meshcollision_force", "0", "Force mesh-based collisions on all q3bsp trisoup surfaces."); #if Q3SURF_NODRAW != TI_NODRAW #error "nodraw isn't constant" @@ -36,10 +54,9 @@ qboolean Mod_LoadSurfedges (lump_t *l); void Mod_LoadLighting (lump_t *l); -qboolean CM_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, trace_t *trace); -qboolean CM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int contents, trace_t *trace); -unsigned int CM_NativeContents(struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs); -unsigned int Q2BSP_PointContents(model_t *mod, vec3_t axis[3], vec3_t p); +static qboolean CM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int contents, trace_t *trace); +static unsigned int CM_NativeContents(struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs); +static unsigned int Q2BSP_PointContents(model_t *mod, vec3_t axis[3], vec3_t p); extern mplane_t *box_planes; @@ -253,6 +270,19 @@ typedef struct int checkcount; // to avoid repeated testings } q3cpatch_t; +typedef struct +{ + vec3_t absmins, absmaxs; + + vecV_t *xyz_array; + size_t numverts; + index_t *indicies; + size_t numincidies; + + q2mapsurface_t *surface; + int checkcount; // to avoid repeated testings +} q3cmesh_t; + typedef struct { int facetype; @@ -261,14 +291,26 @@ typedef struct int firstvert; int shadernum; - int patch_cp[2]; + union + { + struct + { + int cp[2]; + } patch; + struct + { + int firstindex; + int numindicies; + } soup; + }; } q3cface_t; typedef struct cmodel_s { vec3_t mins, maxs; vec3_t origin; // for sounds or lights - int headnode; + mnode_t *headnode; + mleaf_t *headleaf; int numsurfaces; int firstsurface; @@ -288,12 +330,8 @@ static q2cbrushside_t *map_brushsides; static int numtexinfo; static q2mapsurface_t *map_surfaces; -static int numleafs = 1; // allow leaf funcs to be called without a map -static mleaf_t map_leafs[MAX_MAP_LEAFS]; -static int emptyleaf; - static int numleafbrushes; -static int map_leafbrushes[MAX_Q2MAP_LEAFBRUSHES]; +static q2cbrush_t *map_leafbrushes[MAX_Q2MAP_LEAFBRUSHES]; static int numcmodels; static cmodel_t *map_cmodels; @@ -306,9 +344,6 @@ static q2dvis_t *map_q2vis; static q3dvis_t *map_q3pvs; static q3dvis_t *map_q3phs; -static int numentitychars; -static char *map_entitystring; - static int numareas = 1; static q2carea_t map_q2areas[MAX_Q2MAP_AREAS]; static q3carea_t map_q3areas[MAX_CM_AREAS]; @@ -316,13 +351,20 @@ static q3carea_t map_q3areas[MAX_CM_AREAS]; static int numareaportals; static q2dareaportal_t map_areaportals[MAX_Q2MAP_AREAPORTALS]; +//(deprecated) patch collisions static q3cpatch_t map_patches[MAX_CM_PATCHES]; static int numpatches; - static int *map_leafpatches; static int numleafpatches; static int maxleafpatches; +//list of mesh surfaces within the leaf +static q3cmesh_t map_cmeshes[MAX_CM_PATCHES]; +static int numcmeshes; +static int *map_leafcmeshes; +static int numleafcmeshes; +static int maxleafcmeshes; + static int numclusters = 1; static q2mapsurface_t nullsurface; @@ -343,11 +385,6 @@ cmodel_t *CM_InlineModel (char *name); void CM_InitBoxHull (void); static void FloodAreaConnections (void); - -static int c_pointcontents; -static int c_traces, c_brush_traces; - - static vecV_t *map_verts; //3points static int numvertexes; @@ -916,6 +953,7 @@ qboolean CM_CreatePatchesForLeafs (void) q3cface_t *face; q2mapsurface_t *surf; q3cpatch_t *patch; + q3cmesh_t *cmesh; int *checkout = alloca(sizeof(int)*numfaces); if (map_noCurves.ival) @@ -923,81 +961,145 @@ qboolean CM_CreatePatchesForLeafs (void) memset (checkout, -1, sizeof(int)*numfaces); - for (i = 0, leaf = map_leafs; i < numleafs; i++, leaf++) + for (i = 0, leaf = loadmodel->leafs; i < loadmodel->numleafs; i++, leaf++) { leaf->numleafpatches = 0; leaf->firstleafpatch = numleafpatches; + leaf->numleafcmeshes = 0; + leaf->firstleafcmesh = numleafcmeshes; if (leaf->cluster == -1) continue; - for (j=0 ; jnumleaffaces ; j++) + for (j=0 ; jnummarksurfaces ; j++) { - k = leaf->firstleafface + j; - if (k >= numleaffaces) - { - break; - } - - k = map_leaffaces[k]; -#ifdef _DEBUG + k = leaf->firstmarksurface[j] - loadmodel->surfaces; if (k >= numfaces) { Con_Printf (CON_ERROR "CM_CreatePatchesForLeafs: corrupt map\n"); break; } -#endif face = &map_faces[k]; - if (face->facetype != MST_PATCH || face->numverts <= 0) - continue; - if (face->patch_cp[0] <= 0 || face->patch_cp[1] <= 0) + if (face->numverts <= 0) continue; if (face->shadernum < 0 || face->shadernum >= loadmodel->numtextures) continue; - surf = &map_surfaces[face->shadernum]; - if ( !surf->c.value || (surf->c.flags & Q3SURF_NONSOLID) ) + if (!surf->c.value) //surface has no contents value, so can't ever block anything. continue; - if (numleafpatches >= maxleafpatches) + switch(face->facetype) { - maxleafpatches *= 2; - maxleafpatches += 16; - if (numleafpatches > maxleafpatches) - { //detect overflow - Con_Printf (CON_ERROR "CM_CreatePatchesForLeafs: map is insanely huge!\n"); - return false; - } - map_leafpatches = realloc(map_leafpatches, sizeof(*map_leafpatches) * maxleafpatches); - } + case MST_TRIANGLE_SOUP: + if (!face->soup.numindicies) + continue; + //only enable mesh collisions if its meant to be enabled. + //we haven't parsed any shaders, so we depend upon the stuff that the bsp compiler left lying around. + if (!(surf->c.flags & q3bsp_surf_meshcollision_flag.ival) && !q3bsp_surf_meshcollision_force.ival) + continue; - // the patch was already built - if (checkout[k] != -1) - { - map_leafpatches[numleafpatches] = checkout[k]; - patch = &map_patches[checkout[k]]; - } - else - { - if (numpatches >= MAX_CM_PATCHES) + if (numleafcmeshes >= maxleafcmeshes) { - Con_Printf (CON_ERROR "CM_CreatePatchesForLeafs: map has too many patches\n"); - return false; + maxleafcmeshes *= 2; + maxleafcmeshes += 16; + if (numleafcmeshes > maxleafcmeshes) + { //detect overflow + Con_Printf (CON_ERROR "CM_CreateCMeshesForLeafs: map is insanely huge!\n"); + return false; + } + map_leafcmeshes = realloc(map_leafcmeshes, sizeof(*map_leafcmeshes) * maxleafcmeshes); } - patch = &map_patches[numpatches]; - map_leafpatches[numleafpatches] = numpatches; - checkout[k] = numpatches++; + // the patch was already built + if (checkout[k] != -1) + { + map_leafcmeshes[numleafcmeshes] = checkout[k]; + cmesh = &map_cmeshes[checkout[k]]; + } + else + { + if (numcmeshes >= MAX_CM_PATCHES) + { + Con_Printf (CON_ERROR "CM_CreatePatchesForLeafs: map has too many patches\n"); + return false; + } -//gcc warns without this cast - CM_CreatePatch ( patch, surf, (const vec_t *)(map_verts + face->firstvert), face->patch_cp ); + cmesh = &map_cmeshes[numcmeshes]; + map_leafcmeshes[numleafcmeshes] = numcmeshes; + checkout[k] = numcmeshes++; + + //gcc warns without this cast + + cmesh->surface = surf; + cmesh->numverts = face->numverts; + cmesh->numincidies = face->soup.numindicies; + cmesh->xyz_array = ZG_Malloc(&loadmodel->memgroup, cmesh->numverts * sizeof(*cmesh->xyz_array) + cmesh->numincidies * sizeof(*cmesh->indicies)); + cmesh->indicies = (index_t*)(cmesh->xyz_array + cmesh->numverts); + + VectorCopy(map_verts[face->firstvert+0], cmesh->xyz_array[0]); + VectorCopy(cmesh->xyz_array[0], cmesh->absmaxs); + VectorCopy(cmesh->xyz_array[0], cmesh->absmins); + for (k = 1; k < cmesh->numverts; k++) + { + VectorCopy(map_verts[face->firstvert+k], cmesh->xyz_array[k]); + AddPointToBounds(cmesh->xyz_array[k], cmesh->absmins, cmesh->absmaxs); + } + for (k = 0; k < cmesh->numincidies; k++) + cmesh->indicies[k] = map_surfindexes[face->soup.firstindex+k]; + } + leaf->contents |= surf->c.value; + leaf->numleafcmeshes++; + + numleafcmeshes++; + + break; + case MST_PATCH: + if (face->patch.cp[0] <= 0 || face->patch.cp[1] <= 0) + continue; + + if ( !surf->c.value || (surf->c.flags & Q3SURF_NONSOLID) ) + continue; + + if (numleafpatches >= maxleafpatches) + { + maxleafpatches *= 2; + maxleafpatches += 16; + if (numleafpatches > maxleafpatches) + { //detect overflow + Con_Printf (CON_ERROR "CM_CreatePatchesForLeafs: map is insanely huge!\n"); + return false; + } + map_leafpatches = realloc(map_leafpatches, sizeof(*map_leafpatches) * maxleafpatches); + } + + // the patch was already built + if (checkout[k] != -1) + { + map_leafpatches[numleafpatches] = checkout[k]; + patch = &map_patches[checkout[k]]; + } + else + { + if (numpatches >= MAX_CM_PATCHES) + { + Con_Printf (CON_ERROR "CM_CreatePatchesForLeafs: map has too many patches\n"); + return false; + } + + patch = &map_patches[numpatches]; + map_leafpatches[numleafpatches] = numpatches; + checkout[k] = numpatches++; + + //gcc warns without this cast + CM_CreatePatch ( patch, surf, (const vec_t *)(map_verts + face->firstvert), face->patch.cp ); + } + leaf->contents |= patch->surface->c.value; + leaf->numleafpatches++; + + numleafpatches++; + break; } - - leaf->contents |= patch->surface->c.value; - leaf->numleafpatches++; - - numleafpatches++; } } @@ -1021,7 +1123,7 @@ qbyte *cmod_base; CMod_LoadSubmodels ================= */ -qboolean CMod_LoadSubmodels (lump_t *l) +qboolean CModQ2_LoadSubmodels (lump_t *l) { q2dmodel_t *in; cmodel_t *out; @@ -1057,7 +1159,7 @@ qboolean CMod_LoadSubmodels (lump_t *l) out->maxs[j] = LittleFloat (in->maxs[j]) + 1; out->origin[j] = LittleFloat (in->origin[j]); } - out->headnode = LittleLong (in->headnode); + out->headnode = loadmodel->nodes + LittleLong (in->headnode); out->firstsurface = LittleLong (in->firstface); out->numsurfaces = LittleLong (in->numfaces); } @@ -1074,7 +1176,7 @@ qboolean CMod_LoadSubmodels (lump_t *l) CMod_LoadSurfaces ================= */ -qboolean CMod_LoadSurfaces (lump_t *l) +qboolean CModQ2_LoadSurfaces (lump_t *l) { q2texinfo_t *in; q2mapsurface_t *out; @@ -1187,7 +1289,7 @@ texture_t *Mod_LoadWall(char *name, char *sname, unsigned int imageflags) return tex; } -qboolean CMod_LoadTexInfo (lump_t *l) //yes I know these load from the same place +qboolean CModQ2_LoadTexInfo (lump_t *l) //yes I know these load from the same place { q2texinfo_t *in; mtexinfo_t *out; @@ -1361,7 +1463,7 @@ Mod_LoadFaces ================= */ #ifndef SERVERONLY -qboolean CMod_LoadFaces (lump_t *l) +qboolean CModQ2_LoadFaces (lump_t *l) { dsface_t *in; msurface_t *out; @@ -1458,7 +1560,7 @@ CMod_LoadNodes ================= */ -qboolean CMod_LoadNodes (lump_t *l) +qboolean CModQ2_LoadNodes (lump_t *l) { q2dnode_t *in; int child; @@ -1510,7 +1612,7 @@ qboolean CMod_LoadNodes (lump_t *l) child = LittleLong (in->children[j]); out->childnum[j] = child; if (child < 0) - out->children[j] = (mnode_t *)(map_leafs + -1-child); + out->children[j] = (mnode_t *)(loadmodel->leafs + -1-child); else out->children[j] = loadmodel->nodes + child; } @@ -1527,7 +1629,7 @@ CMod_LoadBrushes ================= */ -qboolean CMod_LoadBrushes (lump_t *l) +qboolean CModQ2_LoadBrushes (lump_t *l) { q2dbrush_t *in; q2cbrush_t *out; @@ -1569,7 +1671,7 @@ qboolean CMod_LoadBrushes (lump_t *l) CMod_LoadLeafs ================= */ -qboolean CMod_LoadLeafs (lump_t *l) +qboolean CModQ2_LoadLeafs (lump_t *l) { int i, j; mleaf_t *out; @@ -1590,14 +1692,13 @@ qboolean CMod_LoadLeafs (lump_t *l) return false; } // need to save space for box planes - if (count > sizeof(map_leafs)/sizeof(map_leafs[0])) + if (count > MAX_MAP_LEAFS) { Con_Printf (CON_ERROR "Map has too many leafs\n"); return false; } - out = map_leafs; - numleafs = count; + out = ZG_Malloc(&loadmodel->memgroup, sizeof(*out) * (count+1)); numclusters = 0; loadmodel->leafs = out; @@ -1629,27 +1730,14 @@ qboolean CMod_LoadLeafs (lump_t *l) if (out->cluster >= numclusters) numclusters = out->cluster + 1; } + out = loadmodel->leafs; - if (map_leafs[0].contents != Q2CONTENTS_SOLID) + if (out[0].contents != Q2CONTENTS_SOLID) { Con_Printf (CON_ERROR "Map leaf 0 is not CONTENTS_SOLID\n"); return false; } - emptyleaf = -1; - for (i=1 ; ifilelen; // if (l->filelen > MAX_Q2MAP_ENTSTRING) // Host_Error ("Map has too large entity lump"); - map_entitystring = ZG_Malloc(&loadmodel->memgroup, l->filelen+1); - memcpy (map_entitystring, cmod_base + l->fileofs, l->filelen); - - loadmodel->entities = map_entitystring; + loadmodel->entities = ZG_Malloc(&loadmodel->memgroup, l->filelen+1); + memcpy (loadmodel->entities, cmod_base + l->fileofs, l->filelen); } @@ -1961,7 +2046,7 @@ qboolean CModQ3_LoadSubmodels (lump_t *l) q3dmodel_t *in; cmodel_t *out; int i, j, count; - int *leafbrush; + q2cbrush_t **leafbrush; mleaf_t *bleaf; in = (void *)(cmod_base + l->fileofs); @@ -1986,6 +2071,11 @@ qboolean CModQ3_LoadSubmodels (lump_t *l) out = map_cmodels = ZG_Malloc(&loadmodel->memgroup, count * sizeof(*map_cmodels)); numcmodels = count; + if (count > 1) + bleaf = ZG_Malloc(&loadmodel->memgroup, (count-1) * sizeof(*bleaf)); + else + bleaf = NULL; + mapisq3 = true; for (i=0 ; ifirstsurface = LittleLong (in->firstsurface); out->numsurfaces = LittleLong (in->num_surfaces); if (!i) - out->headnode = 0; + { + out->headnode = loadmodel->nodes; + out->headleaf = NULL; + } else { -//create a new leaf to hold the bruses and be directly clipped - out->headnode = -1 - numleafs; +//create a new leaf to hold the brushes and be directly clipped + out->headleaf = bleaf; + out->headnode = NULL; // out->firstbrush = LittleLong(in->firstbrush); // out->num_brushes = LittleLong(in->num_brushes); - bleaf = &map_leafs[numleafs++]; bleaf->numleafbrushes = LittleLong ( in->num_brushes ); bleaf->firstleafbrush = numleafbrushes; bleaf->contents = 0; @@ -2016,10 +2109,11 @@ qboolean CModQ3_LoadSubmodels (lump_t *l) leafbrush = &map_leafbrushes[numleafbrushes]; for ( j = 0; j < bleaf->numleafbrushes; j++, leafbrush++ ) { - *leafbrush = LittleLong ( in->firstbrush ) + j; - bleaf->contents |= map_brushes[*leafbrush].contents; + *leafbrush = map_brushes + LittleLong ( in->firstbrush ) + j; + bleaf->contents |= (*leafbrush)->contents; } numleafbrushes += bleaf->numleafbrushes; + bleaf++; } //submodels } @@ -2274,8 +2368,16 @@ qboolean CModQ3_LoadFaces (lump_t *l) out->numverts = LittleLong ( in->num_vertices ); out->firstvert = LittleLong ( in->firstvertex ); - out->patch_cp[0] = LittleLong ( in->patchwidth ); - out->patch_cp[1] = LittleLong ( in->patchheight ); + if (out->facetype == MST_PATCH) + { + out->patch.cp[0] = LittleLong ( in->patchwidth ); + out->patch.cp[1] = LittleLong ( in->patchheight ); + } + else + { + out->soup.firstindex = LittleLong(in->firstindex); + out->soup.numindicies = LittleLong(in->num_indexes); + } } loadmodel->numsurfaces = i; @@ -2315,8 +2417,16 @@ qboolean CModRBSP_LoadFaces (lump_t *l) out->numverts = LittleLong ( in->num_vertices ); out->firstvert = LittleLong ( in->firstvertex ); - out->patch_cp[0] = LittleLong ( in->patchwidth ); - out->patch_cp[1] = LittleLong ( in->patchheight ); + if (out->facetype == MST_PATCH) + { + out->patch.cp[0] = LittleLong ( in->patchwidth ); + out->patch.cp[1] = LittleLong ( in->patchheight ); + } + else + { + out->soup.firstindex = LittleLong(in->firstindex); + out->soup.numindicies = LittleLong(in->num_indexes); + } } loadmodel->numsurfaces = i; @@ -3092,15 +3202,12 @@ qboolean CModQ3_LoadLeafs (lump_t *l) return false; } - out = map_leafs; - numleafs = count; + out = ZG_Malloc(&loadmodel->memgroup, sizeof(*out) * (count+1)); numclusters = 0; loadmodel->leafs = out; loadmodel->numleafs = count; - emptyleaf = -1; - for ( i=0 ; iminmaxs[0+j] = LittleLong(in->mins[j]); out->minmaxs[3+j] = LittleLong(in->maxs[j]); } - out->cluster = LittleLong ( in->cluster ); - out->area = LittleLong ( in->area ) + 1; - out->firstleafface = LittleLong ( in->firstleafsurface ); - out->numleaffaces = LittleLong ( in->num_leafsurfaces ); + out->cluster = LittleLong(in->cluster); + out->area = LittleLong(in->area) + 1; +// out->firstleafface = LittleLong(in->firstleafsurface); +// out->numleaffaces = LittleLong(in->num_leafsurfaces); out->contents = 0; - out->firstleafbrush = LittleLong ( in->firstleafbrush ); - out->numleafbrushes = LittleLong ( in->num_leafbrushes ); + out->firstleafbrush = LittleLong(in->firstleafbrush); + out->numleafbrushes = LittleLong(in->num_leafbrushes); - out->firstmarksurface = loadmodel->marksurfaces + - LittleLong(in->firstleafsurface); + out->firstmarksurface = loadmodel->marksurfaces + LittleLong(in->firstleafsurface); out->nummarksurfaces = LittleLong(in->num_leafsurfaces); if (out->minmaxs[0] > out->minmaxs[3+0] || out->minmaxs[1] > out->minmaxs[3+1] || - out->minmaxs[2] > out->minmaxs[3+2] || VectorEquals (out->minmaxs, out->minmaxs+3)) + out->minmaxs[2] > out->minmaxs[3+2])// || VectorEquals (out->minmaxs, out->minmaxs+3)) { out->nummarksurfaces = 0; } - for ( j=0 ; jnumleafbrushes ; j++) + for (j=0 ; jnumleafbrushes ; j++) { - brush = &map_brushes[map_leafbrushes[out->firstleafbrush + j]]; + brush = map_leafbrushes[out->firstleafbrush + j]; out->contents |= brush->contents; } - if ( out->area >= numareas ) { + if (out->area >= numareas) + { numareas = out->area + 1; } - - if ( !out->contents ) { - emptyleaf = i; - } - } - - // if map doesn't have an empty leaf - force one - if ( emptyleaf == -1 ) { - if (numleafs >= MAX_MAP_LEAFS-1) - { - Con_Printf (CON_ERROR "Map does not have an empty leaf\n"); - return false; - } - - out->cluster = -1; - out->area = -1; - out->numleafbrushes = 0; - out->contents = 0; - out->firstleafbrush = 0; - - Con_DPrintf ( "Forcing an empty leaf: %i\n", numleafs ); - emptyleaf = numleafs++; } return true; @@ -3203,7 +3288,7 @@ qboolean CModQ3_LoadPlanes (lump_t *l) qboolean CModQ3_LoadLeafBrushes (lump_t *l) { int i; - int *out; + q2cbrush_t **out; int *in; int count; @@ -3231,7 +3316,7 @@ qboolean CModQ3_LoadLeafBrushes (lump_t *l) numleafbrushes = count; for ( i=0 ; itype = mod_brush; @@ -3798,11 +3878,12 @@ cmodel_t *CM_LoadMap (char *name, char *filein, qboolean clientload, unsigned *c if (!name || !name[0]) { map_cmodels = ZG_Malloc(&loadmodel->memgroup, 1 * sizeof(*map_cmodels)); + loadmodel->leafs = ZG_Malloc(&loadmodel->memgroup, 1 * sizeof(*loadmodel->leafs)); numcmodels = 1; - numleafs = 1; numclusters = 1; numareas = 1; *checksum = 0; + map_cmodels[0].headnode = (mnode_t*)loadmodel->leafs; //directly start with the empty leaf return &map_cmodels[0]; // cinematic servers won't have anything at all } @@ -3846,7 +3927,7 @@ cmodel_t *CM_LoadMap (char *name, char *filein, qboolean clientload, unsigned *c , name, header.version, Q2BSPVERSION, Q3BSPVERSION); return NULL; break; -#if 1 +#ifdef Q3BSPS case 1: //rbsp/fbsp case Q3BSPVERSION+1: //rtcw case Q3BSPVERSION: @@ -3907,7 +3988,6 @@ cmodel_t *CM_LoadMap (char *name, char *filein, qboolean clientload, unsigned *c mapisq3 = true; noerrors = noerrors && CModQ3_LoadShaders (&header.lumps[Q3LUMP_SHADERS]); noerrors = noerrors && CModQ3_LoadPlanes (&header.lumps[Q3LUMP_PLANES]); - noerrors = noerrors && CModQ3_LoadLeafBrushes (&header.lumps[Q3LUMP_LEAFBRUSHES]); if (header.version == 1) { noerrors = noerrors && CModRBSP_LoadBrushSides (&header.lumps[Q3LUMP_BRUSHSIDES]); @@ -3919,6 +3999,7 @@ cmodel_t *CM_LoadMap (char *name, char *filein, qboolean clientload, unsigned *c noerrors = noerrors && CModQ3_LoadVertexes (&header.lumps[Q3LUMP_DRAWVERTS]); } noerrors = noerrors && CModQ3_LoadBrushes (&header.lumps[Q3LUMP_BRUSHES]); + noerrors = noerrors && CModQ3_LoadLeafBrushes (&header.lumps[Q3LUMP_LEAFBRUSHES]); if (header.version == 1) noerrors = noerrors && CModRBSP_LoadFaces (&header.lumps[Q3LUMP_SURFACES]); else @@ -3999,7 +4080,7 @@ cmodel_t *CM_LoadMap (char *name, char *filein, qboolean clientload, unsigned *c loadmodel->funcs.FindTouchedLeafs = Q2BSP_FindTouchedLeafs; #endif loadmodel->funcs.LeafPVS = CM_LeafnumPVS; - loadmodel->funcs.LeafnumForPoint = CM_PointLeafnum; + loadmodel->funcs.LeafnumForPoint = CM_PointLeafnum; #ifndef SERVERONLY loadmodel->funcs.LightPointValues = GLQ3_LightGrid; @@ -4067,17 +4148,17 @@ cmodel_t *CM_LoadMap (char *name, char *filein, qboolean clientload, unsigned *c switch(qrenderer) { case QR_NONE: //dedicated only - noerrors = noerrors && CMod_LoadSurfaces (&header.lumps[Q2LUMP_TEXINFO]); - noerrors = noerrors && CMod_LoadLeafBrushes (&header.lumps[Q2LUMP_LEAFBRUSHES]); - noerrors = noerrors && CMod_LoadPlanes (&header.lumps[Q2LUMP_PLANES]); - noerrors = noerrors && CMod_LoadVisibility (&header.lumps[Q2LUMP_VISIBILITY]); - noerrors = noerrors && CMod_LoadBrushSides (&header.lumps[Q2LUMP_BRUSHSIDES]); - noerrors = noerrors && CMod_LoadBrushes (&header.lumps[Q2LUMP_BRUSHES]); - noerrors = noerrors && CMod_LoadSubmodels (&header.lumps[Q2LUMP_MODELS]); - noerrors = noerrors && CMod_LoadLeafs (&header.lumps[Q2LUMP_LEAFS]); - noerrors = noerrors && CMod_LoadNodes (&header.lumps[Q2LUMP_NODES]); - noerrors = noerrors && CMod_LoadAreas (&header.lumps[Q2LUMP_AREAS]); - noerrors = noerrors && CMod_LoadAreaPortals (&header.lumps[Q2LUMP_AREAPORTALS]); + noerrors = noerrors && CModQ2_LoadSurfaces (&header.lumps[Q2LUMP_TEXINFO]); + noerrors = noerrors && CModQ2_LoadPlanes (&header.lumps[Q2LUMP_PLANES]); + noerrors = noerrors && CModQ2_LoadVisibility (&header.lumps[Q2LUMP_VISIBILITY]); + noerrors = noerrors && CModQ2_LoadBrushSides (&header.lumps[Q2LUMP_BRUSHSIDES]); + noerrors = noerrors && CModQ2_LoadBrushes (&header.lumps[Q2LUMP_BRUSHES]); + noerrors = noerrors && CModQ2_LoadLeafBrushes (&header.lumps[Q2LUMP_LEAFBRUSHES]); + noerrors = noerrors && CModQ2_LoadLeafs (&header.lumps[Q2LUMP_LEAFS]); + noerrors = noerrors && CModQ2_LoadNodes (&header.lumps[Q2LUMP_NODES]); + noerrors = noerrors && CModQ2_LoadSubmodels (&header.lumps[Q2LUMP_MODELS]); + noerrors = noerrors && CModQ2_LoadAreas (&header.lumps[Q2LUMP_AREAS]); + noerrors = noerrors && CModQ2_LoadAreaPortals (&header.lumps[Q2LUMP_AREAPORTALS]); if (noerrors) CMod_LoadEntityString (&header.lumps[Q2LUMP_ENTITIES]); @@ -4108,22 +4189,22 @@ cmodel_t *CM_LoadMap (char *name, char *filein, qboolean clientload, unsigned *c if (noerrors) Mod_LoadLighting (&header.lumps[Q2LUMP_LIGHTING]); #endif - noerrors = noerrors && CMod_LoadSurfaces (&header.lumps[Q2LUMP_TEXINFO]); - noerrors = noerrors && CMod_LoadLeafBrushes (&header.lumps[Q2LUMP_LEAFBRUSHES]); - noerrors = noerrors && CMod_LoadPlanes (&header.lumps[Q2LUMP_PLANES]); + noerrors = noerrors && CModQ2_LoadSurfaces (&header.lumps[Q2LUMP_TEXINFO]); + noerrors = noerrors && CModQ2_LoadPlanes (&header.lumps[Q2LUMP_PLANES]); #ifndef SERVERONLY - noerrors = noerrors && CMod_LoadTexInfo (&header.lumps[Q2LUMP_TEXINFO]); - noerrors = noerrors && CMod_LoadFaces (&header.lumps[Q2LUMP_FACES]); + noerrors = noerrors && CModQ2_LoadTexInfo (&header.lumps[Q2LUMP_TEXINFO]); + noerrors = noerrors && CModQ2_LoadFaces (&header.lumps[Q2LUMP_FACES]); noerrors = noerrors && Mod_LoadMarksurfaces (&header.lumps[Q2LUMP_LEAFFACES], false); #endif - noerrors = noerrors && CMod_LoadVisibility (&header.lumps[Q2LUMP_VISIBILITY]); - noerrors = noerrors && CMod_LoadBrushSides (&header.lumps[Q2LUMP_BRUSHSIDES]); - noerrors = noerrors && CMod_LoadBrushes (&header.lumps[Q2LUMP_BRUSHES]); - noerrors = noerrors && CMod_LoadSubmodels (&header.lumps[Q2LUMP_MODELS]); - noerrors = noerrors && CMod_LoadLeafs (&header.lumps[Q2LUMP_LEAFS]); - noerrors = noerrors && CMod_LoadNodes (&header.lumps[Q2LUMP_NODES]); - noerrors = noerrors && CMod_LoadAreas (&header.lumps[Q2LUMP_AREAS]); - noerrors = noerrors && CMod_LoadAreaPortals (&header.lumps[Q2LUMP_AREAPORTALS]); + noerrors = noerrors && CModQ2_LoadVisibility (&header.lumps[Q2LUMP_VISIBILITY]); + noerrors = noerrors && CModQ2_LoadBrushSides (&header.lumps[Q2LUMP_BRUSHSIDES]); + noerrors = noerrors && CModQ2_LoadBrushes (&header.lumps[Q2LUMP_BRUSHES]); + noerrors = noerrors && CModQ2_LoadLeafBrushes (&header.lumps[Q2LUMP_LEAFBRUSHES]); + noerrors = noerrors && CModQ2_LoadLeafs (&header.lumps[Q2LUMP_LEAFS]); + noerrors = noerrors && CModQ2_LoadNodes (&header.lumps[Q2LUMP_NODES]); + noerrors = noerrors && CModQ2_LoadSubmodels (&header.lumps[Q2LUMP_MODELS]); + noerrors = noerrors && CModQ2_LoadAreas (&header.lumps[Q2LUMP_AREAS]); + noerrors = noerrors && CModQ2_LoadAreaPortals (&header.lumps[Q2LUMP_AREAPORTALS]); if (noerrors) CMod_LoadEntityString (&header.lumps[Q2LUMP_ENTITIES]); @@ -4176,17 +4257,11 @@ cmodel_t *CM_LoadMap (char *name, char *filein, qboolean clientload, unsigned *c loadmodel->numsubmodels = CM_NumInlineModels(loadmodel); { + model_t *wmod = loadmodel; model_t *mod = loadmodel; - mod->hulls[0].firstclipnode = map_cmodels[0].headnode; - mod->hulls[0].available = true; - - for (j=1 ; jhulls[j].firstclipnode = map_cmodels[0].headnode; - mod->hulls[j].available = false; - } - + mod->hulls[0].firstclipnode = map_cmodels[0].headnode-mod->nodes; + mod->rootnode = map_cmodels[0].headnode; mod->nummodelsurfaces = map_cmodels[0].numsurfaces; for (i=1 ; i< loadmodel->numsubmodels ; i++) @@ -4205,16 +4280,24 @@ cmodel_t *CM_LoadMap (char *name, char *filein, qboolean clientload, unsigned *c bm = CM_InlineModel (name); - mod->hulls[0].firstclipnode = bm->headnode; - mod->hulls[0].available = true; + + mod->hulls[0].firstclipnode = -1; //no nodes, + if (bm->headleaf) + { + mod->leafs = bm->headleaf; + mod->nodes = NULL; + mod->hulls[0].firstclipnode = -1; //make it refer directly to the first leaf, for things that still use numbers. + mod->rootnode = (mnode_t*)bm->headleaf; + } + else + { + mod->leafs = wmod->leafs; + mod->nodes = wmod->nodes; + mod->hulls[0].firstclipnode = bm->headnode - mod->nodes; //determine the correct node index + mod->rootnode = bm->headnode; + } mod->nummodelsurfaces = bm->numsurfaces; mod->firstmodelsurface = bm->firstsurface; - for (j=1 ; jhulls[j].firstclipnode = bm->headnode; - mod->hulls[j].lastclipnode = mod->numclipnodes-1; - mod->hulls[j].available = false; - } memset(&mod->batches, 0, sizeof(mod->batches)); mod->vbos = NULL; @@ -4277,30 +4360,25 @@ int CM_NumInlineModels (model_t *model) return numcmodels; } -char *CM_EntityString (model_t *model) -{ - return map_entitystring; -} - int CM_LeafContents (model_t *model, int leafnum) { if (leafnum < 0 || leafnum >= model->numleafs) Host_Error ("CM_LeafContents: bad number"); - return map_leafs[leafnum].contents; + return model->leafs[leafnum].contents; } int CM_LeafCluster (model_t *model, int leafnum) { if (leafnum < 0 || leafnum >= model->numleafs) Host_Error ("CM_LeafCluster: bad number"); - return map_leafs[leafnum].cluster; + return model->leafs[leafnum].cluster; } int CM_LeafArea (model_t *model, int leafnum) { if (leafnum < 0 || leafnum >= model->numleafs) Host_Error ("CM_LeafArea: bad number"); - return map_leafs[leafnum].area; + return model->leafs[leafnum].area; } //======================================================================= @@ -4309,7 +4387,7 @@ int CM_LeafArea (model_t *model, int leafnum) mplane_t *box_planes; int box_headnode; q2cbrush_t *box_brush; -mleaf_t *box_leaf; +mleaf_t box_leaf[2]; //solid, empty model_t box_model; /* @@ -4343,8 +4421,6 @@ void CM_InitBoxHull (void) box_model.funcs.NativeContents = CM_NativeContents; box_model.funcs.NativeTrace = CM_NativeTrace; - box_model.hulls[0].available = true; - box_model.nodes = ZG_Malloc(&box_model.memgroup, sizeof(mnode_t)*6); box_planes = ZG_Malloc(&box_model.memgroup, sizeof(mplane_t)*12); if (numbrushes+1 > SANITY_MAX_MAP_BRUSHES @@ -4356,12 +4432,17 @@ void CM_InitBoxHull (void) box_brush->brushside = ZG_Malloc(&box_model.memgroup, sizeof(q2cbrushside_t)*6); box_brush->contents = Q2CONTENTS_MONSTER; - box_leaf = &map_leafs[numleafs]; - box_leaf->contents = Q2CONTENTS_MONSTER; - box_leaf->firstleafbrush = numleafbrushes; - box_leaf->numleafbrushes = 1; + box_leaf[0].contents = Q2CONTENTS_MONSTER; + box_leaf[0].firstleafbrush = numleafbrushes; + box_leaf[0].numleafbrushes = 1; + box_leaf[1].contents = 0; + box_leaf[1].firstleafbrush = numleafbrushes; + box_leaf[1].numleafbrushes = 1; + box_model.leafs = box_leaf; - map_leafbrushes[numleafbrushes] = numbrushes; + box_model.rootnode = box_model.nodes; + + map_leafbrushes[numleafbrushes] = box_brush; for (i=0 ; i<6 ; i++) { @@ -4375,11 +4456,11 @@ void CM_InitBoxHull (void) // nodes c = &box_model.nodes[i]; c->plane = box_planes + (i*2); - c->childnum[side] = -1 - emptyleaf; + c->childnum[side] = -1 - 1; //empty leaf if (i != 5) c->childnum[side^1] = box_headnode+i + 1; else - c->childnum[side^1] = -1 - numleafs; + c->childnum[side^1] = -1 - 0; //solid leaf // planes p = &box_planes[i*2]; @@ -4456,8 +4537,6 @@ int CM_PointLeafnum_r (model_t *mod, vec3_t p, int num) num = node->childnum[0]; } - c_pointcontents++; // optimize counter - return -1 - num; } @@ -4564,10 +4643,10 @@ int CM_PointContents (model_t *mod, vec3_t p) i = CM_PointLeafnum_r (mod, p, mod->hulls[0].firstclipnode); if (!mapisq3) - contents = map_leafs[i].contents; //q2 is simple. + contents = mod->leafs[i].contents; //q2 is simple. else { - leaf = &map_leafs[i]; + leaf = &mod->leafs[i]; // if ( leaf->contents & CONTENTS_NODROP ) { // contents = CONTENTS_NODROP; @@ -4577,7 +4656,7 @@ int CM_PointContents (model_t *mod, vec3_t p) for (i = 0; i < leaf->numleafbrushes; i++) { - brush = &map_brushes[map_leafbrushes[leaf->firstleafbrush + i]]; + brush = map_leafbrushes[leaf->firstleafbrush + i]; // check if brush actually adds something to contents if ( (contents & brush->contents) == brush->contents ) { @@ -4626,12 +4705,12 @@ unsigned int CM_NativeContents(struct model_s *model, int hulloverride, int fram contents = 0; for (k--; k >= 0; k--) { - leaf = &map_leafs[leaflist[k]]; + leaf = &model->leafs[leaflist[k]]; if (mapisq3) { for (i = 0; i < leaf->numleafbrushes; i++) { - brush = &map_brushes[map_leafbrushes[leaf->firstleafbrush + i]]; + brush = map_leafbrushes[leaf->firstleafbrush + i]; // check if brush actually adds something to contents if ( (contents & brush->contents) == brush->contents ) { @@ -4701,23 +4780,23 @@ BOX TRACING // 1/32 epsilon to keep floating point happy #define DIST_EPSILON (0.03125) -vec3_t trace_start, trace_end; -vec3_t trace_mins, trace_maxs; -vec3_t trace_extents; -vec3_t trace_absmins, trace_absmaxs; -float trace_truefraction; -float trace_nearfraction; +static vec3_t trace_start, trace_end; +static vec3_t trace_mins, trace_maxs; +static vec3_t trace_extents; +static vec3_t trace_absmins, trace_absmaxs; +static float trace_truefraction; +static float trace_nearfraction; -trace_t trace_trace; -int trace_contents; -qboolean trace_ispoint; // optimized case +static trace_t trace_trace; +static int trace_contents; +static qboolean trace_ispoint; // optimized case /* ================ CM_ClipBoxToBrush ================ */ -void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, +static void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, trace_t *trace, q2cbrush_t *brush) { int i, j; @@ -4738,8 +4817,6 @@ void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, if (!brush->numsides) return; - c_brush_traces++; - getout = false; startout = false; leadside = NULL; @@ -4832,7 +4909,246 @@ void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, } } -void CM_ClipBoxToPatch (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, +static void CM_ClipBoxToPlanes (vec3_t trmins, vec3_t trmaxs, vec3_t p1, vec3_t p2, trace_t *trace, vec3_t plmins, vec3_t plmaxs, mplane_t *plane, int numplanes, q2csurface_t *surf) +{ + int i, j; + mplane_t *clipplane; + float dist; + float enterfrac, leavefrac; + vec3_t ofs; + float d1, d2; + qboolean getout, startout; + float f; +// q2cbrushside_t *side, *leadside; + static mplane_t bboxplanes[6] = //we change the dist, but nothing else + { + {1, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + {-1, 0, 0}, + {0, -1, 0}, + {0, 0, -1}, + }; + + float nearfrac=0; + enterfrac = -1; + leavefrac = 2; + clipplane = NULL; + + getout = false; + startout = false; +// leadside = NULL; + + for (i=0 ; inormal[j] < 0) + ofs[j] = trmaxs[j]; + else + ofs[j] = trmins[j]; + } + dist = DotProduct (ofs, plane->normal); + dist = plane->dist - dist; + } + else + { // special point case + dist = plane->dist; + } + + d1 = DotProduct (p1, plane->normal) - dist; + d2 = DotProduct (p2, plane->normal) - dist; + + if (d2 > 0) + getout = true; // endpoint is not in solid + if (d1 > 0) + startout = true; + + // if completely in front of face, no intersection + if (d1 > 0 && d2 >= d1) + return; + + if (d1 <= 0 && d2 <= 0) + continue; + + // crosses face + if (d1 > d2) + { // enter + f = (d1) / (d1-d2); + if (f > enterfrac) + { + enterfrac = f; + nearfrac = (d1-DIST_EPSILON) / (d1-d2); + clipplane = plane; +// leadside = side; + } + } + else + { // leave + f = (d1) / (d1-d2); + if (f < leavefrac) + leavefrac = f; + } + } + + //bevel the brush axially (to match the player's bbox), in case that wasn't already done + for (i=0, plane = bboxplanes; i<6 ; i++, plane++) + { + if (i < 3) + { //positive normal + dist = trmins[i]; + plane->dist = plmaxs[i]; + dist = plane->dist - dist; + d1 = p1[i] - dist; + d2 = p2[i] - dist; + } + else + { //negative normal + j = i-3; + dist = -trmaxs[j]; + plane->dist = -plmins[j]; + dist = plane->dist - dist; + d1 = -p1[j] - dist; + d2 = -p2[j] - dist; + } + + if (d2 > 0) + getout = true; // endpoint is not in solid + if (d1 > 0) + startout = true; + + // if completely in front of face, no intersection + if (d1 > 0 && d2 >= d1) + return; + + if (d1 <= 0 && d2 <= 0) + continue; + + // crosses face + if (d1 > d2) + { // enter + f = (d1) / (d1-d2); + if (f > enterfrac) + { + enterfrac = f; + nearfrac = (d1-DIST_EPSILON) / (d1-d2); + clipplane = plane; +// leadside = side; + } + } + else + { // leave + f = (d1) / (d1-d2); + if (f < leavefrac) + leavefrac = f; + } + } + + if (!startout) + { // original point was inside brush + trace->startsolid = true; + if (!getout) + trace->allsolid = true; + return; + } + if (enterfrac <= leavefrac) + { + if (enterfrac > -1 && enterfrac <= trace_truefraction) + { + if (enterfrac < 0) + enterfrac = 0; + + trace_nearfraction = nearfrac; + trace_truefraction = enterfrac; + + trace->plane.dist = clipplane->dist; + VectorCopy(clipplane->normal, trace->plane.normal); + trace->surface = surf; + trace->contents = surf->value; + } + } +} +static void Mod_Trace_Trisoup_(vecV_t *posedata, index_t *indexes, size_t numindexes, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, trace_t *trace, q2csurface_t *surf) +{ + size_t i; + int j; + float *p1, *p2, *p3; + vec3_t edge1, edge2, edge3; + mplane_t planes[5]; + vec3_t tmins, tmaxs; + + for (i = 0; i < numindexes; i+=3) + { + p1 = posedata[indexes[i+0]]; + p2 = posedata[indexes[i+1]]; + p3 = posedata[indexes[i+2]]; + + //determine the triangle extents, and skip the triangle if we're completely out of bounds + for (j = 0; j < 3; j++) + { + tmins[j] = p1[j]; + if (tmins[j] > p2[j]) + tmins[j] = p2[j]; + if (tmins[j] > p3[j]) + tmins[j] = p3[j]; + if (trace_absmaxs[j]+(1/8.f) < tmins[j]) + break; + tmaxs[j] = p1[j]; + if (tmaxs[j] < p2[j]) + tmaxs[j] = p2[j]; + if (tmaxs[j] < p3[j]) + tmaxs[j] = p3[j]; + if (trace_absmins[j]-(1/8.f) > tmaxs[j]) + break; + } + //skip any triangles which are completely outside the trace bounds + if (j < 3) + continue; + + VectorSubtract(p1, p2, edge1); + VectorSubtract(p3, p2, edge2); + VectorSubtract(p1, p3, edge3); + CrossProduct(edge1, edge2, planes[0].normal); + VectorNormalize(planes[0].normal); + planes[0].dist = DotProduct(p1, planes[0].normal); + VectorNegate(planes[0].normal, planes[1].normal); + planes[1].dist = -planes[0].dist + 4; + + //determine edges + //FIXME: use adjacency info + CrossProduct(edge1, planes[0].normal, planes[2].normal); + VectorNormalize(planes[2].normal); + planes[2].dist = DotProduct(p2, planes[2].normal); + + CrossProduct(planes[0].normal, edge2, planes[3].normal); + VectorNormalize(planes[3].normal); + planes[3].dist = DotProduct(p3, planes[3].normal); + + CrossProduct(planes[0].normal, edge3, planes[4].normal); + VectorNormalize(planes[4].normal); + planes[4].dist = DotProduct(p1, planes[4].normal); + + CM_ClipBoxToPlanes(mins, maxs, start, end, trace, tmins, tmaxs, planes, 5, surf); + } +} + +static void CM_ClipBoxToMesh (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, trace_t *trace, mesh_t *mesh) +{ + trace_truefraction = trace->truefraction; + trace_nearfraction = trace->fraction; + Mod_Trace_Trisoup_(mesh->xyz_array, mesh->indexes, mesh->numindexes, p1, p2, mins, maxs, trace, &nullsurface.c); + trace->truefraction = trace_truefraction; + trace->fraction = trace_nearfraction; +} + +static void CM_ClipBoxToPatch (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, trace_t *trace, q2cbrush_t *brush) { int i, j; @@ -4848,8 +5164,6 @@ void CM_ClipBoxToPatch (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, if (!brush->numsides) return; - c_brush_traces++; - enterfrac = -1; leavefrac = 2; clipplane = NULL; @@ -4946,7 +5260,7 @@ void CM_ClipBoxToPatch (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, CM_TestBoxInBrush ================ */ -void CM_TestBoxInBrush (vec3_t mins, vec3_t maxs, vec3_t p1, +static void CM_TestBoxInBrush (vec3_t mins, vec3_t maxs, vec3_t p1, trace_t *trace, q2cbrush_t *brush) { int i, j; @@ -4993,7 +5307,7 @@ void CM_TestBoxInBrush (vec3_t mins, vec3_t maxs, vec3_t p1, trace->contents |= brush->contents; } -void CM_TestBoxInPatch (vec3_t mins, vec3_t maxs, vec3_t p1, +static void CM_TestBoxInPatch (vec3_t mins, vec3_t maxs, vec3_t p1, trace_t *trace, q2cbrush_t *brush) { int i, j; @@ -5054,24 +5368,21 @@ void CM_TestBoxInPatch (vec3_t mins, vec3_t maxs, vec3_t p1, CM_TraceToLeaf ================ */ -void CM_TraceToLeaf (int leafnum) +static void CM_TraceToLeaf (mleaf_t *leaf) { int k, j; - int brushnum; - mleaf_t *leaf; q2cbrush_t *b; int patchnum; q3cpatch_t *patch; + q3cmesh_t *cmesh; - leaf = &map_leafs[leafnum]; if ( !(leaf->contents & trace_contents)) return; // trace line against all brushes in the leaf for (k=0 ; knumleafbrushes ; k++) { - brushnum = map_leafbrushes[leaf->firstleafbrush+k]; - b = &map_brushes[brushnum]; + b = map_leafbrushes[leaf->firstleafbrush+k]; if (b->checkcount == checkcount) continue; // already checked this brush in another leaf b->checkcount = checkcount; @@ -5107,6 +5418,22 @@ void CM_TraceToLeaf (int leafnum) } } + for (k = 0; k < leaf->numleafcmeshes; k++) + { + patchnum = map_leafcmeshes[leaf->firstleafcmesh+k]; + cmesh = &map_cmeshes[patchnum]; + if (cmesh->checkcount == checkcount) + continue; // already checked this patch in another leaf + cmesh->checkcount = checkcount; + if ( !(cmesh->surface->c.value & trace_contents) ) + continue; + if ( !BoundsIntersect(cmesh->absmins, cmesh->absmaxs, trace_absmins, trace_absmaxs) ) + continue; + + Mod_Trace_Trisoup_(cmesh->xyz_array, cmesh->indicies, cmesh->numincidies, trace_start, trace_end, trace_mins, trace_maxs, &trace_trace, &cmesh->surface->c); + if (trace_nearfraction<=0) + return; + } } @@ -5115,23 +5442,20 @@ void CM_TraceToLeaf (int leafnum) CM_TestInLeaf ================ */ -void CM_TestInLeaf (int leafnum) +static void CM_TestInLeaf (mleaf_t *leaf) { int k, j; - int brushnum; int patchnum; - mleaf_t *leaf; q2cbrush_t *b; + q3cmesh_t *cmesh; q3cpatch_t *patch; - leaf = &map_leafs[leafnum]; if ( !(leaf->contents & trace_contents)) return; // trace line against all brushes in the leaf for (k=0 ; knumleafbrushes ; k++) { - brushnum = map_leafbrushes[leaf->firstleafbrush+k]; - b = &map_brushes[brushnum]; + b = map_leafbrushes[leaf->firstleafbrush+k]; if (b->checkcount == checkcount) continue; // already checked this brush in another leaf b->checkcount = checkcount; @@ -5167,6 +5491,22 @@ void CM_TestInLeaf (int leafnum) } } + for (k = 0; k < leaf->numleafcmeshes; k++) + { + patchnum = map_leafcmeshes[leaf->firstleafcmesh+k]; + cmesh = &map_cmeshes[patchnum]; + if (cmesh->checkcount == checkcount) + continue; // already checked this patch in another leaf + cmesh->checkcount = checkcount; + if ( !(cmesh->surface->c.value & trace_contents) ) + continue; + if ( !BoundsIntersect(cmesh->absmins, cmesh->absmaxs, trace_absmins, trace_absmaxs) ) + continue; + + Mod_Trace_Trisoup_(cmesh->xyz_array, cmesh->indicies, cmesh->numincidies, trace_start, trace_end, trace_mins, trace_maxs, &trace_trace, &cmesh->surface->c); + if (trace_nearfraction<=0) + return; + } } @@ -5176,7 +5516,7 @@ CM_RecursiveHullCheck ================== */ -void CM_RecursiveHullCheck (model_t *mod, int num, float p1f, float p2f, vec3_t p1, vec3_t p2) +static void CM_RecursiveHullCheck (model_t *mod, int num, float p1f, float p2f, vec3_t p1, vec3_t p2) { mnode_t *node; mplane_t *plane; @@ -5194,7 +5534,7 @@ void CM_RecursiveHullCheck (model_t *mod, int num, float p1f, float p2f, vec3_t // if < 0, we are in a leaf node if (num < 0) { - CM_TraceToLeaf (-1-num); + CM_TraceToLeaf (&mod->leafs[-1-num]); return; } @@ -5298,26 +5638,22 @@ return; CM_BoxTrace ================== */ -trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, +static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int brushmask) { int i; -#if ADJ - int moved; -#endif vec3_t point; checkcount++; // for multi-check avoidance - c_traces++; // for statistics, may be zeroed - // fill in a default trace memset (&trace_trace, 0, sizeof(trace_trace)); trace_truefraction = 1; trace_nearfraction = 1; trace_trace.fraction = 1; + trace_trace.truefraction = 1; trace_trace.surface = &(nullsurface.c); if (!mod) // map not loaded @@ -5340,6 +5676,21 @@ trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, VectorAdd (end, trace_maxs, point); AddPointToBounds (point, trace_absmins, trace_absmaxs); + if (0) + { //treat *ALL* tests against the actual geometry instead of using any brushes. + //also ignores the bsp etc. not fast. testing only. + for (i = 0; i < mod->numsurfaces; i++) + { + CM_ClipBoxToMesh(trace_mins, trace_maxs, trace_start, trace_end, &trace_trace, mod->surfaces[i].mesh); + } + } + else + if (0) + { + for (i = 0; i < mod->numleafs; i++) + CM_TraceToLeaf(&mod->leafs[i]); + } + else // // check for position test special case // @@ -5349,21 +5700,6 @@ trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, int i, numleafs; vec3_t c1, c2; int topnode; -#if ADJ - if (-mins[2] != maxs[2]) //be prepared to move the thing up to counter the different min/max - { - moved = (trace_maxs[2] - trace_mins[2])/2; - trace_mins[2] = -moved; - trace_maxs[2] = moved; - trace_extents[2] = -trace_mins[2] > trace_maxs[2] ? -trace_mins[2] : trace_maxs[2]; - moved = (maxs[2] - trace_maxs[2]); - } - - trace_start[2]+=moved; - trace_end[2]+=moved; -#endif - - VectorAdd (start, mins, c1); VectorAdd (start, maxs, c2); @@ -5376,54 +5712,35 @@ trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, numleafs = CM_BoxLeafnums_headnode (mod, c1, c2, leafs, sizeof(leafs)/sizeof(leafs[0]), mod->hulls[0].firstclipnode, &topnode); for (i=0 ; ileafs[leafs[i]]); if (trace_trace.allsolid) break; } VectorCopy (start, trace_trace.endpos); -#if ADJ - trace_trace.endpos[2] -= moved; -#endif return trace_trace; } -#if ADJ - moved = 0; -#endif // // check for point special case // - if (trace_mins[0] == 0 && trace_mins[1] == 0 && trace_mins[2] == 0 + else if (trace_mins[0] == 0 && trace_mins[1] == 0 && trace_mins[2] == 0 && trace_maxs[0] == 0 && trace_maxs[1] == 0 && trace_maxs[2] == 0) { trace_ispoint = true; VectorClear (trace_extents); + CM_RecursiveHullCheck (mod, mod->hulls[0].firstclipnode, 0, 1, trace_start, trace_end); } + // + // general aabb trace + // else { trace_ispoint = false; - trace_extents[0] = -trace_mins[0] > trace_maxs[0] ? -trace_mins[0] : trace_maxs[0]+1; - trace_extents[1] = -trace_mins[1] > trace_maxs[1] ? -trace_mins[1] : trace_maxs[1]+1; - trace_extents[2] = -trace_mins[2] > trace_maxs[2] ? -trace_mins[2] : trace_maxs[2]+1; -#if ADJ - if (-mins[2] != maxs[2]) //be prepared to move the thing up to counter the different min/max - { - moved = (trace_maxs[2] - trace_mins[2])/2; - trace_mins[2] = -moved; - trace_maxs[2] = moved; - trace_extents[2] = -trace_mins[2] > trace_maxs[2] ? -trace_mins[2] : trace_maxs[2]; - moved = (maxs[2] - trace_maxs[2]); - } - - trace_start[2]+=moved; - trace_end[2]+=moved; -#endif + trace_extents[0] = ((-trace_mins[0] > trace_maxs[0]) ? -trace_mins[0] : trace_maxs[0])+1; + trace_extents[1] = ((-trace_mins[1] > trace_maxs[1]) ? -trace_mins[1] : trace_maxs[1])+1; + trace_extents[2] = ((-trace_mins[2] > trace_maxs[2]) ? -trace_mins[2] : trace_maxs[2])+1; + CM_RecursiveHullCheck (mod, mod->hulls[0].firstclipnode, 0, 1, trace_start, trace_end); } - // - // general sweeping through world - // - CM_RecursiveHullCheck (mod, mod->hulls[0].firstclipnode, 0, 1, trace_start, trace_end); - if (trace_nearfraction == 1) { trace_trace.fraction = 1; @@ -5437,13 +5754,10 @@ trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, for (i=0 ; i<3 ; i++) trace_trace.endpos[i] = trace_start[i] + trace_trace.fraction * (trace_end[i] - trace_start[i]); } -#if ADJ - trace_trace.endpos[2] -= moved; -#endif return trace_trace; } -qboolean CM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int contents, trace_t *trace) +static qboolean CM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int contents, trace_t *trace) { if (axis) { @@ -5998,7 +6312,7 @@ qboolean CM_HeadnodeVisible (model_t *mod, int nodenum, qbyte *visbits) if (nodenum < 0) { leafnum = -1-nodenum; - cluster = map_leafs[leafnum].cluster; + cluster = mod->leafs[leafnum].cluster; if (cluster == -1) return false; if (visbits[cluster>>3] & (1<<(cluster&7))) @@ -6012,15 +6326,6 @@ qboolean CM_HeadnodeVisible (model_t *mod, int nodenum, qbyte *visbits) return CM_HeadnodeVisible(mod, node->childnum[1], visbits); } -/* -qboolean Q2BSP_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace) -{ - trace_t ret = CM_BoxTrace(p1, p2, hull->clip_mins, hull->clip_maxs, hull->firstclipnode, MASK_SOLID); - memcpy(trace, &ret, sizeof(trace_t)); - if (ret.fraction==1) - return true; - return false; -}*/ unsigned int Q2BSP_PointContents(model_t *mod, vec3_t axis[3], vec3_t p) { int pc; @@ -6047,6 +6352,8 @@ void CM_Init(void) //register cvars. Cvar_Register(&map_noareas, MAPOPTIONS); Cvar_Register(&map_noCurves, MAPOPTIONS); Cvar_Register(&map_autoopenportals, MAPOPTIONS); + Cvar_Register(&q3bsp_surf_meshcollision_flag, MAPOPTIONS); + Cvar_Register(&q3bsp_surf_meshcollision_force, MAPOPTIONS); Cvar_Register(&r_subdivisions, MAPOPTIONS); } void CM_Shutdown(void) diff --git a/engine/common/huff.c b/engine/common/huff.c index 5de6f307e..f4ea32c04 100644 --- a/engine/common/huff.c +++ b/engine/common/huff.c @@ -1,48 +1,499 @@ /* -Q3Fusion - Quake III Clone Engine +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2003 Andrey Nazarov +This file is part of Quake III Arena source code. -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +along with Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== */ -// -// huff.c - Huffman compression routines for data bitstream -// +/* This is based on the Adaptive Huffman algorithm described in Sayood's Data + * Compression book. The ranks are not actually stored, but implicitly defined + * by the location of a node within a doubly-linked list */ #include "quakedef.h" + #ifdef HUFFNETWORK +#define NYT HMAX /* NYT = Not Yet Transmitted */ +#define INTERNAL_NODE (HMAX+1) + +typedef struct nodetype { + struct nodetype *left, *right, *parent; /* tree structure */ + struct nodetype *next, *prev; /* doubly-linked list */ + struct nodetype **head; /* highest ranked node in block */ + int weight; + int symbol; +} node_t; + +#define HMAX 256 /* Maximum symbol */ + +typedef struct { + int blocNode; + int blocPtrs; + + node_t* tree; + node_t* lhead; + node_t* ltail; + node_t* loc[HMAX+1]; + node_t** freelist; + + node_t nodeList[768]; + node_t* nodePtrs[768]; +} huff_t; + +struct huffman_s{ + int counts[256]; + unsigned int crc; + qboolean built; + + huff_t compressor; + huff_t decompressor; +}; extern cvar_t net_compress; -#define ID_INLINE -#define VALUE(a) (*(size_t *)&(a)) -#define NODE(a) ((void*)((size_t)a)) +static int bloc = 0; +/* +static void Huff_putBit( int bit, qbyte *fout, int *offset) { + bloc = *offset; + if ((bloc&7) == 0) { + fout[(bloc>>3)] = 0; + } + fout[(bloc>>3)] |= bit << (bloc&7); + bloc++; + *offset = bloc; +} -#define NODE_START NODE( 1) -#define NODE_NONE NODE(256) -#define NODE_NEXT NODE(257) +static int Huff_getBloc(void) +{ + return bloc; +} -#define NOT_REFERENCED 256 +static void Huff_setBloc(int _bloc) +{ + bloc = _bloc; +} +*/ +int Huff_getBit( qbyte *fin, int *offset) { + int t; + bloc = *offset; + t = (fin[(bloc>>3)] >> (bloc&7)) & 0x1; + bloc++; + *offset = bloc; + return t; +} -#define HUFF_TREE_SIZE 7175 -typedef void *tree_t[HUFF_TREE_SIZE]; +/* Add a bit to the output file (buffered) */ +static void huff_add_bit (char bit, qbyte *fout) { + if ((bloc&7) == 0) { + fout[(bloc>>3)] = 0; + } + fout[(bloc>>3)] |= bit << (bloc&7); + bloc++; +} -// -// pre-defined frequency counts for all bytes [0..255] -// -static int q3huffCounts[256] = { +/* Receive one bit from the input file (buffered) */ +static int huff_get_bit (qbyte *fin) { + int t; + t = (fin[(bloc>>3)] >> (bloc&7)) & 0x1; + bloc++; + return t; +} + +static node_t **huff_get_ppnode(huff_t* huff) { + node_t **tppnode; + if (!huff->freelist) { + return &(huff->nodePtrs[huff->blocPtrs++]); + } else { + tppnode = huff->freelist; + huff->freelist = (node_t **)*tppnode; + return tppnode; + } +} + +static void huff_free_ppnode(huff_t* huff, node_t **ppnode) { + *ppnode = (node_t *)huff->freelist; + huff->freelist = ppnode; +} + +/* Swap the location of these two nodes in the tree */ +static void huff_swap (huff_t* huff, node_t *node1, node_t *node2) { + node_t *par1, *par2; + + par1 = node1->parent; + par2 = node2->parent; + + if (par1) { + if (par1->left == node1) { + par1->left = node2; + } else { + par1->right = node2; + } + } else { + huff->tree = node2; + } + + if (par2) { + if (par2->left == node2) { + par2->left = node1; + } else { + par2->right = node1; + } + } else { + huff->tree = node1; + } + + node1->parent = par2; + node2->parent = par1; +} + +/* Swap these two nodes in the linked list (update ranks) */ +static void huff_swaplist(node_t *node1, node_t *node2) { + node_t *par1; + + par1 = node1->next; + node1->next = node2->next; + node2->next = par1; + + par1 = node1->prev; + node1->prev = node2->prev; + node2->prev = par1; + + if (node1->next == node1) { + node1->next = node2; + } + if (node2->next == node2) { + node2->next = node1; + } + if (node1->next) { + node1->next->prev = node1; + } + if (node2->next) { + node2->next->prev = node2; + } + if (node1->prev) { + node1->prev->next = node1; + } + if (node2->prev) { + node2->prev->next = node2; + } +} + +/* Do the increments */ +static void huff_increment(huff_t* huff, node_t *node) { + node_t *lnode; + + if (!node) { + return; + } + + if (node->next != NULL && node->next->weight == node->weight) { + lnode = *node->head; + if (lnode != node->parent) { + huff_swap(huff, lnode, node); + } + huff_swaplist(lnode, node); + } + if (node->prev && node->prev->weight == node->weight) { + *node->head = node->prev; + } else { + *node->head = NULL; + huff_free_ppnode(huff, node->head); + } + node->weight++; + if (node->next && node->next->weight == node->weight) { + node->head = node->next->head; + } else { + node->head = huff_get_ppnode(huff); + *node->head = node; + } + if (node->parent) { + huff_increment(huff, node->parent); + if (node->prev == node->parent) { + huff_swaplist(node, node->parent); + if (*node->head == node) { + *node->head = node->parent; + } + } + } +} + +static void Huff_addRef(huff_t* huff, qbyte ch) { + node_t *tnode, *tnode2; + if (huff->loc[ch] == NULL) { /* if this is the first transmission of this node */ + tnode = &(huff->nodeList[huff->blocNode++]); + tnode2 = &(huff->nodeList[huff->blocNode++]); + + tnode2->symbol = INTERNAL_NODE; + tnode2->weight = 1; + tnode2->next = huff->lhead->next; + if (huff->lhead->next) { + huff->lhead->next->prev = tnode2; + if (huff->lhead->next->weight == 1) { + tnode2->head = huff->lhead->next->head; + } else { + tnode2->head = huff_get_ppnode(huff); + *tnode2->head = tnode2; + } + } else { + tnode2->head = huff_get_ppnode(huff); + *tnode2->head = tnode2; + } + huff->lhead->next = tnode2; + tnode2->prev = huff->lhead; + + tnode->symbol = ch; + tnode->weight = 1; + tnode->next = huff->lhead->next; + if (huff->lhead->next) { + huff->lhead->next->prev = tnode; + if (huff->lhead->next->weight == 1) { + tnode->head = huff->lhead->next->head; + } else { + /* this should never happen */ + tnode->head = huff_get_ppnode(huff); + *tnode->head = tnode2; + } + } else { + /* this should never happen */ + tnode->head = huff_get_ppnode(huff); + *tnode->head = tnode; + } + huff->lhead->next = tnode; + tnode->prev = huff->lhead; + tnode->left = tnode->right = NULL; + + if (huff->lhead->parent) { + if (huff->lhead->parent->left == huff->lhead) { /* lhead is guaranteed to by the NYT */ + huff->lhead->parent->left = tnode2; + } else { + huff->lhead->parent->right = tnode2; + } + } else { + huff->tree = tnode2; + } + + tnode2->right = tnode; + tnode2->left = huff->lhead; + + tnode2->parent = huff->lhead->parent; + huff->lhead->parent = tnode->parent = tnode2; + + huff->loc[ch] = tnode; + + huff_increment(huff, tnode2->parent); + } else { + huff_increment(huff, huff->loc[ch]); + } +} + +/* Get a symbol */ +static int Huff_Receive (node_t *node, int *ch, qbyte *fin) { + while (node && node->symbol == INTERNAL_NODE) { + if (huff_get_bit(fin)) { + node = node->right; + } else { + node = node->left; + } + } + if (!node) { + return 0; +// Com_Error(ERR_DROP, "Illegal tree!"); + } + return (*ch = node->symbol); +} + +/* Get a symbol */ +static void Huff_offsetReceive (node_t *node, int *ch, qbyte *fin, int *offset) { + bloc = *offset; + while (node && node->symbol == INTERNAL_NODE) { + if (huff_get_bit(fin)) { + node = node->right; + } else { + node = node->left; + } + } + if (!node) { + *ch = 0; + return; +// Com_Error(ERR_DROP, "Illegal tree!"); + } + *ch = node->symbol; + *offset = bloc; +} + +/* Send the prefix code for this node */ +static void huff_send(node_t *node, node_t *child, qbyte *fout) { + if (node->parent) { + huff_send(node->parent, node, fout); + } + if (child) { + if (node->right == child) { + huff_add_bit(1, fout); + } else { + huff_add_bit(0, fout); + } + } +} + +/* Send a symbol */ +static void Huff_transmit (huff_t *huff, int ch, qbyte *fout) { + int i; + if (huff->loc[ch] == NULL) { + /* node_t hasn't been transmitted, send a NYT, then the symbol */ + Huff_transmit(huff, NYT, fout); + for (i = 7; i >= 0; i--) { + huff_add_bit((char)((ch >> i) & 0x1), fout); + } + } else { + huff_send(huff->loc[ch], NULL, fout); + } +} + +static void Huff_offsetTransmit (huff_t *huff, int ch, qbyte *fout, int *offset) { + bloc = *offset; + huff_send(huff->loc[ch], NULL, fout); + *offset = bloc; +} + +static void Huff_Decompress(sizebuf_t *mbuf, int offset) { + int ch, cch, i, j, size; + qbyte seq[65536]; + qbyte* buffer; + huff_t huff; + + size = mbuf->cursize - offset; + buffer = mbuf->data + offset; + + if ( size <= 0 ) { + return; + } + + memset(&huff, 0, sizeof(huff_t)); + // Initialize the tree & list with the NYT node + huff.tree = huff.lhead = huff.ltail = huff.loc[NYT] = &(huff.nodeList[huff.blocNode++]); + huff.tree->symbol = NYT; + huff.tree->weight = 0; + huff.lhead->next = huff.lhead->prev = NULL; + huff.tree->parent = huff.tree->left = huff.tree->right = NULL; + + cch = buffer[0]*256 + buffer[1]; + // don't overflow with bad messages + if ( cch > mbuf->maxsize - offset ) { + cch = mbuf->maxsize - offset; + } + bloc = 16; + + for ( j = 0; j < cch; j++ ) { + ch = 0; + // don't overflow reading from the messages + // FIXME: would it be better to have an overflow check in get_bit ? + if ( (bloc >> 3) > size ) { + seq[j] = 0; + break; + } + Huff_Receive(huff.tree, &ch, buffer); /* Get a character */ + if ( ch == NYT ) { /* We got a NYT, get the symbol associated with it */ + ch = 0; + for ( i = 0; i < 8; i++ ) { + ch = (ch<<1) + huff_get_bit(buffer); + } + } + + seq[j] = ch; /* Write symbol */ + + Huff_addRef(&huff, (qbyte)ch); /* Increment node */ + } + mbuf->cursize = cch + offset; + memcpy(mbuf->data + offset, seq, cch); +} + +static void Huff_Compress(sizebuf_t *mbuf, int offset) { + int i, ch, size; + qbyte seq[65536]; + qbyte* buffer; + huff_t huff; + + size = mbuf->cursize - offset; + buffer = mbuf->data+ + offset; + + if (size<=0) { + return; + } + + memset(&huff, 0, sizeof(huff_t)); + // Add the NYT (not yet transmitted) node into the tree/list */ + huff.tree = huff.lhead = huff.loc[NYT] = &(huff.nodeList[huff.blocNode++]); + huff.tree->symbol = NYT; + huff.tree->weight = 0; + huff.lhead->next = huff.lhead->prev = NULL; + huff.tree->parent = huff.tree->left = huff.tree->right = NULL; + + seq[0] = (size>>8); + seq[1] = size&0xff; + + bloc = 16; + + for (i=0; icursize = (bloc>>3) + offset; + memcpy(mbuf->data+offset, seq, (bloc>>3)); +} + +static void Huff_Init(huffman_t *huff) +{ + int i, j; + + memset(&huff->compressor, 0, sizeof(huff_t)); + memset(&huff->decompressor, 0, sizeof(huff_t)); + + // Initialize the tree & list with the NYT node + huff->decompressor.tree = huff->decompressor.lhead = huff->decompressor.ltail = huff->decompressor.loc[NYT] = &(huff->decompressor.nodeList[huff->decompressor.blocNode++]); + huff->decompressor.tree->symbol = NYT; + huff->decompressor.tree->weight = 0; + huff->decompressor.lhead->next = huff->decompressor.lhead->prev = NULL; + huff->decompressor.tree->parent = huff->decompressor.tree->left = huff->decompressor.tree->right = NULL; + + // Add the NYT (not yet transmitted) node into the tree/list */ + huff->compressor.tree = huff->compressor.lhead = huff->compressor.loc[NYT] = &(huff->compressor.nodeList[huff->compressor.blocNode++]); + huff->compressor.tree->symbol = NYT; + huff->compressor.tree->weight = 0; + huff->compressor.lhead->next = huff->compressor.lhead->prev = NULL; + huff->compressor.tree->parent = huff->compressor.tree->left = huff->compressor.tree->right = NULL; + + for(i=0;i<256;i++) + { + for (j=0;jcounts[i];j++) + { + Huff_addRef(&huff->compressor, (qbyte)i); + Huff_addRef(&huff->decompressor, (qbyte)i); + } + } +} + + + + +static huffman_t q3huff = +{ + { 0x3D1CB, 0x0A0E9, 0x01894, 0x01BC2, 0x00E92, 0x00EA6, 0x017DE, 0x05AF3, 0x08225, 0x01B26, 0x01E9E, 0x025F2, 0x02429, 0x0436B, 0x00F6D, 0x006F2, 0x02060, 0x00644, 0x00636, 0x0067F, 0x0044C, 0x004BD, 0x004D6, 0x0046E, @@ -75,718 +526,51 @@ static int q3huffCounts[256] = { 0x01E6F, 0x003BA, 0x00509, 0x003A5, 0x00467, 0x00C87, 0x003FC, 0x0039F, 0x0054B, 0x00300, 0x00410, 0x002E9, 0x003B8, 0x00325, 0x00431, 0x002E4, 0x003F5, 0x00325, 0x003F0, 0x0031C, 0x003E4, 0x00421, 0x02CC1, 0x034C0 + }, + 0x286f2e8d }; -static int countinghuffCounts[256]; - - -// -// static Huffman tree -// -static tree_t huffTree; - -// -// received from MSG_* code -// -static int huffBitPos; - - -/* -======================================================================================= - - HUFFMAN TREE CONSTRUCTION - -======================================================================================= -*/ - -/* -============ -Huff_PrepareTree -============ -*/ -static ID_INLINE void Huff_PrepareTree(tree_t tree) -{ - void **node; - - memset(tree, 0, sizeof(tree_t)); - - // create first node - node = &tree[263]; - tree[0] = (void*)(VALUE(tree[0])+1); - - node[7] = NODE_NONE; - tree[2] = node; - tree[3] = node; - tree[4] = node; - tree[261] = node; -} - - - -/* -============ -Huff_GetNode -============ -*/ -static ID_INLINE void **Huff_GetNode(void **tree) -{ - void **node; - int value; - - node = (void**)tree[262]; - if (!node) - { - value = VALUE(tree[1])++; - node = &tree[value + 6407]; - return node; - } - - tree[262] = node[0]; - return node; -} - -/* -============ -Huff_Swap -============ -*/ -static ID_INLINE void Huff_Swap(void **tree1, void **tree2, void **tree3) -{ - void **a, **b; - - a = (void**)tree2[2]; - if (a) - { - if (a[0] == tree2) - a[0] = tree3; - else - a[1] = tree3; - } - else - tree1[2] = tree3; - - b = (void**)tree3[2]; - - if (b) - { - if (b[0] == tree3) - { - b[0] = tree2; - tree2[2] = b; - tree3[2] = a; - return; - } - - b[1] = tree2; - tree2[2] = b; - tree3[2] = a; - return; - } - - tree1[2] = tree2; - tree2[2] = NULL; - tree3[2] = a; -} - -/* -============ -Huff_SwapTrees -============ -*/ -static ID_INLINE void Huff_SwapTrees(void **tree1, void **tree2) -{ - void **temp; - - temp = (void**)tree1[3]; - tree1[3] = tree2[3]; - tree2[3] = temp; - - temp = (void**)tree1[4]; - tree1[4] = tree2[4]; - tree2[4] = temp; - - if (tree1[3] == tree1) - tree1[3] = tree2; - - if (tree2[3] == tree2) - tree2[3] = tree1; - - temp = (void**)tree1[3]; - if (temp) - temp[4] = tree1; - - temp = (void**)tree2[3]; - if (temp) - temp[4] = tree2; - - temp = (void**)tree1[4]; - if (temp) - temp[3] = tree1; - - temp = (void**)tree2[4]; - if (temp) - temp[3] = tree2; - -} - -/* -============ -Huff_DeleteNode -============ -*/ -static ID_INLINE void Huff_DeleteNode(void **tree1, void **tree2) -{ - tree2[0] = tree1[262]; - tree1[262] = tree2; -} - -/* -============ -Huff_IncrementFreq_r -============ -*/ -static void Huff_IncrementFreq_r(void **tree1, void **tree2) -{ - void **a, **b; - - if (!tree2) - { - return; - } - - a = (void**)tree2[3]; - if (a) - { - a = (void**)a[6]; - if (a == tree2[6]) - { - b = (void**)tree2[5]; - if (b[0] != tree2[2]) - { - Huff_Swap(tree1, (void**)b[0], tree2); - } - Huff_SwapTrees((void**)b[0], tree2); - } - } - - a = (void**)tree2[4]; - if (a && a[6] == tree2[6]) - { - b = (void**)tree2[5]; - b[0] = a; - } - else - { - a = (void**)tree2[5]; - a[0] = 0; - Huff_DeleteNode(tree1, (void**)tree2[5]); - } - - - VALUE(tree2[6])++; - a = (void**)tree2[3]; - if (a && a[6] == tree2[6]) - { - tree2[5] = a[5]; - } - else - { - a = Huff_GetNode(tree1); - tree2[5] = a; - a[0] = tree2; - } - - if (tree2[2]) - { - Huff_IncrementFreq_r(tree1, (void**)tree2[2]); - - if (tree2[4] == tree2[2]) - { - Huff_SwapTrees(tree2, (void**)tree2[2]); - a = (void**)tree2[5]; - - if (a[0] == tree2) - { - a[0] = (void**)tree2[2]; - } - } - } -} - -/* -============ -Huff_AddReference - -Insert 'ch' into the tree or increment it's frequency -============ -*/ -static void Huff_AddReference(void **tree, int ch) -{ - void **a, **b, **c, **d; - int value; - - ch &= 255; - if (tree[ch + 5]) - { - Huff_IncrementFreq_r(tree, (void**)tree[ch + 5]); - return; // already added - } - - value = VALUE(tree[0])++; - b = &tree[value * 8 + 263]; - - value = VALUE(tree[0])++; - a = &tree[value * 8 + 263]; - - a[7] = NODE_NEXT; - a[6] = NODE_START; - d = (void**)tree[3]; - a[3] = d[3]; - if (a[3]) - { - d = (void**)a[3]; - d[4] = a; - d = (void**)a[3]; - if (d[6] == NODE_START) - { - a[5] = d[5]; - } - else - { - d = Huff_GetNode(tree); - a[5] = d; - d[0] = a; - } - } - else - { - d = Huff_GetNode(tree); - a[5] = d; - d[0] = a; - - } - - d = (void**)tree[3]; - d[3] = a; - a[4] = (void**)tree[3]; - b[7] = NODE(ch); - b[6] = NODE_START; - d = (void**)tree[3]; - b[3] = d[3]; - if (b[3]) - { - d = (void**)b[3]; - d[4] = b; - if (d[6] == NODE_START) - { - b[5] = d[5]; - } - else - { - d = Huff_GetNode(tree); - b[5] = d; - d[0] = a; - } - } - else - { - d = Huff_GetNode(tree); - b[5] = d; - d[0] = b; - } - - d = (void**)tree[3]; - d[3] = b; - b[4] = (void**)tree[3]; - b[1] = NULL; - b[0] = NULL; - d = (void**)tree[3]; - c = (void**)d[2]; - if (c) - { - if (c[0] == tree[3]) - { - c[0] = a; - } - else - { - c[1] = a; - } - } - else - { - tree[2] = a; - } - - a[1] = b; - d = (void**)tree[3]; - a[0] = d; - a[2] = d[2]; - b[2] = a; - d = (void**)tree[3]; - d[2] = a; - tree[ch + 5] = b; - - Huff_IncrementFreq_r(tree, (void**)a[2]); -} - -/* -======================================================================================= - - BITSTREAM I/O - -======================================================================================= -*/ - -/* -============ -Huff_EmitBit - -Put one bit into buffer -============ -*/ -static ID_INLINE void Huff_EmitBit(int bit, qbyte *buffer) -{ - if (!(huffBitPos & 7)) - { - buffer[huffBitPos >> 3] = 0; - } - - buffer[huffBitPos >> 3] |= bit << (huffBitPos & 7); - huffBitPos++; -} - -/* -============ -Huff_GetBit - -Read one bit from buffer -============ -*/ -static ID_INLINE int Huff_GetBit(qbyte *buffer) -{ - int bit; - - bit = buffer[huffBitPos >> 3] >> (huffBitPos & 7); - huffBitPos++; - - return (bit & 1); -} - -/* -============ -Huff_EmitPathToByte -============ -*/ -static ID_INLINE void Huff_EmitPathToByte(void **tree, void **subtree, qbyte *buffer) -{ - if (tree[2]) - { - Huff_EmitPathToByte((void**)tree[2], tree, buffer); - } - - if (!subtree) - { - return; - } - - // - // emit tree walking control bits - // - if (tree[1] == subtree) - { - Huff_EmitBit(1, buffer); - } - else - { - Huff_EmitBit(0, buffer); - } -} - -/* -============ -Huff_GetByteFromTree - -Get one qbyte using dynamic or static tree -============ -*/ -static ID_INLINE int Huff_GetByteFromTree(void **tree, qbyte *buffer) -{ - if (!tree) - { - return 0; - } - - // - // walk through the tree until we get a value - // - while (tree[7] == NODE_NEXT) - { - if (!Huff_GetBit(buffer)) - { - tree = (void**)tree[0]; - } - else - { - tree = (void**)tree[1]; - } - - if (!tree) - { - return 0; - } - } - - return VALUE(tree[7]); -} - -/* -============ -Huff_EmitByteDynamic - -Emit one qbyte using dynamic tree -============ -*/ -static void Huff_EmitByteDynamic(void **tree, int value, qbyte *buffer) -{ - void **subtree; - int i; - - // - // if qbyte was already referenced, emit path to it - // - subtree = (void**)tree[value + 5]; - if (subtree) - { - if (subtree[2]) - { - Huff_EmitPathToByte((void**)subtree[2], subtree, buffer); - } - return; - } - - // - // qbyte was not referenced, just emit 8 bits - // - Huff_EmitByteDynamic(tree, NOT_REFERENCED, buffer); - - for (i = 7; i >= 0; i--) - { - Huff_EmitBit((value >> i) & 1, buffer); - } - -} - -/* -======================================================================================= - - PUBLIC INTERFACE - -======================================================================================= -*/ - -/* -============ -Huff_CompressPacket - -Compress message using dynamic Huffman tree, -beginning from specified offset -============ -*/ -void Huff_EncryptPacket(sizebuf_t *msg, int offset) -{ - tree_t tree; - qbyte buffer[MAX_OVERALLMSGLEN]; - qbyte *data; - int outLen; - int inLen; - int i; - - data = msg->data + offset; - inLen = msg->cursize - offset; - if (inLen <= 0 || inLen >= MAX_OVERALLMSGLEN) - { - return; - } - - Huff_PrepareTree(tree); - - buffer[0] = inLen >> 8; - buffer[1] = inLen & 0xFF; - huffBitPos = 16; - - for (i = 0; i < inLen; i++) - { - Huff_EmitByteDynamic(tree, data[i], buffer); - Huff_AddReference(tree, data[i]); - } - - outLen = (huffBitPos >> 3) + 1; - - msg->cursize = offset + outLen; - memcpy(data, buffer, outLen); - -} - -/* -============ -Huff_DecompressPacket - -Decompress message using dynamic Huffman tree, -beginning from specified offset -============ -*/ -void Huff_DecryptPacket(sizebuf_t *msg, int offset) -{ - tree_t tree; - qbyte buffer[MAX_OVERALLMSGLEN]; - qbyte *data; - int outLen; - int inLen; - int i, j; - int ch; - - data = msg->data + offset; - inLen = msg->cursize - offset; - if (inLen <= 0) - { - return; - } - - Huff_PrepareTree(tree); - - outLen = (data[0] << 8) + data[1]; - huffBitPos = 16; - - if (outLen > msg->maxsize - offset) - { - outLen = msg->maxsize - offset; - } - - for (i = 0; i < outLen; i++) - { - if ((huffBitPos >> 3) > inLen) - { - buffer[i] = 0; - break; - } - - ch = Huff_GetByteFromTree((void**)tree[2], data); - - if (ch == NOT_REFERENCED) - { - ch = 0; // just read 8 bits - for (j = 0 ; j < 8 ; j++) - { - ch <<= 1; - ch |= Huff_GetBit(data); - } - } - - buffer[i] = ch; - Huff_AddReference(tree, ch); - } - - - msg->cursize = offset + outLen; - memcpy(data, buffer, outLen); -} - -/* -============ -Huff_EmitByte -============ -*/ -void Huff_EmitByte(int ch, qbyte *buffer, int *count) -{ - huffBitPos = *count; - Huff_EmitPathToByte((void**)huffTree[ch + 5], NULL, buffer); - *count = huffBitPos; -} - -/* -============ -Huff_GetByte -============ -*/ -int Huff_GetByte(qbyte *buffer, int *count) -{ - int ch; - - huffBitPos = *count; - ch = Huff_GetByteFromTree((void**)huffTree[2], buffer); - *count = huffBitPos; - - return ch; -} - -static int madetable; -/* -============ -Huff_Init -============ -*/ -void Huff_Init(int *huffCounts) -{ - int i, j; - - if (!huffCounts) - huffCounts = q3huffCounts; - - // build empty tree - Huff_PrepareTree(huffTree); - - // add all pre-defined qbyte references - for (i = 0; i < 256; i++) - { - for (j = 0; j < huffCounts[i]; j++) - { - Huff_AddReference(huffTree, i); - } - huffCounts[i] = LittleLong(huffCounts[i]); - } - madetable=Com_BlockChecksum(huffCounts, sizeof(*huffCounts)*256); - for(i=0;i<256;i++) - huffCounts[i] = LittleLong(huffCounts[i]); -} - -void Huff_LoadTable(char *filename) -{ -} - int Huff_PreferedCompressionCRC (void) { if (!net_compress.ival) return 0; - - if (!madetable) - Huff_Init(NULL); - return madetable; + return q3huff.crc; } - -qboolean Huff_CompressionCRC(int crc) +huffman_t *Huff_CompressionCRC(int crc) { - if (!madetable) - Huff_Init(NULL); - if (crc != LittleLong(madetable)) - return false; - return true; + huffman_t *huff = NULL; + + if (crc == q3huff.crc) + huff = &q3huff; + else + huff = NULL; + + if (huff && !huff->built) + Huff_Init(huff); + return huff; +} +void Huff_DecryptPacket(sizebuf_t *msg, int offset) +{ + //decompress using a dynamic from-nil tree + Huff_Decompress(msg, offset); +} +void Huff_EncryptPacket(sizebuf_t *msg, int offset) +{ + //decompress using a dynamic from-nil tree + Huff_Compress(msg, offset); +} +int Huff_GetByte(qbyte *buffer, int *count) +{ + int ch; + Huff_offsetReceive (q3huff.decompressor.tree, &ch, buffer, count); + return ch; +} +void Huff_EmitByte(int ch, qbyte *buffer, int *count) +{ + Huff_offsetTransmit(&q3huff.compressor, ch, buffer, count); } - - - - - -/* -============ -Huff_CompressPacket - -Compress message using loaded Huffman tree, -beginning from specified offset -============ -*/ -void Huff_CompressPacket( sizebuf_t *msg, int offset ) +void Huff_CompressPacket(huffman_t *huff, sizebuf_t *msg, int offset) { qbyte buffer[MAX_OVERALLMSGLEN]; qbyte *data; @@ -794,9 +578,6 @@ void Huff_CompressPacket( sizebuf_t *msg, int offset ) int inLen; int i; - if (!madetable) - Huff_Init(NULL); - data = msg->data + offset; inLen = msg->cursize - offset; if (inLen <= 0 || inLen >= MAX_OVERALLMSGLEN) @@ -808,11 +589,8 @@ void Huff_CompressPacket( sizebuf_t *msg, int offset ) outLen = 0; for (i=0; i < inLen; i++) { - Huff_EmitByte(data[i], buffer, &outLen); + Huff_offsetTransmit(&huff->compressor, data[i], buffer, &outLen); - countinghuffCounts[data[i]]++; - - outLen = (huffBitPos >> 3) + 1; if (outLen > inLen) break; if (outLen > MAX_OVERALLMSGLEN-64) @@ -825,8 +603,6 @@ void Huff_CompressPacket( sizebuf_t *msg, int offset ) } } - outLen = (huffBitPos >> 3) + 1; - if (outLen > inLen) { memmove(data+1, data, inLen); @@ -837,7 +613,7 @@ void Huff_CompressPacket( sizebuf_t *msg, int offset ) msg->cursize = offset + outLen; { //add the bitcount - data[0] = (outLen<<3) - huffBitPos; + data[0] = (outLen<<3) - outLen; data+=1; msg->cursize+=1; } @@ -845,25 +621,13 @@ void Huff_CompressPacket( sizebuf_t *msg, int offset ) Sys_Error("Compression became too large\n"); memcpy(data, buffer, outLen); } - -/* -============ -Huff_DecompressPacket - -Decompress message using loaded Huffman tree, -beginning from specified offset -============ -*/ -void Huff_DecompressPacket(sizebuf_t *msg, int offset) +void Huff_DecompressPacket(huffman_t *huff, sizebuf_t *msg, int offset) { qbyte buffer[MAX_OVERALLMSGLEN]; qbyte *data; int outLen; int inLen; - int i; - - if (!madetable) - Huff_Init(NULL); + int i, ch; data = msg->data + offset; inLen = msg->cursize - offset; @@ -889,7 +653,8 @@ void Huff_DecompressPacket(sizebuf_t *msg, int offset) { if (i == MAX_OVERALLMSGLEN) Sys_Error("Decompression became too large\n"); - buffer[i] = Huff_GetByte(data, &outLen); + Huff_offsetReceive (huff->decompressor.tree, &ch, data, &outLen); + buffer[i] = ch; } msg->cursize = offset + i; @@ -897,6 +662,5 @@ void Huff_DecompressPacket(sizebuf_t *msg, int offset) Sys_Error("Decompression became too large\n"); memcpy(msg->data + offset, buffer, i); } - #endif diff --git a/engine/common/mathlib.c b/engine/common/mathlib.c index 46dc0c88c..21b8dd6df 100644 --- a/engine/common/mathlib.c +++ b/engine/common/mathlib.c @@ -502,14 +502,15 @@ float Q_rsqrt(float number) float QDECL VectorNormalize (vec3_t v) { - float length, ilength; + float length; + float ilength; length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; length = sqrt (length); // FIXME if (length) { - ilength = 1/length; + ilength = 1.0/length; v[0] *= ilength; v[1] *= ilength; v[2] *= ilength; diff --git a/engine/common/net.h b/engine/common/net.h index 4824ba8f7..274b124e3 100644 --- a/engine/common/net.h +++ b/engine/common/net.h @@ -182,7 +182,7 @@ typedef struct // time and size data to calculate bandwidth int outgoing_size[MAX_LATENT]; double outgoing_time[MAX_LATENT]; - qboolean compress; + struct huffman_s *compresstable; //nq servers must recieve truncated packets. int in_fragment_length; @@ -210,12 +210,15 @@ nqprot_t NQNetChan_Process(netchan_t *chan); #endif #ifdef HUFFNETWORK +#define HUFFCRC_QUAKE3 0x286f2e8d + +typedef struct huffman_s huffman_t; int Huff_PreferedCompressionCRC (void); void Huff_EncryptPacket(sizebuf_t *msg, int offset); void Huff_DecryptPacket(sizebuf_t *msg, int offset); -qboolean Huff_CompressionCRC(int crc); -void Huff_CompressPacket(sizebuf_t *msg, int offset); -void Huff_DecompressPacket(sizebuf_t *msg, int offset); +huffman_t *Huff_CompressionCRC(int crc); +void Huff_CompressPacket(huffman_t *huff, sizebuf_t *msg, int offset); +void Huff_DecompressPacket(huffman_t *huff, sizebuf_t *msg, int offset); int Huff_GetByte(qbyte *buffer, int *count); void Huff_EmitByte(int ch, qbyte *buffer, int *count); #endif diff --git a/engine/common/net_chan.c b/engine/common/net_chan.c index c637710eb..720840e50 100644 --- a/engine/common/net_chan.c +++ b/engine/common/net_chan.c @@ -723,10 +723,10 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate) chan->outgoing_time[i] = realtime; #ifdef HUFFNETWORK - if (chan->compress) + if (chan->compresstable) { //int oldsize = send.cursize; - Huff_CompressPacket(&send, 8 + ((chan->sock == NS_CLIENT)?2:0) + (chan->fragmentsize?2:0)); + Huff_CompressPacket(chan->compresstable, &send, 8 + ((chan->sock == NS_CLIENT)?2:0) + (chan->fragmentsize?2:0)); // Con_Printf("%i becomes %i\n", oldsize, send.cursize); // Huff_DecompressPacket(&send, (chan->sock == NS_CLIENT)?10:8); } @@ -739,7 +739,7 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate) { int hsz = 10 + ((chan->sock == NS_CLIENT)?2:0); /*header size, if fragmentation is in use*/ - if (!chan->fragmentsize || send.cursize < chan->fragmentsize - hsz) + if ((!chan->fragmentsize) || send.cursize-hsz < ((chan->fragmentsize - hsz)&~7)) NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address); else { @@ -1003,10 +1003,10 @@ qboolean Netchan_Process (netchan_t *chan) chan->last_received = realtime; #ifdef HUFFNETWORK - if (chan->compress) + if (chan->compresstable) { // Huff_CompressPacket(&net_message, (chan->sock == NS_SERVER)?10:8); - Huff_DecompressPacket(&net_message, msg_readcount); + Huff_DecompressPacket(chan->compresstable, &net_message, msg_readcount); } #endif diff --git a/engine/common/pmove.c b/engine/common/pmove.c index 8368c905d..ececab8fe 100644 --- a/engine/common/pmove.c +++ b/engine/common/pmove.c @@ -873,7 +873,7 @@ void PM_CategorizePosition (void) VectorMA (pmove.origin, 24, flatforward, fwd1); - t = CM_BoxTrace(pmove.physents[0].model, pmove.origin, fwd1, pmove.player_mins, pmove.player_maxs, MASK_PLAYERSOLID); + pmove.physents[0].model->funcs.NativeTrace(pmove.physents[0].model, 0, 0, NULL, pmove.origin, fwd1, pmove.player_mins, pmove.player_maxs, MASK_PLAYERSOLID, &t); if (t.surface->flags & Q3SURF_LADDER) { pmove.onladder = true; diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 08f04d167..ffeb9c2f5 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -2556,7 +2556,7 @@ void QCBUILTIN PF_dupstring(pubprogfuncs_t *prinst, struct globalvars_s *pr_glob void QCBUILTIN PF_strcat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { char *buf; - int len = 0; + size_t len = 0; const char *s[8]; int l[8]; int i; @@ -2568,13 +2568,16 @@ void QCBUILTIN PF_strcat (pubprogfuncs_t *prinst, struct globalvars_s *pr_global } len++; /*for the null*/ ((int *)pr_globals)[OFS_RETURN] = prinst->AllocTempString(prinst, &buf, len); - len = 0; - for (i = 0; i < prinst->callargc; i++) + if (buf) { - memcpy(buf, s[i], l[i]); - buf += l[i]; + len = 0; + for (i = 0; i < prinst->callargc; i++) + { + memcpy(buf, s[i], l[i]); + buf += l[i]; + } + *buf = '\0'; } - *buf = '\0'; } //returns a section of a string as a tempstring diff --git a/engine/common/q3common.c b/engine/common/q3common.c index 7b1965dd1..6f861ffb5 100644 --- a/engine/common/q3common.c +++ b/engine/common/q3common.c @@ -412,11 +412,9 @@ static void MSG_WriteRawBits( sizebuf_t *msg, int value, int bits ) MSG_WriteHuffBits ============ */ +#ifdef HUFFNETWORK static void MSG_WriteHuffBits( sizebuf_t *msg, int value, int bits ) { -#ifdef MSG_PROFILING - int startbits = msg->currentbit; -#endif int remaining; int i; @@ -445,11 +443,8 @@ static void MSG_WriteHuffBits( sizebuf_t *msg, int value, int bits ) } msg->cursize = (msg->currentbit >> 3) + 1; - -#ifdef MSG_PROFILING - msg_bitsEmitted += msg->currentbit - startbits; -#endif // MSG_PROFILING } +#endif /* ============ @@ -514,9 +509,11 @@ void MSG_WriteBits(sizebuf_t *msg, int value, int bits) case SZ_RAWBITS: MSG_WriteRawBits( msg, value, bits ); break; +#ifdef HUFFNETWORK case SZ_HUFFMAN: MSG_WriteHuffBits( msg, value, bits ); break; +#endif } } diff --git a/engine/common/world.h b/engine/common/world.h index 7fea6d8b2..164c49622 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -61,7 +61,7 @@ typedef struct trace_s //q2 game dll code will memcpy the lot from trace_t to q2trace_t. qboolean allsolid; // if true, plane is not valid qboolean startsolid; // if true, the initial point was in a solid area - float fraction; // time completed, 1.0 = didn't hit anything + float fraction; // time completed, 1.0 = didn't hit anything (nudged closer to the start point to cover precision issues) vec3_t endpos; // final position cplane_t plane; // surface normal at impact q2csurface_t *surface; // q2-compat surface hit @@ -71,6 +71,7 @@ typedef struct trace_s int entnum; qboolean inopen, inwater; + float truefraction; //can be negative, also has floating point precision issues, etc. } trace_t; typedef struct q2trace_s diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index a6df87cf3..39cf8070e 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -16845,6 +16845,7 @@ 128) ambientlight[i] = 128; - if (shadelight[i] > 192) - shadelight[i] = 192; + if (shadelight[i] > 255) + shadelight[i] = 255; } //MORE HUGE HACKS! WHEN WILL THEY CEASE! @@ -1279,9 +1279,9 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel) if (e->flags & Q2RF_GLOW) { - shadelight[0] += sin(cl.time)*0.25; - shadelight[1] += sin(cl.time)*0.25; - shadelight[2] += sin(cl.time)*0.25; + float scale = 1 + 0.2 * sin(cl.time*7); + VectorScale(ambientlight, scale, ambientlight); + VectorScale(shadelight, scale, shadelight); } VectorMA(ambientlight, 0.5, shadelight, e->light_avg); diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index a1b0126e9..4fae08182 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -4208,7 +4208,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) continue; if (batch->shader->flags & SHADER_SKY) { - if (shaderstate.mode == BEM_STANDARD || shaderstate.mode == BEM_DEPTHDARK || shaderstate.mode == BEM_WIREFRAME) + if (shaderstate.mode == BEM_STANDARD || shaderstate.mode == BEM_DEPTHDARK)// || shaderstate.mode == BEM_WIREFRAME) { if (!batch->shader->prog) { diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index 6c96c73a6..161700545 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -112,7 +112,7 @@ typedef struct int reserved2; int reserved1; //char modelname[1+]; -} dsmesh_t; +} dsmesh_v1_t; typedef struct { @@ -184,6 +184,8 @@ typedef struct struct hmwater_s *water; + size_t traceseq; + #ifndef SERVERONLY pvscache_t pvscache; vec4_t colours[SECTHEIGHTSIZE*SECTHEIGHTSIZE]; //FIXME: make bytes @@ -196,12 +198,11 @@ typedef struct mesh_t mesh; mesh_t *amesh; - int numents; - int maxents; - entity_t *ents; - hmpolyset_t *polys; #endif + int numents; + int maxents; + struct hmentity_s **ents; } hmsection_t; typedef struct { @@ -210,7 +211,10 @@ typedef struct typedef struct heightmap_s { char path[MAX_QPATH]; - char watershadername[MAX_QPATH]; //typically the name of the ocean or whatever. + char defaultwatershader[MAX_QPATH]; //typically the name of the ocean or whatever. + float defaultwaterheight; + float defaultgroundheight; + char defaultgroundtexture[MAX_QPATH]; int firstsegx, firstsegy; int maxsegx, maxsegy; //tex/cull sections float sectionsize; //each section is this big, in world coords @@ -220,7 +224,15 @@ typedef struct heightmap_s mesh_t skymesh; mesh_t *askymesh; unsigned int exteriorcontents; - qboolean beinglazy; //only load one section per frame, if its the renderer doing the loading. this helps avoid stalls, in theory. + qboolean beinglazy; //only load one section per frame, if its the renderer doing the loading. this helps avoid nasty stalls, in theory. + size_t traceseq; + size_t drawnframe; + enum + { + DGT_SOLID, //invalid/new areas should be completely solid until painted. + DGT_HOLES, //invalid/new sections should be non-solid+invisible + DGT_FLAT //invalid/new sections should be filled with ground by default + } defaultgroundtype; enum { HMM_TERRAIN, @@ -233,6 +245,16 @@ typedef struct heightmap_s link_t recycle; //section list in lru order // link_t collected; //memory that may be reused, to avoid excess reallocs. + struct hmentity_s + { + size_t drawnframe; //don't add it to the scene multiple times. + size_t traceseq; //don't trace through this entity multiple times if its in different sections. + int refs; //entity is free/reusable when its no longer referenced by any sections + entity_t ent; + + struct hmentity_s *next; //used for freeing/allocating an entity + } *entities; + #ifndef SERVERONLY unsigned int numusedlmsects; //to track leaks and stats unsigned int numunusedlmsects; @@ -548,6 +570,7 @@ static hmsection_t *Terr_GenerateSection(heightmap_t *hm, int sx, int sy) return s; } +//generates some water static void *Terr_GenerateWater(hmsection_t *s, float maxheight) { int i; @@ -557,7 +580,7 @@ static void *Terr_GenerateWater(hmsection_t *s, float maxheight) s->water = w; #ifndef SERVERONLY if (!isDedicated) - w->shader = R_RegisterCustom (s->hmmod->watershadername, SUF_NONE, Shader_DefaultWaterShader, NULL); + w->shader = R_RegisterCustom (s->hmmod->defaultwatershader, SUF_NONE, Shader_DefaultWaterShader, NULL); #endif w->simple = true; w->contentmask = FTECONTENTS_WATER; @@ -570,10 +593,121 @@ static void *Terr_GenerateWater(hmsection_t *s, float maxheight) return w; } +//embeds a mesh +static void Terr_AddMesh(heightmap_t *hm, int loadflags, model_t *mod, vec3_t epos, vec3_t axis[3], float scale) +{ + struct hmentity_s *e, *f = NULL; + hmsection_t *s; + int min[2], max[2], coord[2]; + int i; + + if (!mod) + return; + + if (!scale) + scale = 1; + + if (axis[0][0] != 1 || axis[0][1] != 0 || axis[0][2] != 0 || + axis[1][0] != 0 || axis[1][1] != 1 || axis[1][2] != 0 || + axis[2][0] != 0 || axis[2][1] != 0 || axis[2][2] != 1) + { + min[0] = floor((epos[0]-mod->radius*scale) / hm->sectionsize) + CHUNKBIAS; + min[1] = floor((epos[1]-mod->radius*scale) / hm->sectionsize) + CHUNKBIAS; + min[0] = bound(hm->firstsegx, min[0], hm->maxsegx-1); + min[1] = bound(hm->firstsegy, min[1], hm->maxsegy-1); + + max[0] = floor((epos[0]+mod->radius*scale) / hm->sectionsize) + CHUNKBIAS; + max[1] = floor((epos[1]+mod->radius*scale) / hm->sectionsize) + CHUNKBIAS; + max[0] = bound(hm->firstsegx, max[0], hm->maxsegx-1); + max[1] = bound(hm->firstsegy, max[1], hm->maxsegy-1); + } + else + { + min[0] = floor((epos[0]+mod->mins[0]*scale) / hm->sectionsize) + CHUNKBIAS; + min[1] = floor((epos[1]+mod->mins[1]*scale) / hm->sectionsize) + CHUNKBIAS; + min[0] = bound(hm->firstsegx, min[0], hm->maxsegx-1); + min[1] = bound(hm->firstsegy, min[1], hm->maxsegy-1); + + max[0] = floor((epos[0]+mod->maxs[0]*scale) / hm->sectionsize) + CHUNKBIAS; + max[1] = floor((epos[1]+mod->maxs[1]*scale) / hm->sectionsize) + CHUNKBIAS; + max[0] = bound(hm->firstsegx, max[0], hm->maxsegx-1); + max[1] = bound(hm->firstsegy, max[1], hm->maxsegy-1); + } + + //try to find the ent if it already exists (don't do dupes) + for (e = hm->entities; e; e = e->next) + { + if (!e->refs) + f = e; + else + { + if (e->ent.origin[0] != epos[0] || e->ent.origin[1] != epos[1] || e->ent.origin[2] != epos[2]) + continue; + if (e->ent.model != mod || e->ent.scale != scale) + continue; + if (memcmp(axis, e->ent.axis, sizeof(axis))) + continue; + break; //looks like a match. + } + } + //allocate it if needed + if (!e) + { + if (f) + e = f; //can reuse a released one + else + { //allocate one + e = Z_Malloc(sizeof(*e)); + e->next = hm->entities; + hm->entities = e; + } + + e->ent.drawflags = SCALE_ORIGIN_ORIGIN; + e->ent.scale = scale; + e->ent.playerindex = -1; + e->ent.shaderRGBAf[0] = 1; + e->ent.shaderRGBAf[1] = 1; + e->ent.shaderRGBAf[2] = 1; + e->ent.shaderRGBAf[3] = 1; + VectorCopy(epos, e->ent.origin); + memcpy(e->ent.axis, axis, sizeof(e->ent.axis)); + e->ent.model = mod; + } + + for (coord[0] = min[0]; coord[0] <= max[0]; coord[0]++) + { + for (coord[1] = min[1]; coord[1] <= max[1]; coord[1]++) + { + s = Terr_GetSection(hm, coord[0], coord[1], loadflags); + if (!s) + continue; + + //don't add pointless dupes + for (i = 0; i < s->numents; i++) + { + if (s->ents[i] == e) + break; + } + if (i < s->numents) + continue; + + s->flags |= TSF_EDITED; + + if (s->maxents == s->numents) + { + s->maxents++; + s->ents = realloc(s->ents, sizeof(*s->ents)*(s->maxents)); + } + s->ents[s->numents++] = e; + e->refs++; + } + } +} + static void *Terr_ReadV1(heightmap_t *hm, hmsection_t *s, void *ptr, int len) { #ifndef SERVERONLY - dsmesh_t *dm; + dsmesh_v1_t *dm; float *colours; #endif dsection_v1_t *ds = ptr; @@ -661,36 +795,13 @@ static void *Terr_ReadV1(heightmap_t *hm, hmsection_t *s, void *ptr, int len) } /*load any static ents*/ - s->numents = ds->ents_num; - s->maxents = s->numents; - if (s->maxents) - s->ents = Z_Malloc(sizeof(*s->ents) * s->maxents); - else - s->ents = NULL; - if (!s->ents) - s->numents = s->maxents = 0; - for (i = 0, dm = (dsmesh_t*)ptr; i < s->numents; i++, dm = (dsmesh_t*)((qbyte*)dm + dm->size)) + for (i = 0, dm = (dsmesh_v1_t*)ptr; i < ds->ents_num; i++, dm = (dsmesh_v1_t*)((qbyte*)dm + dm->size)) { - s->ents[i].model = Mod_ForName((char*)(dm + 1), MLV_WARN); - if (!s->ents[i].model || s->ents[i].model->type == mod_dummy) - { - s->numents--; - i--; - continue; - } - s->ents[i].scale = dm->scale; - s->ents[i].drawflags = SCALE_ORIGIN_ORIGIN; - s->ents[i].playerindex = -1; - VectorCopy(dm->axisorg[0], s->ents[i].axis[0]); - VectorCopy(dm->axisorg[1], s->ents[i].axis[1]); - VectorCopy(dm->axisorg[2], s->ents[i].axis[2]); - VectorCopy(dm->axisorg[3], s->ents[i].origin); - s->ents[i].origin[0] += (s->sx-CHUNKBIAS)*hm->sectionsize; - s->ents[i].origin[1] += (s->sy-CHUNKBIAS)*hm->sectionsize; - s->ents[i].shaderRGBAf[0] = 1; - s->ents[i].shaderRGBAf[1] = 1; - s->ents[i].shaderRGBAf[2] = 1; - s->ents[i].shaderRGBAf[3] = 1; + vec3_t org; + org[0] = dm->axisorg[3][0] + (s->sx-CHUNKBIAS)*hm->sectionsize; + org[1] = dm->axisorg[3][1] + (s->sy-CHUNKBIAS)*hm->sectionsize; + org[2] = dm->axisorg[3][2]; + Terr_AddMesh(hm, TGS_NOLOAD, Mod_ForName((char*)(dm + 1), MLV_WARN), org, dm->axisorg, dm->scale); } #endif return ptr; @@ -853,7 +964,7 @@ static void Terr_SaveV2(heightmap_t *hm, hmsection_t *s, vfsfile_t *f, int sx, i char *shadername = w->shader->name; int fl = 0; - if (strcmp(shadername, hm->watershadername)) + if (strcmp(shadername, hm->defaultwatershader)) fl |= 1; for (x = 0; x < 8; x++) if (w->holes[x]) @@ -943,27 +1054,27 @@ static void Terr_SaveV2(heightmap_t *hm, hmsection_t *s, vfsfile_t *f, int sx, i } mf = 0; - if (s->ents[i].scale != 1) + if (s->ents[i]->ent.scale != 1) mf |= TMF_SCALE; Terr_Write_SInt(&strm, mf); - if (s->ents[i].model) - Terr_Write_String(&strm, s->ents[i].model->name); + if (s->ents[i]->ent.model) + Terr_Write_String(&strm, s->ents[i]->ent.model->name); else Terr_Write_String(&strm, "*invalid"); - Terr_Write_Float(&strm, s->ents[i].origin[0]+(CHUNKBIAS-sx)*hm->sectionsize); - Terr_Write_Float(&strm, s->ents[i].origin[1]+(CHUNKBIAS-sy)*hm->sectionsize); - Terr_Write_Float(&strm, s->ents[i].origin[2]); - Terr_Write_Float(&strm, s->ents[i].axis[0][0]); - Terr_Write_Float(&strm, s->ents[i].axis[0][1]); - Terr_Write_Float(&strm, s->ents[i].axis[0][2]); - Terr_Write_Float(&strm, s->ents[i].axis[1][0]); - Terr_Write_Float(&strm, s->ents[i].axis[1][1]); - Terr_Write_Float(&strm, s->ents[i].axis[1][2]); - Terr_Write_Float(&strm, s->ents[i].axis[2][0]); - Terr_Write_Float(&strm, s->ents[i].axis[2][1]); - Terr_Write_Float(&strm, s->ents[i].axis[2][2]); + Terr_Write_Float(&strm, s->ents[i]->ent.origin[0]+(CHUNKBIAS-sx)*hm->sectionsize); + Terr_Write_Float(&strm, s->ents[i]->ent.origin[1]+(CHUNKBIAS-sy)*hm->sectionsize); + Terr_Write_Float(&strm, s->ents[i]->ent.origin[2]); + Terr_Write_Float(&strm, s->ents[i]->ent.axis[0][0]); + Terr_Write_Float(&strm, s->ents[i]->ent.axis[0][1]); + Terr_Write_Float(&strm, s->ents[i]->ent.axis[0][2]); + Terr_Write_Float(&strm, s->ents[i]->ent.axis[1][0]); + Terr_Write_Float(&strm, s->ents[i]->ent.axis[1][1]); + Terr_Write_Float(&strm, s->ents[i]->ent.axis[1][2]); + Terr_Write_Float(&strm, s->ents[i]->ent.axis[2][0]); + Terr_Write_Float(&strm, s->ents[i]->ent.axis[2][1]); + Terr_Write_Float(&strm, s->ents[i]->ent.axis[2][2]); if (mf & TMF_SCALE) - Terr_Write_Float(&strm, s->ents[i].scale); + Terr_Write_Float(&strm, s->ents[i]->ent.scale); } //reset it in case the buffer is getting a little full @@ -1023,7 +1134,7 @@ static void *Terr_ReadV2(heightmap_t *hm, hmsection_t *s, void *ptr, int len) if (fl & 1) Terr_Read_String(&strm, shadername, sizeof(shadername)); else - Q_strncpyz(shadername, hm->watershadername, sizeof(hm->watershadername)); + Q_strncpyz(shadername, hm->defaultwatershader, sizeof(shadername)); #ifndef SERVERONLY // CL_CheckOrEnqueDownloadFile(shadername, NULL, 0); w->shader = R_RegisterCustom (shadername, SUF_NONE, Shader_DefaultWaterShader, NULL); @@ -1122,50 +1233,35 @@ static void *Terr_ReadV2(heightmap_t *hm, hmsection_t *s, void *ptr, int len) } /*load any static ents*/ - s->numents = Terr_Read_SInt(&strm); - if (s->maxents) - BZ_Free(s->ents); - s->maxents = s->numents; - if (s->maxents) - s->ents = BZ_Malloc(sizeof(*s->ents) * s->maxents); - else - s->ents = NULL; - if (!s->ents) - s->numents = s->maxents = 0; - for (i = 0; i < s->numents; i++) + j = Terr_Read_SInt(&strm); + for (i = 0; i < j; i++) { + vec3_t axis[3]; + vec3_t org; unsigned int mf; + model_t *mod; + float scale; mf = Terr_Read_SInt(&strm); - memset(&s->ents[i], 0, sizeof(s->ents[i])); - s->ents[i].model = Mod_FindName(Terr_Read_String(&strm, modelname, sizeof(modelname))); - s->ents[i].origin[0] = Terr_Read_Float(&strm); - s->ents[i].origin[1] = Terr_Read_Float(&strm); - s->ents[i].origin[2] = Terr_Read_Float(&strm); - s->ents[i].axis[0][0] = Terr_Read_Float(&strm); - s->ents[i].axis[0][1] = Terr_Read_Float(&strm); - s->ents[i].axis[0][2] = Terr_Read_Float(&strm); - s->ents[i].axis[1][0] = Terr_Read_Float(&strm); - s->ents[i].axis[1][1] = Terr_Read_Float(&strm); - s->ents[i].axis[1][2] = Terr_Read_Float(&strm); - s->ents[i].axis[2][0] = Terr_Read_Float(&strm); - s->ents[i].axis[2][1] = Terr_Read_Float(&strm); - s->ents[i].axis[2][2] = Terr_Read_Float(&strm); - s->ents[i].scale = (mf&TMF_SCALE)?Terr_Read_Float(&strm):1; - s->ents[i].drawflags = SCALE_ORIGIN_ORIGIN; - s->ents[i].playerindex = -1; - s->ents[i].origin[0] += (s->sx-CHUNKBIAS)*hm->sectionsize; - s->ents[i].origin[1] += (s->sy-CHUNKBIAS)*hm->sectionsize; - s->ents[i].shaderRGBAf[0] = 1; - s->ents[i].shaderRGBAf[1] = 1; - s->ents[i].shaderRGBAf[2] = 1; - s->ents[i].shaderRGBAf[3] = 1; + mod = Mod_FindName(Terr_Read_String(&strm, modelname, sizeof(modelname))); + org[0] = Terr_Read_Float(&strm); + org[1] = Terr_Read_Float(&strm); + org[2] = Terr_Read_Float(&strm); + axis[0][0] = Terr_Read_Float(&strm); + axis[0][1] = Terr_Read_Float(&strm); + axis[0][2] = Terr_Read_Float(&strm); + axis[1][0] = Terr_Read_Float(&strm); + axis[1][1] = Terr_Read_Float(&strm); + axis[1][2] = Terr_Read_Float(&strm); + axis[2][0] = Terr_Read_Float(&strm); + axis[2][1] = Terr_Read_Float(&strm); + axis[2][2] = Terr_Read_Float(&strm); + scale = (mf&TMF_SCALE)?Terr_Read_Float(&strm):1; - if (!s->ents[i].model) - { - s->numents--; - i--; - } + org[0] += (s->sx-CHUNKBIAS)*hm->sectionsize; + org[1] += (s->sy-CHUNKBIAS)*hm->sectionsize; + + Terr_AddMesh(hm, TGS_NOLOAD, mod, org, axis, scale); } #endif return ptr; @@ -1175,9 +1271,7 @@ static void *Terr_ReadV2(heightmap_t *hm, hmsection_t *s, void *ptr, int len) static void Terr_GenerateDefault(heightmap_t *hm, hmsection_t *s) { -#ifndef SERVERONLY int i; -#endif s->flags |= TSF_FAILEDLOAD; memset(s->holes, 0, sizeof(s->holes)); @@ -1186,7 +1280,7 @@ static void Terr_GenerateDefault(heightmap_t *hm, hmsection_t *s) Q_strncpyz(s->texname[0], "", sizeof(s->texname[0])); Q_strncpyz(s->texname[1], "", sizeof(s->texname[1])); Q_strncpyz(s->texname[2], "", sizeof(s->texname[2])); - Q_strncpyz(s->texname[3], "", sizeof(s->texname[3])); + Q_strncpyz(s->texname[3], hm->defaultgroundtexture, sizeof(s->texname[3])); if (s->lightmap >= 0) { @@ -1222,6 +1316,12 @@ static void Terr_GenerateDefault(heightmap_t *hm, hmsection_t *s) s->mesh.colors4f_array[0] = s->colours; #endif + for (i = 0; i < SECTHEIGHTSIZE*SECTHEIGHTSIZE; i++) + s->heights[i] = hm->defaultgroundheight; + + if (hm->defaultwaterheight > hm->defaultgroundheight) + Terr_GenerateWater(s, hm->defaultwaterheight); + #if 0//def DEBUG void *f; if (lightmap_bytes == 4 && lightmap_bgra && FS_LoadFile(va("maps/%s/splatt.png", hm->path), &f) != (qofs_t)-1) @@ -1475,7 +1575,7 @@ static void Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy, un static void Terr_SaveV1(heightmap_t *hm, hmsection_t *s, vfsfile_t *f, int sx, int sy) { int i; - dsmesh_t dm; + dsmesh_v1_t dm; qbyte *lm; dsection_v1_t ds; vec4_t dcolours[SECTHEIGHTSIZE*SECTHEIGHTSIZE]; @@ -1555,21 +1655,21 @@ static void Terr_SaveV1(heightmap_t *hm, hmsection_t *s, vfsfile_t *f, int sx, i for (i = 0; i < s->numents; i++) { int pad; - dm.scale = s->ents[i].scale; - VectorCopy(s->ents[i].axis[0], dm.axisorg[0]); - VectorCopy(s->ents[i].axis[1], dm.axisorg[1]); - VectorCopy(s->ents[i].axis[2], dm.axisorg[2]); - VectorCopy(s->ents[i].origin, dm.axisorg[3]); + dm.scale = s->ents[i]->ent.scale; + VectorCopy(s->ents[i]->ent.axis[0], dm.axisorg[0]); + VectorCopy(s->ents[i]->ent.axis[1], dm.axisorg[1]); + VectorCopy(s->ents[i]->ent.axis[2], dm.axisorg[2]); + VectorCopy(s->ents[i]->ent.origin, dm.axisorg[3]); dm.axisorg[3][0] += (CHUNKBIAS-sx)*hm->sectionsize; dm.axisorg[3][1] += (CHUNKBIAS-sy)*hm->sectionsize; - dm.size = sizeof(dm) + strlen(s->ents[i].model->name) + 1; + dm.size = sizeof(dm) + strlen(s->ents[i]->ent.model->name) + 1; if (dm.size & 3) pad = 4 - (dm.size&3); else pad = 0; dm.size += pad; VFS_WRITE(f, &dm, sizeof(dm)); - VFS_WRITE(f, s->ents[i].model->name, strlen(s->ents[i].model->name)+1); + VFS_WRITE(f, s->ents[i]->ent.model->name, strlen(s->ents[i]->ent.model->name)+1); if (pad) VFS_WRITE(f, ¬hing, pad); } @@ -1812,7 +1912,13 @@ qboolean Terrain_LocateSection(char *name, flocation_t *loc) void Terr_DestroySection(heightmap_t *hm, hmsection_t *s, qboolean lightmapreusable) { + int i; RemoveLink(&s->recycle); + + for (i = 0; i < s->numents; i++) + s->ents[i]->refs-=1; + s->numents = 0; + #ifndef SERVERONLY if (s->lightmap >= 0) { @@ -2601,7 +2707,13 @@ void Terr_DrawInBounds(struct tdibctx *ctx, int x, int y, int w, int h) { vec3_t dist; float a; - model_t *model = s->ents[i].model; + model_t *model; + //skip the entity if its already been added to some batch this frame. + if (s->ents[i]->drawnframe == hm->drawnframe) + continue; + s->ents[i]->drawnframe = hm->drawnframe; + + model = s->ents[i]->ent.model; if (!model) continue; @@ -2615,7 +2727,7 @@ void Terr_DrawInBounds(struct tdibctx *ctx, int x, int y, int w, int h) if (model->needload) continue; - VectorSubtract(s->ents[i].origin, r_origin, dist); + VectorSubtract(s->ents[i]->ent.origin, r_origin, dist); a = VectorLength(dist); a = 1024 - a + model->radius*16; a /= model->radius; @@ -2624,18 +2736,18 @@ void Terr_DrawInBounds(struct tdibctx *ctx, int x, int y, int w, int h) if (a >= 1) { a = 1; - s->ents[i].flags &= ~RF_TRANSLUCENT; + s->ents[i]->ent.flags &= ~RF_TRANSLUCENT; } else - s->ents[i].flags |= RF_TRANSLUCENT; - s->ents[i].shaderRGBAf[3] = a; + s->ents[i]->ent.flags |= RF_TRANSLUCENT; + s->ents[i]->ent.shaderRGBAf[3] = a; switch(model->type) { case mod_alias: - R_GAlias_GenerateBatches(&s->ents[i], ctx->batches); + R_GAlias_GenerateBatches(&s->ents[i]->ent, ctx->batches); break; case mod_brush: - Surf_GenBrushBatches(ctx->batches, &s->ents[i]); + Surf_GenBrushBatches(ctx->batches, &s->ents[i]->ent); break; default: //FIXME: no sprites! oh noes! break; @@ -2802,6 +2914,7 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e) bounds[3] = hm->maxsegy; } + hm->drawnframe+=1; tdibctx.hm = hm; tdibctx.batches = batches; tdibctx.ent = e; @@ -3073,6 +3186,7 @@ typedef struct { heightmap_t *hm; int contents; int hitcontentsmask; + trace_t *result; } hmtrace_t; static void Heightmap_Trace_Brush(hmtrace_t *tr, vec4_t *planes, int numplanes) @@ -3157,7 +3271,7 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty) vec3_t p[4]; vec4_t n[5]; int t; -// int i; + int i; #ifndef STRICTEDGES float d1, d2; @@ -3187,26 +3301,47 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty) Heightmap_Trace_Brush(tr, n, 4); return; } -/* - for (i = 0; i < s->numents; i++) - { - vec3_t start_l, end_l; - trace_t etr; - model_t *model = s->ents[i].model; - int frame = s->ents[i].framestate.g[FS_REG].frame[0]; - if (!model || model->needload || !model->funcs.NativeTrace) - continue; - VectorSubtract (tr->start, s->ents[i].origin, start_l); - VectorSubtract (tr->end, s->ents[i].origin, end_l); - start_l[2] -= tr->mins[2]; - end_l[2] -= tr->mins[2]; - VectorScale(start_l, s->ents[i].scale, start_l); - VectorScale(end_l, s->ents[i].scale, end_l); - memset(&etr, 0, sizeof(etr)); - etr.fraction = 1; - if (model->funcs.NativeTrace (model, 0, frame, s->ents[i].axis, start_l, end_l, tr->mins, tr->maxs, tr->hitcontentsmask, &etr)) + if (s->traceseq != tr->hm->traceseq) + { + s->traceseq = tr->hm->traceseq; + for (i = 0; i < s->numents; i++) { + vec3_t start_l, end_l; + trace_t etr; + model_t *model; + int frame; + if (s->ents[i]->traceseq == tr->hm->traceseq) + continue; + s->ents[i]->traceseq = tr->hm->traceseq; + model = s->ents[i]->ent.model; + frame = s->ents[i]->ent.framestate.g[FS_REG].frame[0]; + if (!model || model->needload || !model->funcs.NativeTrace) + continue; + //figure out where on the submodel the trace is. + VectorSubtract (tr->start, s->ents[i]->ent.origin, start_l); + VectorSubtract (tr->end, s->ents[i]->ent.origin, end_l); + start_l[2] -= tr->mins[2]; + end_l[2] -= tr->mins[2]; + VectorScale(start_l, s->ents[i]->ent.scale, start_l); + VectorScale(end_l, s->ents[i]->ent.scale, end_l); + + //skip if the local trace points are outside the model's bounds +/* for (j = 0; j < 3; j++) + { + if (start_l[j]+tr->mins[j] > model->maxs[j] && end_l[j]+tr->mins[j] > model->maxs[j]) + continue; + if (start_l[j]+tr->maxs[j] < model->mins[j] && end_l[j]+tr->maxs[j] < model->mins[j]) + continue; + } +*/ + //do the trace + memset(&etr, 0, sizeof(etr)); + etr.fraction = 1; + model->funcs.NativeTrace (model, 0, frame, s->ents[i]->ent.axis, start_l, end_l, tr->mins, tr->maxs, tr->hitcontentsmask, &etr); + + tr->result->startsolid |= etr.startsolid; + tr->result->allsolid |= etr.allsolid; if (etr.fraction < tr->frac) { tr->contents = etr.contents; @@ -3218,7 +3353,7 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty) } } } -*/ + sx = tx - CHUNKBIAS*(SECTHEIGHTSIZE-1); sy = ty - CHUNKBIAS*(SECTHEIGHTSIZE-1); @@ -3388,6 +3523,7 @@ qboolean Heightmap_Trace(struct model_s *model, int hulloverride, int frame, vec float wbias; hmtrace_t hmtrace; hmtrace.hm = model->terrain; + hmtrace.hm->traceseq++; hmtrace.htilesize = hmtrace.hm->sectionsize / (SECTHEIGHTSIZE-1); hmtrace.frac = 1; hmtrace.contents = 0; @@ -3399,6 +3535,7 @@ qboolean Heightmap_Trace(struct model_s *model, int hulloverride, int frame, vec memset(trace, 0, sizeof(*trace)); trace->fraction = 1; + hmtrace.result = trace; //to tile space hmtrace.start[0] = (start[0]); @@ -4064,7 +4201,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g hmsection_t *s; x = pos[0]*4 / hm->sectionsize; y = pos[1]*4 / hm->sectionsize; - x = bound(hm->firstsegx*4, x, hm->maxsegy*4-1); + x = bound(hm->firstsegx*4, x, hm->maxsegx*4-1); y = bound(hm->firstsegy*4, y, hm->maxsegy*4-1); s = Terr_GetSection(hm, x/4, y/4, TGS_FORCELOAD); @@ -4142,7 +4279,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g hmsection_t *s; x = pos[0] / hm->sectionsize; y = pos[1] / hm->sectionsize; - x = bound(hm->firstsegx, x, hm->maxsegy-1); + x = bound(hm->firstsegx, x, hm->maxsegx-1); y = bound(hm->firstsegy, y, hm->maxsegy-1); s = Terr_GetSection(hm, x, y, TGS_LOAD); @@ -4157,7 +4294,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g int x, y; x = pos[0] / hm->sectionsize; y = pos[1] / hm->sectionsize; - x = bound(hm->firstsegx, x, hm->maxsegy-1); + x = bound(hm->firstsegx, x, hm->maxsegx-1); y = bound(hm->firstsegy, y, hm->maxsegy-1); ted_texkill(Terr_GetSection(hm, x, y, TGS_FORCELOAD), PR_GetStringOfs(prinst, OFS_PARM4)); @@ -4165,59 +4302,36 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g break; case ter_mesh_add: { - entity_t *e; - float *epos; - int x, y; - hmsection_t *s; - epos = ((wedict_t *)G_EDICT(prinst, OFS_PARM1))->v->origin; - x = (epos[0] / hm->sectionsize) + CHUNKBIAS; - y = (epos[1] / hm->sectionsize) + CHUNKBIAS; - x = bound(hm->firstsegx, x, hm->maxsegy-1); - y = bound(hm->firstsegy, y, hm->maxsegy-1); - - s = Terr_GetSection(hm, x, y, TGS_FORCELOAD); - if (!s) - return; - - s->flags |= TSF_EDITED; - - if (s->maxents == s->numents) - { - s->maxents++; - s->ents = realloc(s->ents, sizeof(*s->ents)*(s->maxents)); - } - e = &s->ents[s->numents++]; - - memset(e, 0, sizeof(*e)); - e->scale = ((wedict_t *)G_EDICT(prinst, OFS_PARM1))->xv->scale; - e->playerindex = -1; - e->shaderRGBAf[0] = 1; - e->shaderRGBAf[1] = 1; - e->shaderRGBAf[2] = 1; - e->shaderRGBAf[3] = 1; - VectorCopy(epos, e->origin); - AngleVectorsFLU(((wedict_t *)G_EDICT(prinst, OFS_PARM1))->v->angles, e->axis[0], e->axis[1], e->axis[2]); - e->model = vmw->Get_CModel(vmw, ((wedict_t *)G_EDICT(prinst, OFS_PARM1))->v->modelindex); + vec3_t axis[3]; + wedict_t *ed = G_WEDICT(prinst, OFS_PARM1); + //FIXME: modeltype pitch inversion + AngleVectorsFLU(ed->v->angles, axis[0], axis[1], axis[2]); + Terr_AddMesh(hm, TGS_FORCELOAD, vmw->Get_CModel(vmw, ed->v->modelindex), ed->v->origin, axis, ed->xv->scale); } break; case ter_mesh_kill: { -// int i; + int i; // entity_t *e; int x, y; // float r; hmsection_t *s; x = pos[0] / hm->sectionsize; y = pos[1] / hm->sectionsize; - x = bound(hm->firstsegx, x, hm->maxsegy-1); + x = bound(hm->firstsegx, x, hm->maxsegx-1); y = bound(hm->firstsegy, y, hm->maxsegy-1); s = Terr_GetSection(hm, x, y, TGS_FORCELOAD); if (!s) return; - s->numents = 0; - s->flags |= TSF_EDITED; + if (s->numents) + { + for (i = 0; i < s->numents; i++) + s->ents[i]->refs -= 1; + s->flags |= TSF_EDITED; + s->numents = 0; + } /*for (i = 0; i < s->numents; i++) { @@ -4241,6 +4355,11 @@ void Terr_ParseEntityLump(char *data, heightmap_t *heightmap) heightmap->sectionsize = 1024; heightmap->mode = HMM_TERRAIN; + heightmap->defaultgroundheight = 0; + heightmap->defaultwaterheight = 0; + Q_strncpyz(heightmap->defaultwatershader, va("water/%s", heightmap->path), sizeof(heightmap->defaultwatershader)); + Q_strncpyz(heightmap->defaultgroundtexture, "", sizeof(heightmap->defaultgroundtexture)); + if (data) if ((data=COM_Parse(data))) //read the map info. if (com_token[0] == '{') @@ -4251,7 +4370,7 @@ void Terr_ParseEntityLump(char *data, heightmap_t *heightmap) if (com_token[0] == '}') break; // end of worldspawn if (com_token[0] == '_') - strcpy(key, com_token + 1); //_ vars are for comments/utility stuff that arn't visible to progs. Ignore them. + strcpy(key, com_token + 1); //_ vars are for comments/utility stuff that arn't visible to progs and for compat. We want to support these stealth things. else strcpy(key, com_token); if (!((data=COM_Parse(data)))) @@ -4266,6 +4385,14 @@ void Terr_ParseEntityLump(char *data, heightmap_t *heightmap) heightmap->maxsegx = atoi(com_token); else if (!strcmp("maxysegment", key)) heightmap->maxsegy = atoi(com_token); + else if (!strcmp("defaultwaterheight", key)) + heightmap->defaultwaterheight = atof(com_token); + else if (!strcmp("defaultgroundheight", key)) + heightmap->defaultgroundheight = atof(com_token); + else if (!strcmp("defaultgroundtexture", key)) + Q_strncpyz(heightmap->defaultgroundtexture, key, sizeof(heightmap->defaultgroundtexture)); + else if (!strcmp("defaultwatertexture", key)) + Q_strncpyz(heightmap->defaultwatershader, key, sizeof(heightmap->defaultwatershader)); else if (!strcmp("tiles", key)) { char *d; @@ -4302,7 +4429,6 @@ void Terr_FinishTerrain(heightmap_t *hm, char *shadername, char *skyname) #ifndef SERVERONLY if (qrenderer != QR_NONE) { - Q_strncpyz(hm->watershadername, va("water/%s", hm->path), sizeof(hm->watershadername)); if (skyname) hm->skyshader = R_RegisterCustom(va("skybox_%s", skyname), SUF_NONE, Shader_DefaultSkybox, NULL); else @@ -4433,7 +4559,7 @@ qboolean QDECL Terr_LoadTerrainModel (model_t *mod, void *buffer, size_t bufsize mod->mins[0] = (hm->firstsegx - CHUNKBIAS) * hm->sectionsize; mod->mins[1] = (hm->firstsegy - CHUNKBIAS) * hm->sectionsize; mod->mins[2] = -999999999999999999999999.f; - mod->maxs[0] = (hm->maxsegy - CHUNKBIAS) * hm->sectionsize; + mod->maxs[0] = (hm->maxsegx - CHUNKBIAS) * hm->sectionsize; mod->maxs[1] = (hm->maxsegy - CHUNKBIAS) * hm->sectionsize; mod->maxs[2] = 999999999999999999999999.f; @@ -4525,6 +4651,10 @@ void Mod_Terrain_Create_f(void) "_minysegment -2048\n" "_maxxsegment 2048\n" "_maxysegment 2048\n" + "//_defaultgroundtexture city4_2\n" + "//_defaultwatertexture *water2\n" + "//_defaultgroundheight -1024\n" + "//_defaultwaterheight 0\n" //hurrah, sea level. // "_tiles 64 64 8 8\n" "}\n" "{\n" @@ -4533,6 +4663,8 @@ void Mod_Terrain_Create_f(void) "}\n" , Cmd_Argv(2)); COM_WriteFile(mname, mdata, strlen(mdata)); + + //FIXME: create 4 sections around the origin } //reads in the terrain a tile at a time, and writes it out again. //the new version will match our current format version. diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 26d9421d4..794e919fa 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" -#ifndef SERVERONLY //FIXME +#if 1//ndef SERVERONLY //FIXME #include "glquake.h" #include "com_mesh.h" @@ -33,6 +33,14 @@ extern cvar_t r_shadow_bumpscale_basetexture; extern cvar_t r_replacemodels; extern cvar_t gl_lightmap_average; +#ifdef SERVERONLY +cvar_t gl_overbright, gl_specular, gl_load24bit, r_replacemodels, gl_miptexLevel, r_fb_bmodels; //all of these can/should default to 0 +cvar_t r_noframegrouplerp = CVARF ("r_noframegrouplerp", "0", CVAR_ARCHIVE); +cvar_t dpcompat_psa_ungroup = CVAR ("dpcompat_psa_ungroup", "0"); +texture_t r_notexture_mip_real; +texture_t *r_notexture_mip = &r_notexture_mip_real; +#endif + qboolean isnotmap = true; //used to not warp ammo models. model_t *loadmodel; @@ -53,7 +61,7 @@ model_t *Mod_LoadModel (model_t *mod, enum mlverbosity_e verbose); qboolean Mod_LoadDoomLevel(model_t *mod); #endif -#ifdef DOOMWADS +#ifdef DSPMODELS void Mod_LoadDoomSprite (model_t *mod); #endif @@ -95,8 +103,8 @@ void Mod_UpdateLightmap(int snum) } #endif - -void Mod_MemList_f(void) +#ifndef SERVERONLY +static void Mod_MemList_f(void) { int m; model_t *mod; @@ -110,7 +118,7 @@ void Mod_MemList_f(void) Con_Printf("Total: %i bytes\n", total); } -void Mod_BatchList_f(void) +static void Mod_BatchList_f(void) { int m, i; model_t *mod; @@ -147,7 +155,7 @@ void Mod_BatchList_f(void) } } -void Mod_TextureList_f(void) +static void Mod_TextureList_f(void) { int m, i; texture_t *tx; @@ -190,7 +198,7 @@ void Mod_TextureList_f(void) Con_Printf("%u\n", count); } -void Mod_BlockTextureColour_f (void) +static void Mod_BlockTextureColour_f (void) { char texname[64]; model_t *mod; @@ -236,7 +244,7 @@ void Mod_BlockTextureColour_f (void) } } } - +#endif #if defined(RUNTIMELIGHTING) && defined(MULTITHREAD) @@ -476,7 +484,9 @@ void Mod_Purge(enum mod_purge_e ptype) //brush models cannot be safely flushed. if (!unused && ptype != MP_RESET) continue; +#ifndef SERVERONLY Surf_Clear(mod); +#endif } #ifdef TERRAIN @@ -511,17 +521,21 @@ void Mod_Init (qboolean initial) mod_numknown = 0; Q1BSP_Init(); +#ifndef SERVERONLY Cmd_AddCommand("mod_memlist", Mod_MemList_f); Cmd_AddCommand("mod_batchlist", Mod_BatchList_f); Cmd_AddCommand("mod_texturelist", Mod_TextureList_f); Cmd_AddCommand("mod_usetexture", Mod_BlockTextureColour_f); +#endif } if (initial) { Alias_Register(); +#ifdef SPRMODELS Mod_RegisterModelFormatMagic(NULL, "Quake1 Sprite (spr)", IDSPRITEHEADER, Mod_LoadSpriteModel); +#endif #ifdef SP2MODELS Mod_RegisterModelFormatMagic(NULL, "Quake2 Sprite (sp2)", IDSPRITE2HEADER, Mod_LoadSprite2Model); #endif @@ -837,7 +851,9 @@ model_t *Mod_LoadModel (model_t *mod, enum mlverbosity_e verbose) mod->maxs[2] = 16; mod->needload = false; mod->engineflags = 0; +#ifndef SERVERONLY P_LoadedModel(mod); +#endif return mod; } @@ -927,7 +943,7 @@ model_t *Mod_LoadModel (model_t *mod, enum mlverbosity_e verbose) buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf)); if (!buf) { -#ifdef DOOMWADS +#ifdef DSPMODELS if (doomsprite) // special case needed for doom sprites { mod->needload = false; @@ -962,8 +978,10 @@ model_t *Mod_LoadModel (model_t *mod, enum mlverbosity_e verbose) { if (!modelloaders[i].load(mod, buf, com_filesize)) continue; +#ifndef SERVERONLY if (mod->type == mod_brush) Surf_BuildModelLightmaps(mod); +#endif } else { @@ -997,8 +1015,10 @@ model_t *Mod_LoadModel (model_t *mod, enum mlverbosity_e verbose) #endif */ +#ifndef SERVERONLY P_LoadedModel(mod); Validation_IncludeFile(mod->name, (char *)buf, com_filesize); +#endif TRACE(("Mod_LoadModel: Loaded\n")); @@ -1045,7 +1065,9 @@ model_t *Mod_LoadModel (model_t *mod, enum mlverbosity_e verbose) mod->maxs[2] = 16; mod->needload = 2; mod->engineflags = 0; +#ifndef SERVERONLY P_LoadedModel(mod); +#endif return mod; } @@ -1264,6 +1286,7 @@ void Mod_LoadAdvancedTexture(char *name, int *base, int *norm, int *luma, int *g void Mod_FinishTexture(texture_t *tx, texnums_t tn) { +#ifndef SERVERONLY extern cvar_t gl_shadeq1_name; char altname[MAX_QPATH]; char *star; @@ -1285,14 +1308,16 @@ void Mod_FinishTexture(texture_t *tx, texnums_t tn) } R_BuildDefaultTexnums(&tn, tx->shader); +#endif } #define LMT_DIFFUSE 1 #define LMT_FULLBRIGHT 2 #define LMT_BUMP 4 #define LMT_SPEC 8 -void Mod_LoadMiptex(texture_t *tx, miptex_t *mt, texnums_t *tn, int maps) +static void Mod_LoadMiptex(texture_t *tx, miptex_t *mt, texnums_t *tn, int maps) { +#ifndef SERVERONLY char altname[256]; qbyte *base; qboolean alphaed; @@ -1414,6 +1439,7 @@ void Mod_LoadMiptex(texture_t *tx, miptex_t *mt, texnums_t *tn, int maps) } } } +#endif } /* @@ -1627,6 +1653,7 @@ TRACE(("dbg: Mod_LoadTextures: inittexturedescs\n")); void Mod_NowLoadExternal(void) { +#ifndef SERVERONLY int i, width, height; qboolean alphaed; texture_t *tx; @@ -1693,6 +1720,7 @@ void Mod_NowLoadExternal(void) } Mod_FinishTexture(tx, tn); } +#endif } qbyte lmgamma[256]; @@ -1768,6 +1796,7 @@ void Mod_LoadLighting (lump_t *l) if (!samples) return; +#ifndef SERVERONLY if (!luxdata && r_loadlits.ival && r_deluxemapping.ival) { //the map util has a '-scalecos X' parameter. use 0 if you're going to use only just lux. without lux scalecos 0 is hideous. char luxname[MAX_QPATH]; @@ -1927,6 +1956,7 @@ void Mod_LoadLighting (lump_t *l) // else //failed to find } +#endif #ifdef RUNTIMELIGHTING if (r_loadlits.value == 2 && !lightmodel && (!litdata || (!luxdata && r_deluxemapping.ival))) @@ -2007,8 +2037,10 @@ void Mod_LoadLighting (lump_t *l) *out++ = lmgamma[*litdata++]; } +#ifndef SERVERONLY if ((loadmodel->engineflags & MDLF_RGBLIGHTING) && r_lightmap_saturation.value != 1.0f) SaturateR8G8B8(loadmodel->lightdata, l->filelen, r_lightmap_saturation.value); +#endif } /* @@ -2485,6 +2517,7 @@ qboolean Mod_LoadFaces (lump_t *l, qboolean lm, mesh_t **meshlist) return true; } +#ifndef SERVERONLY void ModQ1_Batches_BuildQ1Q2Poly(model_t *mod, msurface_t *surf, void *cookie) { int i, lindex; @@ -3115,7 +3148,7 @@ void Mod_Batches_Build(mesh_t *meshlist, model_t *mod, void (*build)(model_t *mo if (BE_GenBrushModelVBO) BE_GenBrushModelVBO(mod); } - +#endif /* ================= @@ -3985,27 +4018,7 @@ qboolean Mod_LoadPlanes (lump_t *l) return true; } -/* -================= -RadiusFromBounds -================= -*/ - -float RadiusFromBounds (vec3_t mins, vec3_t maxs); -/* -{ - int i; - vec3_t corner; - - for (i=0 ; i<3 ; i++) - { - corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]); - } - - return Length (corner); -} -*/ - +#ifndef SERVERONLY //combination of R_AddDynamicLights and R_MarkLights static void Q1BSP_StainNode (mnode_t *node, float *parms) { @@ -4043,6 +4056,7 @@ static void Q1BSP_StainNode (mnode_t *node, float *parms) Q1BSP_StainNode (node->children[0], parms); Q1BSP_StainNode (node->children[1], parms); } +#endif void Mod_FixupNodeMinsMaxs (mnode_t *node, mnode_t *parent) { @@ -4073,7 +4087,8 @@ void Mod_FixupNodeMinsMaxs (mnode_t *node, mnode_t *parent) } } -void Mod_FixupMinsMaxs(void) + +static void Mod_FixupMinsMaxs(void) { //q1 bsps are capped to +/- 32767 by the nodes/leafs //verts arn't though @@ -4125,17 +4140,17 @@ void Mod_FixupMinsMaxs(void) lnumverts = surf->numedges; for (en=0 ; ensurfedges[surf->firstedge + en]; + lindex = loadmodel->surfedges[surf->firstedge + en]; if (lindex > 0) { e = &pedges[lindex]; - v = currentmodel->vertexes[e->v[0]].position; + v = loadmodel->vertexes[e->v[0]].position; } else { e = &pedges[-lindex]; - v = currentmodel->vertexes[e->v[1]].position; + v = loadmodel->vertexes[e->v[1]].position; } if (pleaf->minmaxs[0] > v[0]) @@ -4184,6 +4199,9 @@ qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize) header = (dheader_t *)buffer; +#ifdef SERVERONLY + isnotmap = !!sv.world.worldmodel; +#else if ((!cl.worldmodel && cls.state>=ca_connected) #ifndef CLIENTONLY || (!sv.world.worldmodel && sv.active) @@ -4192,6 +4210,7 @@ qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize) isnotmap = false; else isnotmap = true; +#endif i = LittleLong (header->version); @@ -4267,18 +4286,10 @@ qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize) crouchhullfile = NULL; TRACE(("Loading info\n")); -#ifndef CLIENTONLY - if (sv.state) //if the server is running - { - if (!strcmp(loadmodel->name, va("maps/%s.bsp", sv.name))) - Mod_ParseInfoFromEntityLump(loadmodel, mod_base + header->lumps[LUMP_ENTITIES].fileofs, loadname); - } - else +#ifndef SERVERONLY + if (!isnotmap) + Mod_ParseInfoFromEntityLump(loadmodel, mod_base + header->lumps[LUMP_ENTITIES].fileofs, loadname); #endif - { - if (!cl.model_precache[1]) //not copied across yet - Mod_ParseInfoFromEntityLump(loadmodel, mod_base + header->lumps[LUMP_ENTITIES].fileofs, loadname); - } // load into heap if (!isDedicated || ode) @@ -4357,9 +4368,11 @@ qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize) TRACE(("LoadBrushModel %i\n", __LINE__)); Q1BSP_SetModelFuncs(mod); TRACE(("LoadBrushModel %i\n", __LINE__)); +#ifndef SERVERONLY mod->funcs.LightPointValues = GLQ1BSP_LightPointValues; - mod->funcs.StainNode = Q1BSP_StainNode; mod->funcs.MarkLights = Q1BSP_MarkLights; + mod->funcs.StainNode = Q1BSP_StainNode; +#endif mod->numframes = 2; // regular and alternate animation @@ -4371,6 +4384,7 @@ qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize) { bm = &mod->submodels[i]; + mod->rootnode = mod->nodes + bm->headnode[0]; mod->hulls[0].firstclipnode = bm->headnode[0]; mod->hulls[0].available = true; Q1BSP_CheckHullNodes(&mod->hulls[0]); @@ -4404,7 +4418,9 @@ TRACE(("LoadBrushModel %i\n", __LINE__)); TRACE(("LoadBrushModel %i\n", __LINE__)); if (meshlist) { +#ifndef SERVERONLY Mod_Batches_Build(meshlist, mod, NULL, NULL); +#endif } TRACE(("LoadBrushModel %i\n", __LINE__)); @@ -4447,6 +4463,7 @@ ALIAS MODELS //========================================================= +#ifdef SPRMODELS /* ================= Mod_LoadSpriteFrame @@ -4755,6 +4772,7 @@ qboolean QDECL Mod_LoadSpriteModel (model_t *mod, void *buffer, size_t fsize) return true; } +#endif #ifdef SP2MODELS qboolean QDECL Mod_LoadSprite2Model (model_t *mod, void *buffer, size_t fsize) @@ -4843,7 +4861,7 @@ qboolean QDECL Mod_LoadSprite2Model (model_t *mod, void *buffer, size_t fsize) } #endif -#ifdef DOOMWADS +#ifdef DSPMODELS typedef struct { short width; diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index 435778ceb..1033f965d 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -373,11 +373,13 @@ typedef struct msurface_s mtexinfo_t *texinfo; int visframe; // should be drawn when node is crossed int shadowframe; + int clipcount; -// lighting info +// legacy lighting info int dlightframe; int dlightbits; +//static lighting int lightmaptexturenums[MAXRLIGHTMAPS]; //rbsp+fbsp formats have multiple lightmaps qbyte styles[MAXQ1LIGHTMAPS]; qbyte vlstyles[MAXRLIGHTMAPS]; @@ -455,8 +457,8 @@ typedef struct mleaf_s int area; unsigned int firstleafbrush; unsigned int numleafbrushes; - unsigned int firstleafface; - unsigned int numleaffaces; + unsigned int firstleafcmesh; + unsigned int numleafcmeshes; unsigned int firstleafpatch; unsigned int numleafpatches; #endif @@ -884,6 +886,7 @@ typedef struct model_s int numnodes; mnode_t *nodes; void *cnodes; + mnode_t *rootnode; int numtexinfo; mtexinfo_t *texinfo; @@ -1014,7 +1017,6 @@ qbyte *CM_ClusterPHS (struct model_s *mod, int cluster); int CM_BoxLeafnums (struct model_s *mod, vec3_t mins, vec3_t maxs, int *list, int listsize, int *topnode); int CM_PointContents (struct model_s *mod, vec3_t p); int CM_TransformedPointContents (struct model_s *mod, vec3_t p, int headnode, vec3_t origin, vec3_t angles); -struct trace_s CM_BoxTrace (struct model_s *mod, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int brushmask); int CM_HeadnodeForBox (struct model_s *mod, vec3_t mins, vec3_t maxs); struct trace_s CM_TransformedBoxTrace (struct model_s *mod, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int brushmask, vec3_t origin, vec3_t angles); struct model_s *CM_TempBoxModel(vec3_t mins, vec3_t maxs); diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index 8e99466ac..162302274 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -1010,6 +1010,13 @@ void GLQ3_LightGrid(model_t *mod, vec3_t point, vec3_t res_diffuse, vec3_t res_a res_ambient[0] = 255; //out of the map res_ambient[1] = 255; res_ambient[2] = 255; + + if (res_diffuse) + { + res_diffuse[0] = 255; + res_diffuse[1] = 255; + res_diffuse[2] = 255; + } return; } } @@ -1209,7 +1216,7 @@ int R_LightPoint (vec3_t p) end[1] = p[1]; end[2] = p[2] - 2048; - r = GLRecursiveLightPoint (cl.worldmodel->nodes, p, end); + r = GLRecursiveLightPoint (cl.worldmodel->rootnode, p, end); if (r == -1) r = 0; @@ -1234,7 +1241,7 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end) int i; mtexinfo_t *tex; qbyte *lightmap, *deluxmap; - float scale; + float scale, overbright; int maps; if (cl.worldmodel->fromgame == fg_quake2) @@ -1309,6 +1316,7 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end) l[3]=0;l[4]=0;l[5]=0; if (lightmap) { + overbright = 1/255.0f; if (cl.worldmodel->deluxdata) { if (cl.worldmodel->engineflags & MDLF_RGBLIGHTING) @@ -1320,7 +1328,7 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end) for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { - scale = d_lightstylevalue[surf->styles[maps]]/256.0f; + scale = d_lightstylevalue[surf->styles[maps]]*overbright; if (cl_lightstyle[surf->styles[maps]].colour & 1) l[0] += lightmap[0] * scale; @@ -1349,7 +1357,7 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end) for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { - scale = d_lightstylevalue[surf->styles[maps]]/256.0f; + scale = d_lightstylevalue[surf->styles[maps]]*overbright; if (cl_lightstyle[surf->styles[maps]].colour & 1) l[0] += *lightmap * scale; @@ -1378,7 +1386,7 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end) for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { - scale = d_lightstylevalue[surf->styles[maps]]/256.0f; + scale = d_lightstylevalue[surf->styles[maps]]*overbright; if (cl_lightstyle[surf->styles[maps]].colour & 1) l[0] += lightmap[0] * scale; @@ -1398,7 +1406,7 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end) for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { - scale = d_lightstylevalue[surf->styles[maps]]/256.0f; + scale = d_lightstylevalue[surf->styles[maps]]*overbright; if (cl_lightstyle[surf->styles[maps]].colour & 1) l[0] += *lightmap * scale; @@ -1450,7 +1458,7 @@ void GLQ1BSP_LightPointValues(model_t *model, vec3_t point, vec3_t res_diffuse, end[1] = point[1]; end[2] = point[2] - 2048; - r = GLRecursiveLightPoint3C(model->nodes, point, end); + r = GLRecursiveLightPoint3C(model->rootnode, point, end); if (r == NULL) { res_diffuse[0] = 0; @@ -1467,14 +1475,14 @@ void GLQ1BSP_LightPointValues(model_t *model, vec3_t point, vec3_t res_diffuse, } else { - res_diffuse[0] = r[0]; - res_diffuse[1] = r[1]; - res_diffuse[2] = r[2]; + res_diffuse[0] = r[0]*2; + res_diffuse[1] = r[1]*2; + res_diffuse[2] = r[2]*2; /*bright on one side, dark on the other, but not too dark*/ - res_ambient[0] = r[0]/3; - res_ambient[1] = r[1]/3; - res_ambient[2] = r[2]/3; + res_ambient[0] = r[0]/2; + res_ambient[1] = r[1]/2; + res_ambient[2] = r[2]/2; res_dir[0] = r[3]; res_dir[1] = r[4]; diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 956811949..e5a4ea630 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -4607,10 +4607,17 @@ void Shader_DefaultSkinShell(const char *shortname, shader_t *s, const void *arg Shader_DefaultScript(shortname, s, "{\n" - "sort blend\n" - "deformvertexes normal 1 1\n" + "sort seethrough\n" //before blend, but after other stuff. should fix most issues with shotgun etc effects obscuring it. +// "deformvertexes normal 1 1\n" + //draw it with depth but no colours at all "{\n" - "map $diffuse\n" + "map $whiteimage\n" + "maskcolor\n" + "depthwrite\n" + "}\n" + //now draw it again, depthfunc = equal should fill only the near-side, avoiding any excess-brightness issues with overlapping triangles + "{\n" + "map $whiteimage\n" "rgbgen entity\n" "alphagen entity\n" "blendfunc blend\n" diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index b4fb555aa..c1cf13d96 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -70,32 +70,33 @@ BINDTEXFUNCPTR qglBindTexture; /*glslang - arb_shader_objects gl core uses different names/distinctions from the extension */ -FTEPFNGLCREATEPROGRAMOBJECTARBPROC qglCreateProgramObjectARB; -FTEPFNGLDELETEOBJECTARBPROC qglDeleteProgramObject_; -FTEPFNGLDELETEOBJECTARBPROC qglDeleteShaderObject_; -FTEPFNGLUSEPROGRAMOBJECTARBPROC qglUseProgramObjectARB; -FTEPFNGLCREATESHADEROBJECTARBPROC qglCreateShaderObjectARB; -FTEPFNGLSHADERSOURCEARBPROC qglShaderSourceARB; -FTEPFNGLCOMPILESHADERARBPROC qglCompileShaderARB; -FTEPFNGLGETOBJECTPARAMETERIVARBPROC qglGetShaderParameteriv_; -FTEPFNGLGETOBJECTPARAMETERIVARBPROC qglGetProgramParameteriv_; -FTEPFNGLATTACHOBJECTARBPROC qglAttachObjectARB; -FTEPFNGLGETINFOLOGARBPROC qglGetShaderInfoLog_; -FTEPFNGLGETINFOLOGARBPROC qglGetProgramInfoLog_; -FTEPFNGLLINKPROGRAMARBPROC qglLinkProgramARB; -FTEPFNGLBINDATTRIBLOCATIONARBPROC qglBindAttribLocationARB; +FTEPFNGLCREATEPROGRAMOBJECTARBPROC qglCreateProgramObjectARB; +FTEPFNGLDELETEOBJECTARBPROC qglDeleteProgramObject_; +FTEPFNGLDELETEOBJECTARBPROC qglDeleteShaderObject_; +FTEPFNGLUSEPROGRAMOBJECTARBPROC qglUseProgramObjectARB; +FTEPFNGLCREATESHADEROBJECTARBPROC qglCreateShaderObjectARB; +FTEPFNGLSHADERSOURCEARBPROC qglShaderSourceARB; +FTEPFNGLCOMPILESHADERARBPROC qglCompileShaderARB; +FTEPFNGLGETOBJECTPARAMETERIVARBPROC qglGetShaderParameteriv_; +FTEPFNGLGETOBJECTPARAMETERIVARBPROC qglGetProgramParameteriv_; +FTEPFNGLATTACHOBJECTARBPROC qglAttachObjectARB; +FTEPFNGLGETINFOLOGARBPROC qglGetShaderInfoLog_; +FTEPFNGLGETINFOLOGARBPROC qglGetProgramInfoLog_; +FTEPFNGLLINKPROGRAMARBPROC qglLinkProgramARB; +FTEPFNGLBINDATTRIBLOCATIONARBPROC qglBindAttribLocationARB; FTEPFNGLGETATTRIBLOCATIONARBPROC qglGetAttribLocationARB; -FTEPFNGLGETUNIFORMLOCATIONARBPROC qglGetUniformLocationARB; +FTEPFNGLGETUNIFORMLOCATIONARBPROC qglGetUniformLocationARB; FTEPFNGLUNIFORMMATRIXPROC qglUniformMatrix4fvARB; FTEPFNGLUNIFORMMATRIXPROC qglUniformMatrix3x4fv; FTEPFNGLUNIFORMMATRIXPROC qglUniformMatrix4x3fv; -FTEPFNGLUNIFORM4FARBPROC qglUniform4fARB; -FTEPFNGLUNIFORM4FVARBPROC qglUniform4fvARB; -FTEPFNGLUNIFORM3FARBPROC qglUniform3fARB; -FTEPFNGLUNIFORM3FVARBPROC qglUniform3fvARB; -FTEPFNGLUNIFORM4FVARBPROC qglUniform2fvARB; -FTEPFNGLUNIFORM1IARBPROC qglUniform1iARB; -FTEPFNGLUNIFORM1FARBPROC qglUniform1fARB; +FTEPFNGLUNIFORM4FARBPROC qglUniform4fARB; +FTEPFNGLUNIFORM4FVARBPROC qglUniform4fvARB; +FTEPFNGLUNIFORM3FARBPROC qglUniform3fARB; +FTEPFNGLUNIFORM3FVARBPROC qglUniform3fvARB; +FTEPFNGLUNIFORM4FVARBPROC qglUniform2fvARB; +FTEPFNGLUNIFORM1IARBPROC qglUniform1iARB; +FTEPFNGLUNIFORM1FARBPROC qglUniform1fARB; +FTEPFNGLGETSHADERSOURCEARBPROC qglGetShaderSource; #endif //standard 1.1 opengl calls void (APIENTRY *qglAlphaFunc) (GLenum func, GLclampf ref); @@ -803,6 +804,7 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) qglUniform2fvARB = NULL; qglUniform1iARB = NULL; qglUniform1fARB = NULL; + qglGetShaderSource = NULL; } // glslang //the gf2 to gf4 cards emulate vertex_shader and thus supports shader_objects. @@ -852,6 +854,7 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) qglGetVertexAttribPointerv = (void *)getglext("glGetVertexAttribPointerv"); qglEnableVertexAttribArray = (void *)getglext("glEnableVertexAttribArray"); qglDisableVertexAttribArray = (void *)getglext("glDisableVertexAttribArray"); + qglGetShaderSource = (void *)getglext("glGetShaderSource"); Con_DPrintf("GLSL available\n"); } else if (GL_CheckExtension("GL_ARB_fragment_shader") @@ -890,6 +893,7 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) qglUniform2fvARB = (void *)getglext("glUniform2fvARB"); qglUniform1iARB = (void *)getglext("glUniform1iARB"); qglUniform1fARB = (void *)getglext("glUniform1fARB"); + qglGetShaderSource = (void *)getglext("glGetShaderSourceARB"); Con_DPrintf("GLSL available\n"); } @@ -1365,12 +1369,11 @@ qboolean GLSlang_GenerateIncludes(int maxstrings, int *strings, const GLchar *pr // glslang helper api function definitions // type should be GL_FRAGMENT_SHADER_ARB or GL_VERTEX_SHADER_ARB -GLhandleARB GLSlang_CreateShader (const char *name, int ver, const char **precompilerconstants, const char *shadersource, GLenum shadertype, qboolean silent) +//doesn't check to see if it was okay. use FinishShader for that. +static GLhandleARB GLSlang_CreateShader (const char *name, int ver, const char **precompilerconstants, const char *shadersource, GLenum shadertype, qboolean silent) { GLhandleARB shader; - GLint compiled; - char str[1024]; - int loglen, i; + int i; const GLchar *prstrings[64+16]; GLint length[sizeof(prstrings)/sizeof(prstrings[0])]; int strings = 0; @@ -1511,9 +1514,24 @@ GLhandleARB GLSlang_CreateShader (const char *name, int ver, const char **precom qglShaderSourceARB(shader, strings, prstrings, length); qglCompileShaderARB(shader); + return shader; +} + +//called after CreateShader. Checks for success. +//Splitting creation allows for both vertex+fragment shaders to be processed simultaneously if the driver threads glCompileShaderARB. +static GLhandleARB GLSlang_FinishShader(GLhandleARB shader, const char *name, GLenum shadertype, qboolean silent) +{ + GLint compiled; + int loglen; + + if (!shader) //if there's no shader, then there was nothing to finish... + return shader; + qglGetShaderParameteriv_(shader, GL_OBJECT_COMPILE_STATUS_ARB, &compiled); if(!compiled) { + char str[8192]; + qglGetShaderInfoLog_(shader, sizeof(str), NULL, str); qglDeleteShaderObject_(shader); if (!silent) @@ -1530,19 +1548,11 @@ GLhandleARB GLSlang_CreateShader (const char *name, int ver, const char **precom Con_Printf("Shader_CreateShader: This shouldn't happen ever\n"); break; } - Con_DPrintf("Shader \"%s\" source:\n", name); - for (i = 0; i < strings; i++) + if (developer.ival) { - int j; - if (length[i] < 0) - Con_DPrintf("%s", prstrings[i]); - else - { - for (j = 0; j < length[i]; j++) - Con_DPrintf("%c", prstrings[i][j]); - } + qglGetShaderSource(shader, sizeof(str), NULL, str); + Con_Printf("Shader \"%s\" source:\n%s", name, str); } - Con_DPrintf("%s\n", str); } return 0; } @@ -1552,13 +1562,14 @@ GLhandleARB GLSlang_CreateShader (const char *name, int ver, const char **precom qglGetShaderParameteriv_(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &loglen); if (loglen) { + char str[8192]; + qglGetShaderInfoLog_(shader, sizeof(str), NULL, str); if (strstr(str, "WARNING")) { - Con_Printf("Shader source:\n"); - for (i = 0; i < strings; i++) - Con_Printf("%s", prstrings[i]); - Con_Printf("%s\n", str); + Con_Printf("Shader \"%s\" log:\n%s", name, str); + qglGetShaderSource(shader, sizeof(str), NULL, str); + Con_Printf("Shader \"%s\" source:\n%s", name, str); } } } @@ -1568,9 +1579,9 @@ GLhandleARB GLSlang_CreateShader (const char *name, int ver, const char **precom GLhandleARB GLSlang_CreateProgramObject (const char *name, GLhandleARB vert, GLhandleARB frag, qboolean silent) { - GLhandleARB program; - GLint linked; - char str[2048]; + GLhandleARB program; + GLint linked; + char str[2048]; program = qglCreateProgramObjectARB(); qglAttachObjectARB(program, vert); @@ -1629,8 +1640,11 @@ GLhandleARB GLSlang_CreateProgram(const char *name, int ver, const char **precom if (!precompilerconstants) precompilerconstants = &nullconstants; - vs = GLSlang_CreateShader(name, ver, precompilerconstants, vert, GL_VERTEX_SHADER_ARB, silent); fs = GLSlang_CreateShader(name, ver, precompilerconstants, frag, GL_FRAGMENT_SHADER_ARB, silent); + vs = GLSlang_CreateShader(name, ver, precompilerconstants, vert, GL_VERTEX_SHADER_ARB, silent); + + fs = GLSlang_FinishShader(fs, name, GL_FRAGMENT_SHADER_ARB, silent); + vs = GLSlang_FinishShader(vs, name, GL_VERTEX_SHADER_ARB, silent); if (!vs || !fs) handle = 0; @@ -1653,7 +1667,7 @@ GLhandleARB GLSlang_CreateProgram(const char *name, int ver, const char **precom len = ui; blobdata = BZ_Malloc(len); - qglGetProgramBinary(handle, len, NULL, &e, blobdata); + qglGetProgramBinary(handle, len, NULL, &e, blobdata); fmt = e; VFS_WRITE(blobfile, &fmt, sizeof(fmt)); diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index fa87779b7..5b99250ce 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -47,6 +47,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. void D3D9_Set2D (void); +float RadiusFromBounds (vec3_t mins, vec3_t maxs); void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs); qboolean BoundsIntersect (vec3_t mins1, vec3_t maxs1, vec3_t mins2, vec3_t maxs2); void ClearBounds (vec3_t mins, vec3_t maxs); @@ -180,6 +181,7 @@ typedef void (APIENTRYP FTEPFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei c typedef void (APIENTRYP FTEPFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP FTEPFNGLUNIFORM1IARBPROC) (GLint location, GLint v0); typedef void (APIENTRYP FTEPFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0); +typedef void (APIENTRYP FTEPFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); typedef void (APIENTRY * FTEPFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count); typedef void (APIENTRY * FTEPFNGLUNLOCKARRAYSEXTPROC) (void); diff --git a/engine/partcfgs/generatebuiltin.c b/engine/partcfgs/generatebuiltin.c index 4172637a4..7b6e7b230 100644 --- a/engine/partcfgs/generatebuiltin.c +++ b/engine/partcfgs/generatebuiltin.c @@ -9,6 +9,7 @@ char effects[][64] = "high.cfg", "minimal.cfg", "h2part.cfg", + "q2part.cfg", "tsshaft.cfg", "" }; diff --git a/engine/partcfgs/q2part.cfg b/engine/partcfgs/q2part.cfg new file mode 100644 index 000000000..5994a5b78 --- /dev/null +++ b/engine/partcfgs/q2part.cfg @@ -0,0 +1,158 @@ + +r_part pe_default +{ + texture "classicparticle" + tcoords 0 0 16 16 32 + count 1 + scale 1 + alpha 1 + die 0.3 0.8 + randomvel 20 + orgadd 0 31 + spawnorg 4 + gravity 40 + scalefactor 0.8 +} + + +r_part q2_smoke +{ + count 0 0 1 + model "models/objects/smoke/tris.md2" framestart=0 frameend=4 framerate=10 alpha=1 +} +r_part q2_smokeandflash +{ + count 0 0 1 + model "models/objects/flash/tris.md2" framestart=0 frameend=2 framerate=10 alpha=-1 fullbright + assoc q2_smoke +} + +r_part teq2_gunshot /*machinegun*/ +{ + texture "classicparticle" + tcoords 0 0 16 16 32 + count 40 + scale 1 + alpha 1 + die 0.3 0.8 + randomvel 20 + orgadd 0 31 + spawnorg 4 + gravity 40 + scalefactor 0.8 + colorindex 0 7 + /*smoke puff models*/ + assoc q2_smokeandflash + /*low chance of various sounds*/ + sound world/ric1.wav 1 1 0 0 1 + sound world/ric2.wav 1 1 0 0 1 + sound world/ric3.wav 1 1 0 0 1 + sound "" 1 1 0 0 12 +} + +r_part teq2_shotgun /*shotgun... duh*/ +{ + texture "classicparticle" + tcoords 0 0 16 16 32 + count 20 + scale 1 + alpha 1 + die 0.3 0.8 + randomvel 20 + orgadd 0 31 + spawnorg 4 + gravity 40 + scalefactor 0.8 + colorindex 0 7 + /*smoke puff models*/ + assoc q2_smokeandflash +} + +r_part teq2_blood +{ + texture "classicparticle" + tcoords 0 0 16 16 32 + count 60 + scale 1 + alpha 1 + die 0.3 0.8 + randomvel 20 + orgadd 0 31 + spawnorg 4 + gravity 40 + scalefactor 0.8 + colorindex 232 7 +} + +r_part q2_blasterpuff +{ + count 0 0 1 + model "models/objects/explode/tris.md2" framestart=0 frameend=4 framerate=10 alpha=1 orient additive fullbright noshadow +} +r_part teq2_blaster +{ + texture "classicparticle" + tcoords 0 0 16 16 32 + count 60 + scale 1 + alpha 1 + die 0.3 0.8 + randomvel 40 + orgadd 0 15 + veladd 30 + spawnorg 4 + gravity 40 + scalefactor 0.8 + colorindex 0xe0 7 + assoc q2_blasterpuff /*the model*/ + lightradius 150 + lightradiusfade 400 + lightrgb 1 1 0 + lightshadows 0 + sound "weapons/lashit.wav" 1 1 0 0 +} +r_part TR_BLASTERTRAIL +{ + texture "classicparticle" + tcoords 0 0 16 16 32 + scale 0.5 + alpha 1 + scalefactor 0.8 + step 5 + spawnorg 1 + randomvel 5 + die 0.3 0.5 + colorindex 0xe0 +} + +r_part TR_RAILTRAIL +{ + /*blue spiral*/ + texture "classicparticle" + tcoords 0 0 16 16 32 + scale 0.5 + alpha 1 + scalefactor 0.8 + step 1 + spawnmode spiral 64 + spawnorg 3 + spawnvel 6 + die 1 1.2 + colorindex 116 7 + + sound "weapons/railgf1a.wav" 1 1 0 0 +} +r_part +TR_RAILTRAIL +{ + /*grey filler*/ + texture "classicparticle" + tcoords 0 0 16 16 32 + scale 0.5 + alpha 1 + scalefactor 0.8 + step 0.75 + spawnorg 3 + spawnvel 3 + die 0.6 0.8 + colorindex 0 15 +} diff --git a/engine/server/net_preparse.c b/engine/server/net_preparse.c index ca63980c1..daf8b6c30 100644 --- a/engine/server/net_preparse.c +++ b/engine/server/net_preparse.c @@ -1329,7 +1329,7 @@ void NPP_NQWriteCoord(int dest, float in) //replacement write func (nq to qw) } else { - short datas = (int)(in*8); + short datas = (int)(in*8)&0xffff; datas = LittleShort(datas); NPP_AddData(&datas, sizeof(short)); diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index a1945e1c4..01c4ca318 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -9233,7 +9233,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"strcat", PF_strcat, 0, 0, 0, 115, "string(string s1, optional string s2, ...)"}, // (FRIK_FILE) {"substring", PF_substring, 0, 0, 0, 116, "string(string s, float start, float length)"}, // (FRIK_FILE) {"stov", PF_stov, 0, 0, 0, 117, "vector(string s)"}, // (FRIK_FILE) - {"strzone", PF_dupstring, 0, 0, 0, 118, "string(string s)"}, // (FRIK_FILE) + {"strzone", PF_dupstring, 0, 0, 0, 118, "string(string s, ...)"}, // (FRIK_FILE) {"strunzone", PF_forgetstring, 0, 0, 0, 119, "void(string s)"}, // (FRIK_FILE) //end frikfile diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index f39acfc32..bea97d518 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -1811,7 +1811,6 @@ void SV_ClientProtocolExtensionsChanged(client_t *client) { #ifdef Q3SERVER case SCP_QUAKE3: - Huff_PreferedCompressionCRC(); if (client->frameunion.q3frames) Z_Free(client->frameunion.q3frames); client->frameunion.q3frames = Z_Malloc(Q3UPDATE_BACKUP*sizeof(*client->frameunion.q3frames)); @@ -2721,7 +2720,12 @@ client_t *SVC_DirectConnect(void) //this is used by q3 (note, we already decrypted the huffman connection packet in a hack) if (!sv_listen_q3.value) + { + if (!sv_listen_nq.value) + SV_RejectMessage (SCP_DARKPLACES6, "Server is not accepting quake3 clients at this time.\n", version_string()); + Con_TPrintf ("* rejected connect from q3 client\n"); return NULL; + } numssclients = 1; protocol = SCP_QUAKE3; @@ -2748,11 +2752,20 @@ client_t *SVC_DirectConnect(void) s = Info_ValueForKey(userinfo[0], "name"); if (!*s) Info_SetValueForKey(userinfo[0], "name", "UnnamedQ3", sizeof(userinfo[0])); + +#ifdef HUFFNETWORK + huffcrc = HUFFCRC_QUAKE3; +#endif } else if (*(Cmd_Argv(0)+7) == '\\') { //DP has the userinfo attached directly to the end of the connect command if (!sv_listen_dp.value) + { + if (!sv_listen_nq.value) + SV_RejectMessage (SCP_DARKPLACES6, "Server is not accepting darkplaces clients at this time.\n", version_string()); + Con_TPrintf ("* rejected connect from dp client\n"); return NULL; + } Q_strncpyz (userinfo[0], net_message.data + 11, sizeof(userinfo[0])-1); if (strcmp(Info_ValueForKey(userinfo[0], "protocol"), "darkplaces 3")) @@ -2903,6 +2916,7 @@ client_t *SVC_DirectConnect(void) } break; case PROTOCOL_VERSION_HUFFMAN: +#ifdef HUFFNETWORK huffcrc = Q_atoi(Cmd_Argv(1)); Con_DPrintf("Client supports huffman compression. crc 0x%x\n", huffcrc); if (!net_compress.ival || !Huff_CompressionCRC(huffcrc)) @@ -2911,6 +2925,7 @@ client_t *SVC_DirectConnect(void) Con_TPrintf ("* rejected - bad compression state\n"); return NULL; } +#endif break; case PROTOCOL_VERSION_FRAGMENT: mtu = Q_atoi(Cmd_Argv(1)) & ~7; @@ -3265,6 +3280,13 @@ client_t *SVC_DirectConnect(void) case GT_LUA: #endif case GT_PROGS: + if (protocol == SCP_QUAKE2) + { + SV_RejectMessage(protocol, "This is a Quake server."); + Con_DPrintf ("* Rejected q2 client.\n"); + return NULL; + } + if (svprogfuncs) ent = EDICT_NUM(svprogfuncs, edictnum); else @@ -3279,6 +3301,7 @@ client_t *SVC_DirectConnect(void) if (reject) { SV_RejectMessage(protocol, "%s", reject); + Con_DPrintf ("* Game rejected a connection.\n"); return NULL; } } @@ -3287,12 +3310,26 @@ client_t *SVC_DirectConnect(void) #ifdef Q2SERVER case GT_QUAKE2: + if (protocol != SCP_QUAKE2) + { + SV_RejectMessage(protocol, "This is a Quake2 server."); + Con_DPrintf ("* Rejected non-q2 client.\n"); + return NULL; + } q2ent = Q2EDICT_NUM(edictnum); temp.edict = NULL; temp.q2edict = q2ent; if (!ge->ClientConnect(q2ent, temp.userinfo)) + { + const char *reject = Info_ValueForKey(temp.userinfo, "rejmsg"); + if (*reject) + SV_RejectMessage(protocol, "%s\nConnection Refused.", reject); + else + SV_RejectMessage(protocol, "Connection Refused."); + Con_DPrintf ("Game rejected a connection.\n"); return NULL; + } ge->ClientUserinfoChanged(q2ent, temp.userinfo); @@ -3337,10 +3374,12 @@ client_t *SVC_DirectConnect(void) Netchan_Setup (NS_SERVER, &newcl->netchan, &adr, qport); +#ifdef HUFFNETWORK if (huffcrc) - newcl->netchan.compress = true; + newcl->netchan.compresstable = Huff_CompressionCRC(huffcrc); else - newcl->netchan.compress = false; +#endif + newcl->netchan.compresstable = NULL; if (mtu >= 64) { newcl->netchan.fragmentsize = mtu; @@ -3929,7 +3968,9 @@ qboolean SV_ConnectionlessPacket (void) if (!strstr(s, "\\name\\")) { //if name isn't in the string, assume they're q3 //this isn't quite true though, hence the listen check. but users shouldn't be connecting with an empty name anyway. more fool them. +#ifdef HUFFNETWORK Huff_DecryptPacket(&net_message, 12); +#endif MSG_BeginReading(svs.netprim); MSG_ReadLong(); s = MSG_ReadStringLine(); diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 05fd5de82..52b30d401 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -604,7 +604,7 @@ void SVNQ_New_f (void) // set view MSG_WriteByte (&host_client->netchan.message, svc_setview); - MSG_WriteEntity (&host_client->netchan.message, NUM_FOR_EDICT(svprogfuncs, host_client->edict)); + MSG_WriteEntity (&host_client->netchan.message, host_client - svs.clients);//NUM_FOR_EDICT(svprogfuncs, host_client->edict)); MSG_WriteByte (&host_client->netchan.message, svc_signonnum); MSG_WriteByte (&host_client->netchan.message, 1); @@ -4643,7 +4643,10 @@ void SVNQ_Spawn_f (void) // set up the edict ent = host_client->edict; - if (host_client->istobeloaded) //minimal setup + if (!ent) + { + } + else if (host_client->istobeloaded) //minimal setup { host_client->entgravity = ent->xv->gravity*sv_gravity.value; host_client->maxspeed = ent->xv->maxspeed; @@ -4669,21 +4672,30 @@ void SVNQ_Spawn_f (void) memset (host_client->statsf, 0, sizeof(host_client->statsf)); memset (host_client->statss, 0, sizeof(host_client->statss)); - ClientReliableWrite_Begin (host_client, svcnq_updatestatlong, 6); - ClientReliableWrite_Byte (host_client, STAT_TOTALSECRETS); - ClientReliableWrite_Long (host_client, pr_global_struct->total_secrets); - - ClientReliableWrite_Begin (host_client, svcnq_updatestatlong, 6); - ClientReliableWrite_Byte (host_client, STAT_TOTALMONSTERS); - ClientReliableWrite_Long (host_client, pr_global_struct->total_monsters); - - ClientReliableWrite_Begin (host_client, svcnq_updatestatlong, 6); - ClientReliableWrite_Byte (host_client, STAT_SECRETS); - ClientReliableWrite_Long (host_client, pr_global_struct->found_secrets); - - ClientReliableWrite_Begin (host_client, svcnq_updatestatlong, 6); - ClientReliableWrite_Byte (host_client, STAT_MONSTERS); - ClientReliableWrite_Long (host_client, pr_global_struct->killed_monsters); + if (pr_global_ptrs->total_secrets) + { + ClientReliableWrite_Begin (host_client, svcnq_updatestatlong, 6); + ClientReliableWrite_Byte (host_client, STAT_TOTALSECRETS); + ClientReliableWrite_Long (host_client, pr_global_struct->total_secrets); + } + if (pr_global_ptrs->total_monsters) + { + ClientReliableWrite_Begin (host_client, svcnq_updatestatlong, 6); + ClientReliableWrite_Byte (host_client, STAT_TOTALMONSTERS); + ClientReliableWrite_Long (host_client, pr_global_struct->total_monsters); + } + if (pr_global_ptrs->found_secrets) + { + ClientReliableWrite_Begin (host_client, svcnq_updatestatlong, 6); + ClientReliableWrite_Byte (host_client, STAT_SECRETS); + ClientReliableWrite_Long (host_client, pr_global_struct->found_secrets); + } + if (pr_global_ptrs->killed_monsters) + { + ClientReliableWrite_Begin (host_client, svcnq_updatestatlong, 6); + ClientReliableWrite_Byte (host_client, STAT_MONSTERS); + ClientReliableWrite_Long (host_client, pr_global_struct->killed_monsters); + } MSG_WriteByte (&host_client->netchan.message, svc_signonnum); MSG_WriteByte (&host_client->netchan.message, 3); @@ -4847,7 +4859,7 @@ void SVNQ_NQColour_f (void) playercolor = top*16 + bottom; - if (progstype != PROG_QW) + if (progstype != PROG_QW && host_client->edict) host_client->edict->v->team = bottom + 1; Info_SetValueForKey(host_client->userinfo, "topcolor", va("%i", top), sizeof(host_client->userinfo)); diff --git a/engine/server/svq2_game.c b/engine/server/svq2_game.c index 32bf51486..ea8364812 100644 --- a/engine/server/svq2_game.c +++ b/engine/server/svq2_game.c @@ -825,8 +825,11 @@ qboolean SVQ2_InitGameProgs(void) return false; } + //stop q2 from crashing. if (!deathmatch.value && !coop.value) maxclients.value = 1; + else + maxclients.value = maxclients.ival; if (maxclients.value > MAX_CLIENTS) Cvar_SetValue(&maxclients, MAX_CLIENTS); diff --git a/engine/server/svq3_game.c b/engine/server/svq3_game.c index d3c708de9..5967b0f3a 100644 --- a/engine/server/svq3_game.c +++ b/engine/server/svq3_game.c @@ -2544,7 +2544,7 @@ void SVQ3Q1_SendGamestateConfigstrings(sizebuf_t *msg) str = refpacknames;//FS_GetPackNames(buffer, sizeof(buffer), true); Info_SetValueForKey(sysinfo, "sv_referencedPakNames", str, sizeof(sysinfo)); -Con_Printf("Sysinfo: %s\n", sysinfo); +//Con_Printf("Sysinfo: %s\n", sysinfo); str = "0"; Info_SetValueForKey(sysinfo, "sv_pure", str, sizeof(sysinfo)); @@ -3223,7 +3223,9 @@ void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and if (net_message.cursize < 13) return; +#ifdef HUFFNETWORK Huff_DecryptPacket(&net_message, 12); +#endif Cmd_TokenizeString((char*)net_message.data+4, false, false); @@ -3235,7 +3237,15 @@ void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and if (!cl) cl = SVQ3_FindEmptyPlayerSlot(); - if (!cl) +#ifdef HUFFNETWORK + if (!Huff_CompressionCRC(HUFFCRC_QUAKE3)) + { + reason = "Could not set up compression."; + userinfo = NULL; + } + else +#endif + if (!cl) { reason = "Server is full."; userinfo = NULL; @@ -3251,10 +3261,6 @@ void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and reason = "Invalid challenge"; else { -#ifndef SERVERONLY - if (net_from.type == NA_LOOPBACK) - cls.challenge = challenge = 500; -#endif Q_strncpyz(cl->userinfo, userinfo, sizeof(cl->userinfo)); reason = NET_AdrToString(adr, sizeof(adr), &net_from); Info_SetValueForStarKey(cl->userinfo, "ip", reason, sizeof(cl->userinfo)); @@ -3290,8 +3296,6 @@ void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and NET_SendPacket (NS_SERVER, 19, "\377\377\377\377connectResponse", &net_from); - Huff_PreferedCompressionCRC(); - cl->frameunion.q3frames = BZ_Malloc(Q3UPDATE_BACKUP*sizeof(*cl->frameunion.q3frames)); }