/* Copyright (C) 1997-2001 Id Software, Inc. Copyright (C) 2000-2002 Mr. Hyde and Mad Dog This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "g_local.h" /* //#ifdef KMQUAKE2_ENGINE_MOD //#define NEW_FOGSYS //#endif */ // Fog is sent to engine like this: // gi.WriteByte (svc_fog); // svc_fog = 21 // gi.WriteByte (fog_enable); // 1 = on, 0 = off // gi.WriteByte (fog_model); // 0, 1, or 2 // gi.WriteByte (fog_density); // 1-100 // gi.WriteShort (fog_near); // >0, < fog_far // gi.WriteShort (fog_far); // >fog_near-64, < 10000 // gi.WriteByte (fog_red); // 0-255 // gi.WriteByte (fog_green); // 0-255 // gi.WriteByte (fog_blue); // 0-255 // gi.unicast (player_ent, true); #ifdef DISABLE_FOG void Fog_Init (void) {} void Fog (edict_t *ent) {} void Fog_Off (edict_t *ent) {} void Fog_Off_Global (void) {} void Fog_ConsoleFog (void) {} void GLFog (void) {} void trig_fog_fade (edict_t *self) {} void init_trigger_fog_delay (edict_t *self) {} void fog_fade (edict_t *self) {} void target_fog_use (edict_t *self, edict_t *other, edict_t *activator) {} void trigger_fog_use (edict_t *self, edict_t *other, edict_t *activator) {} void SP_trigger_fog (edict_t *self) { G_FreeEdict(self); } void SP_trigger_fog_bbox (edict_t *self) { G_FreeEdict(self); } void SP_target_fog (edict_t *self) { G_FreeEdict(self); } void Cmd_Fog_f (edict_t *ent) {} #else // DISABLE_FOG #ifdef NEW_FOGSYS // new multi-client fog code here /* ================================================= NEW FOG SYSTEM ================================================= */ void Client_Fog_Off (edict_t *player_ent) { if (!player_ent || !player_ent->client || player_ent->is_bot) return; gi.WriteByte (svc_fog); // svc_fog = 21 gi.WriteByte (0); // disable message, remaining paramaters are ignored gi.WriteByte (0); // 0, 1, or 2 gi.WriteByte (0); // 1-100 gi.WriteShort (0); // >0, fog_near-64, < 10000 gi.WriteByte (0); // 0-255 gi.WriteByte (0); // 0-255 gi.WriteByte (0); // 0-255 gi.unicast (player_ent, true); } #else // NEW_FOGSYS /* ================================================= OLD FOG SYSTEM ================================================= */ #ifdef KMQUAKE2_ENGINE_MOD // engine fog #define GL_LINEAR 0x2601 #define GL_EXP 0x0800 #define GL_EXP2 0x0801 #else // old sever-side fog #include #define __MSC__ #include #endif // KMQUAKE2_ENGINE_MOD fog_t gfogs[MAX_FOGS]; fog_t trig_fade_fog; fog_t fade_fog; fog_t *pfog; qboolean InTriggerFog; float last_software_frame; float last_opengl_frame; int GLModels[3] = {GL_LINEAR, GL_EXP, GL_EXP2}; #ifdef KMQUAKE2_ENGINE_MOD // engine fog int last_fog_model, last_fog_density, last_fog_near, last_fog_far, last_fog_color[3]; #else // old sever-side fog HMODULE hOpenGL; typedef void (WINAPI *GLCLEARCOLOR) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); typedef void (WINAPI *GLDISABLE) (GLenum cap); typedef void (WINAPI *GLENABLE) (GLenum cap); typedef void (WINAPI *GLFOGF) (GLenum pname, GLfloat param); typedef void (WINAPI *GLFOGFV) (GLenum pname, const GLfloat *params); typedef void (WINAPI *GLFOGI) (GLenum pname, GLint param); typedef void (WINAPI *GLHINT) (GLenum target, GLenum mode); GLCLEARCOLOR GL_glClearColor; GLDISABLE GL_glDisable; GLENABLE GL_glEnable; GLFOGF GL_glFogf; GLFOGFV GL_glFogfv; GLFOGI GL_glFogi; GLHINT GL_glHint; #endif // KMQUAKE2_ENGINE_MOD #define FOG_ON 1 #define FOG_TOGGLE 2 #define FOG_TURNOFF 4 #define FOG_STARTOFF 8 #define COLOR(r,g,b) ((((BYTE)(b)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(r))<<16))) void fog_fade (edict_t *self); void Fog_ConsoleFog (void) { // This routine is ONLY called for console fog commands if (deathmatch->value || coop->value) return; if (!level.active_fog) return; memcpy(&level.current_fog, &gfogs[0], sizeof(fog_t)); pfog = &level.current_fog; // Force sensible values for linear: if ( (pfog->Model == 0) && (pfog->Near == 0.0f) && (pfog->Far == 0.0f) ) { pfog->Near=64; pfog->Far=1024; } } void Cmd_Say_f (edict_t *ent, qboolean team, qboolean arg0); void Cmd_Fog_f (edict_t *ent) { char *cmd; char *parm; fog_t *fog; fog = &gfogs[0]; cmd = gi.argv(0); if (gi.argc() < 2) parm = NULL; else parm = gi.argv(1); if (!ent || !ent->client || ent->is_bot) return; if (Q_stricmp (cmd, "fog_help") == 0 ) { gi.dprintf("Fog parameters for console only.\n" "Use fog_active to see parameters for currently active fog.\n"); gi.dprintf("\nUse \"fog [0/1]\" to turn fog off/on (currently %s)\n" "Current GL driver is %s\n",(level.active_fog > 0 ? "on" : "off"), gl_driver->string); gi.dprintf("Fog_Red = red component (0-1)\n" "Fog_Grn = green component (0-1)\n" "Fog_Blu = blue component (0-1)\n" "Fog_Model 0=linear, 1=exponential, 2=exponential squared\n\n" "Linear parameters:\n" "Fog_Near = fog start distance (>0 and < Fog_Far)\n" "Fog_Far = distance where objects are completely obscured\n" " (<10000 and > Fog_Near)\n" "Exponential parameters:\n" "Fog_Density Best results with values < 100\n\n" "Command without a value will show current setting\n"); } else if (Q_stricmp (cmd, "fog_active") == 0 ) { if (level.active_fog) { gi.dprintf("Active fog:\n" " Color: %f, %f, %f\n" " Model: %s\n", level.current_fog.Color[0], level.current_fog.Color[1], level.current_fog.Color[2], ((level.current_fog.Model == 1) ? "Exp" : ((level.current_fog.Model == 2) ? "Exp2" : "Linear"))); if (level.current_fog.Model) gi.dprintf("Density: %f\n", level.current_fog.Density); else { gi.dprintf(" Near: %f\n", level.current_fog.Near); gi.dprintf(" Far: %f\n", level.current_fog.Far); } } else gi.dprintf("No fogs currently active\n"); } else if (Q_stricmp (cmd, "fog_stuff") == 0 ) { gi.dprintf("active_fog=%d, last_active_fog=%d\n",level.active_fog,level.last_active_fog); } else if (Q_stricmp (cmd, "fog") == 0 ) { if (parm) { int on; on = atoi(parm); level.active_fog = level.active_target_fog = (on ? 1 : 0); Fog_ConsoleFog(); } gi.dprintf("fog is %s\n",(level.active_fog ? "on" : "off")); } else if (Q_stricmp (cmd, "Fog_Red") == 0 ) { if (!parm) gi.dprintf("%s = %f\n",cmd,fog->Color[0]); else { level.active_fog = level.active_target_fog = 1; fog->Color[0] = max(0.0f,min(1.0f,(float)atof(parm))); Fog_ConsoleFog(); } } else if (Q_stricmp (cmd, "Fog_Grn") == 0 ) { if (!parm) gi.dprintf("%s = %f\n",cmd,fog->Color[1]); else { level.active_fog = level.active_target_fog = 1; fog->Color[1] = max(0.0f,min(1.0f,(float)atof(parm))); Fog_ConsoleFog(); } } else if (Q_stricmp (cmd, "Fog_Blu") == 0 ) { if (!parm) gi.dprintf("%s = %f\n",cmd,fog->Color[2]); else { level.active_fog = level.active_target_fog = 1; fog->Color[2] = max(0.0f,min(1.0f,(float)atof(parm))); Fog_ConsoleFog(); } } else if (Q_stricmp (cmd, "Fog_Near") == 0 ) { if (!parm) gi.dprintf("%s = %f\n",cmd,fog->Near); else { level.active_fog = level.active_target_fog = 1; fog->Near = (float)atof(parm); Fog_ConsoleFog(); } } else if (Q_stricmp (cmd, "Fog_Far") == 0 ) { if (!parm) gi.dprintf("%s = %f\n",cmd,fog->Far); else { level.active_fog = level.active_target_fog = 1; fog->Far = (float)atof(parm); Fog_ConsoleFog(); } } else if (Q_stricmp (cmd, "Fog_Model") == 0 ) { if (!parm) gi.dprintf("%s = %d\n0=Linear\n1=Exp\n2=Exp2\n",cmd,fog->Model); else { level.active_fog = level.active_target_fog = 1; //fog->Model = max(0,min(2,atoi(parm))); fog->Model = max(0,min(3,atoi(parm))); if (fog->Model == 3) fog->GL_Model = GLModels[2]; else fog->GL_Model = GLModels[fog->Model]; Fog_ConsoleFog(); } } else if (Q_stricmp (cmd, "Fog_Density") == 0 ) { if (!parm) gi.dprintf("%s = %f\n",cmd,fog->Density); else { level.active_fog = level.active_target_fog = 1; fog->Density = fog->Density1 = fog->Density2 = (float)atof(parm); Fog_ConsoleFog(); } } else if (Q_stricmp (cmd, "Fog_List") == 0 ) { int i; fog_t *cFog; gi.dprintf("level.num_fogs=%d\n", level.num_fogs); gi.dprintf("level.num_trigger_fogs=%d\n", level.num_trigger_fogs); for (i=0; iTrigger ? "true" : "false")); gi.dprintf("Model=%d, Near=%g, Far=%g, Density=%g\n", cFog->Model, cFog->Near, cFog->Far, cFog->Density); gi.dprintf("Color=%g,%g,%g\n", cFog->Color[0],cFog->Color[1],cFog->Color[2]); gi.dprintf("Targetname=%s\n", (cFog->ent ? cFog->ent->targetname : "no ent")); } } else Cmd_Say_f (ent, false, true); } /* void SoftwareFog (edict_t *ent) { if (!ent || !ent->client) // || ent->is_bot) return; ent->client->fadein = level.framenum - 1; ent->client->fadehold = level.framenum + 2; ent->client->fadeout = 0.0f; ent->client->fadecolor[0] = pfog->Color[0]; ent->client->fadecolor[1] = pfog->Color[1]; ent->client->fadecolor[2] = pfog->Color[2]; if (pfog->Model == 0) ent->client->fadealpha = pfog->Far / 256.0f; else if (pfog->Model == 1) ent->client->fadealpha = pfog->Density / 30.0f; else ent->client->fadealpha = pfog->Density / 15.0f; if (ent->client->fadealpha > 0.9f) ent->client->fadealpha = 0.9f; last_software_frame = level.framenum; } */ void GLFog (edict_t *ent) { #ifdef KMQUAKE2_ENGINE_MOD // engine fog // edict_t *player_ent = &g_edicts[1]; int fog_model, fog_density, fog_near, fog_far, fog_color[3]; if (!ent || !ent->client || ent->is_bot) return; if (pfog->GL_Model == GL_EXP) fog_model = 1; else if (pfog->GL_Model == GL_EXP2) fog_model = 2; else // GL_LINEAR fog_model = 0; fog_density = (int)(pfog->Density); fog_near = (int)(pfog->Near); fog_far = (int)(pfog->Far); fog_color[0] = (int)(pfog->Color[0]*255); fog_color[1] = (int)(pfog->Color[1]*255); fog_color[2] = (int)(pfog->Color[2]*255); // check for change in fog state before updating if ( fog_model == last_fog_model && fog_density == last_fog_density && fog_near == last_fog_near && fog_far == last_fog_far && fog_color[0] == last_fog_color[0] && fog_color[1] == last_fog_color[1] && fog_color[2] == last_fog_color[2] ) return; gi.WriteByte (svc_fog); // svc_fog = 21 gi.WriteByte (1); // enable message gi.WriteByte (fog_model); // model 0, 1, or 2 gi.WriteByte (fog_density); // density 1-100 gi.WriteShort (fog_near); // near >0, < fog_far gi.WriteShort (fog_far); // far >fog_near-64, < 10000 gi.WriteByte (fog_color[0]); // red 0-255 gi.WriteByte (fog_color[1]); // green 0-255 gi.WriteByte (fog_color[2]); // blue 0-255 gi.unicast (ent, true); // write to last fog state last_fog_model = fog_model; last_fog_density = fog_density; last_fog_near = fog_near; last_fog_far = fog_far; VectorCopy (fog_color, last_fog_color); #else // old sever-side fog GLfloat fogColor[4]; if (!hOpenGL) return; fogColor[0] = pfog->Color[0]; fogColor[1] = pfog->Color[1]; fogColor[2] = pfog->Color[2]; fogColor[3] = 1.0; GL_glEnable (GL_FOG); // turn on fog, otherwise you won't see any GL_glClearColor ( fogColor[0], fogColor[1], fogColor[2], fogColor[3]); // Clear the background color to the fog color GL_glFogi (GL_FOG_MODE, pfog->GL_Model); GL_glFogfv (GL_FOG_COLOR, fogColor); if (pfog->GL_Model == GL_LINEAR) { GL_glFogf (GL_FOG_START, pfog->Near); GL_glFogf (GL_FOG_END, pfog->Far); } else GL_glFogf (GL_FOG_DENSITY, pfog->Density/10000.f); GL_glHint (GL_FOG_HINT, GL_NICEST); #endif // KMQUAKE2_ENGINE_MOD last_opengl_frame = level.framenum; } void trig_fog_fade (edict_t *self) { float frames; int index; if (!InTriggerFog) { self->nextthink = 0; return; } if (level.framenum <= self->goal_frame) { index = self->fog_index-1; frames = self->goal_frame - level.framenum + 1; if (trig_fade_fog.Model == 0) { trig_fade_fog.Near += (gfogs[index].Near - trig_fade_fog.Near)/frames; trig_fade_fog.Far += (gfogs[index].Far - trig_fade_fog.Far )/frames; } else { trig_fade_fog.Density += (gfogs[index].Density - trig_fade_fog.Density) /frames; trig_fade_fog.Density1 += (gfogs[index].Density1 - trig_fade_fog.Density1)/frames; trig_fade_fog.Density2 += (gfogs[index].Density2 - trig_fade_fog.Density2)/frames; } trig_fade_fog.Color[0] += (gfogs[index].Color[0] - trig_fade_fog.Color[0])/frames; trig_fade_fog.Color[1] += (gfogs[index].Color[1] - trig_fade_fog.Color[1])/frames; trig_fade_fog.Color[2] += (gfogs[index].Color[2] - trig_fade_fog.Color[2])/frames; trig_fade_fog.GL_Model = GLModels[trig_fade_fog.Model]; self->nextthink = level.time + FRAMETIME; gi.linkentity(self); } } void init_trigger_fog_delay (edict_t *self) { int i; int index; edict_t *e; index = self->fog_index-1; // scan for other trigger_fog's that are currently "thinking", iow // the trigger_fog has a delay and is ramping. If found, stop the ramp for those fogs for (i=1, e=g_edicts+i; iinuse) continue; if (e == self) continue; if (e->think == trig_fog_fade || e->think == fog_fade) { e->think = NULL; e->nextthink = 0; gi.linkentity(e); } } self->spawnflags |= FOG_ON; if (!level.active_fog) { // Fog isn't currently on memcpy(&level.current_fog, &gfogs[index], sizeof(fog_t)); level.current_fog.Near = 4999.0f; level.current_fog.Far = 5000.0f; level.current_fog.Density = 0.0f; level.current_fog.Density1 = 0.0f; level.current_fog.Density2 = 0.0f; } VectorCopy(self->fog_color,gfogs[index].Color); gfogs[index].Near = self->fog_near; gfogs[index].Far = self->fog_far; gfogs[index].Density = self->fog_density; gfogs[index].Density1 = self->fog_density; gfogs[index].Density2 = self->density; self->goal_frame = level.framenum + self->delay*10 + 1; self->think = trig_fog_fade; self->nextthink = level.time + FRAMETIME; memcpy(&trig_fade_fog, &level.current_fog, sizeof(fog_t)); level.active_fog = self->fog_index; } void Fog (edict_t *ent) { edict_t *triggerfog; // edict_t *player = ent; //&g_edicts[1]; vec3_t viewpoint; if (!gl_driver || !vid_ref) return; if (deathmatch->value || coop->value) return; if (!ent || !ent->client || ent->is_bot) return; VectorCopy(ent->s.origin, viewpoint); viewpoint[2] += ent->viewheight; if (Q_stricmp(vid_ref->string,"gl")) { last_software_frame = level.framenum; level.active_fog = 0; return; } InTriggerFog = false; if (level.num_trigger_fogs) { int i; int trigger; trigger = 0; for (i=1; iinuse) continue; if (!(gfogs[i].ent->spawnflags & FOG_ON)) continue; if (viewpoint[0] < gfogs[i].ent->absmin[0]) continue; if (viewpoint[0] > gfogs[i].ent->absmax[0]) continue; if (viewpoint[1] < gfogs[i].ent->absmin[1]) continue; if (viewpoint[1] > gfogs[i].ent->absmax[1]) continue; if (viewpoint[2] < gfogs[i].ent->absmin[2]) continue; if (viewpoint[2] > gfogs[i].ent->absmax[2]) continue; trigger = i; break; } if (trigger) { InTriggerFog = true; triggerfog = gfogs[trigger].ent; if (level.last_active_fog != trigger+1) { if (triggerfog->delay) init_trigger_fog_delay(triggerfog); else memcpy(&level.current_fog, &gfogs[trigger], sizeof(fog_t)); level.active_fog = trigger+1; } else if (triggerfog->delay) memcpy(&level.current_fog, &trig_fade_fog, sizeof(fog_t)); } else { InTriggerFog = false; level.active_fog = level.active_target_fog; // if we are just coming out of a trigger_fog, force // level.current_fog to last active target_fog values if (level.active_fog && level.last_active_fog && gfogs[level.last_active_fog-1].Trigger) { edict_t *ent = gfogs[level.active_fog-1].ent; if (ent && (ent->think == fog_fade)) ent->think(ent); else memcpy(&level.current_fog, &gfogs[level.active_fog-1], sizeof(fog_t)); } } } if (!level.active_fog) { if (level.last_active_fog) Fog_Off (ent); level.last_active_fog = 0; return; } pfog = &level.current_fog; if ((pfog->Density1 != pfog->Density2) && (game.maxclients == 1) && (pfog->Model)) { float density; float dp; vec3_t vp; AngleVectors(ent->client->ps.viewangles,vp,0,0); dp = DotProduct(pfog->Dir,vp) + 1.0; density = ((pfog->Density1*dp) + (pfog->Density2*(2.0-dp)))/2.; if (pfog->Density != density) { pfog->Density = density; } } GLFog (ent); level.last_active_fog = level.active_fog; } void Fog_Off (edict_t *ent) { if (deathmatch->value || coop->value) return; // If game is shutting down, g_edicts will likely be invalid // and the client will clear the fog automatically // if (gameShutdown) // return; if (!ent || !ent->client || ent->is_bot) return; #ifdef KMQUAKE2_ENGINE_MOD // engine fog gi.WriteByte (svc_fog); // svc_fog = 21 gi.WriteByte (0); // disable message, remaining paramaters are ignored gi.WriteByte (0); // 0, 1, or 2 gi.WriteByte (0); // 1-100 gi.WriteShort (0); // >0, < fog_far gi.WriteShort (0); // >fog_near-64, < 10000 gi.WriteByte (0); // 0-255 gi.WriteByte (0); // 0-255 gi.WriteByte (0); // 0-255 gi.unicast (ent, true); // write to last fog state last_fog_model = last_fog_density = last_fog_near = last_fog_far = 0; VectorSet (last_fog_color, 255, 255, 255); #else // old sever-side fog if (gl_driver && vid_ref) { if (!strcmp(vid_ref->string,"gl")) { if (hOpenGL) GL_glDisable (GL_FOG); } else { ent->client->fadein = 0; } } #endif // KMQUAKE2_ENGINE_MOD } void Fog_Off_Global (void) { #ifndef KMQUAKE2_ENGINE_MOD // old sever-side fog if (gl_driver && vid_ref) { if (!strcmp(vid_ref->string, "gl")) { if (hOpenGL) GL_glDisable (GL_FOG); } else { edict_t *player; player = &g_edicts[1]; player->client->fadein = 0; } } #endif // KMQUAKE2_ENGINE_MOD } void Fog_Init (void) { #ifndef KMQUAKE2_ENGINE_MOD char GL_Lib[64]; if (gl_driver_fog && strlen(gl_driver_fog->string)) // strncpy(GL_Lib, gl_driver_fog->string); Q_strncpyz(GL_Lib, gl_driver_fog->string, sizeof(GL_Lib)); else // strncpy(GL_Lib, "opengl32"); Q_strncpyz(GL_Lib, "opengl32", sizeof(GL_Lib)); // strncat(GL_Lib,".dll"); Q_strncatz(GL_Lib,".dll", sizeof(GL_Lib)); hOpenGL = LoadLibrary(GL_Lib); if (hOpenGL) { GL_glClearColor = (GLCLEARCOLOR)GetProcAddress(hOpenGL,"glClearColor"); GL_glDisable = (GLDISABLE)GetProcAddress(hOpenGL,"glDisable"); GL_glEnable = (GLENABLE)GetProcAddress(hOpenGL,"glEnable"); GL_glFogf = (GLFOGF)GetProcAddress(hOpenGL,"glFogf"); GL_glFogfv = (GLFOGFV)GetProcAddress(hOpenGL,"glFogfv"); GL_glFogi = (GLFOGI)GetProcAddress(hOpenGL,"glFogi"); GL_glHint = (GLHINT)GetProcAddress(hOpenGL,"glHint"); } #endif // KMQUAKE2_ENGINE_MOD gfogs[0].Color[0] = gfogs[0].Color[1] = gfogs[0].Color[2] = 0.5; gfogs[0].Model = 1; gfogs[0].GL_Model = GLModels[1]; gfogs[0].Density = 20.; gfogs[0].Trigger = false; #ifdef KMQUAKE2_ENGINE_MOD // engine fog // write to last fog state last_fog_model = last_fog_density = last_fog_near = last_fog_far = 0; VectorSet (last_fog_color, 255, 255, 255); #endif // KMQUAKE2_ENGINE_MOD } void fog_fade (edict_t *self) { float frames; int index; if (level.framenum <= self->goal_frame) { index = self->fog_index-1; frames = self->goal_frame - level.framenum + 1; if (fade_fog.Model == 0) { fade_fog.Near += (gfogs[index].Near - fade_fog.Near)/frames; fade_fog.Far += (gfogs[index].Far - fade_fog.Far )/frames; } else { fade_fog.Density += (gfogs[index].Density - fade_fog.Density) /frames; fade_fog.Density1 += (gfogs[index].Density1 - fade_fog.Density1)/frames; fade_fog.Density2 += (gfogs[index].Density2 - fade_fog.Density2)/frames; } fade_fog.Color[0] += (gfogs[index].Color[0] - fade_fog.Color[0])/frames; fade_fog.Color[1] += (gfogs[index].Color[1] - fade_fog.Color[1])/frames; fade_fog.Color[2] += (gfogs[index].Color[2] - fade_fog.Color[2])/frames; fade_fog.GL_Model = GLModels[fade_fog.Model]; self->nextthink = level.time + FRAMETIME; if (!InTriggerFog) memcpy(&level.current_fog, &fade_fog, sizeof(fog_t)); gi.linkentity(self); } else { // if (!(self->spawnflags & FOG_ON)) if (self->spawnflags & FOG_TURNOFF) level.active_fog = level.active_target_fog = 0; } } #endif // NEW_FOGSYS // The fog entity code works for both systems /*QUAKED target_fog (1 0 0) (-8 -8 -8) (8 8 8) ADDITIVE NEGATIVE Change the fog effects. ADDITIVE : adds the target_fog settings to the current settings NEGATIVE : subtracts the target_fog settings from the current settings fog_color : The colour of the fog, the colour picker box can (and should IMO) be used. fog_density : The density of the fog, dens*10K (exp&exp2) Default=20 fog_model : Choices are: 0 :Linear (Default) 1 :Exponential 2 :Exponential2 fog_near : How close the player must get before he sees the fog. Default=64 fog_far : How far the player can see into the fog. Default=1024 density : Specifies how player see fog. Direction is in degrees. Default=0 delay : Ramp time in seconds count : Number of times it can be used */ void target_fog_use (edict_t *self, edict_t *other, edict_t *activator) { int i; int index; edict_t *e; if (!self) return; // if (!activator || !activator->client) // return; self->count--; if (self->count == 0) { self->think = G_FreeEdict; self->nextthink = level.time + self->delay + 1; } if ((self->spawnflags & FOG_ON) && (self->spawnflags & FOG_TOGGLE)) { self->spawnflags &= ~FOG_ON; return; } else self->spawnflags |= FOG_ON; index = self->fog_index-1; InTriggerFog = false; // scan for other target_fog's that are currently "thinking", iow // the target_fog has a delay and is ramping. If found, stop the ramp for those fogs for (i=1, e=g_edicts+i; iinuse) continue; if (e->think == fog_fade) { e->nextthink = 0; gi.linkentity(e); } } if (self->spawnflags & FOG_TURNOFF) { // Fog is "turn off" only if ( self->delay && level.active_fog ) { gfogs[index].Far = 5000.0f; gfogs[index].Near = 4999.0f; gfogs[index].Density = 0.0f; gfogs[index].Density1 = 0.0f; gfogs[index].Density2 = 0.0f; VectorCopy(level.current_fog.Color,gfogs[index].Color); self->goal_frame = level.framenum + self->delay*10 + 1; self->think = fog_fade; self->nextthink = level.time + FRAMETIME; level.active_fog = level.active_target_fog = self->fog_index; memcpy(&fade_fog, &level.current_fog, sizeof(fog_t)); } else level.active_fog = level.active_target_fog = 0; } else { if (self->delay) { if (!level.active_fog) { // Fog isn't currently on memcpy(&level.current_fog, &gfogs[index], sizeof(fog_t)); level.current_fog.Near = 4999.0f; level.current_fog.Far = 5000.0f; level.current_fog.Density = 0.0f; level.current_fog.Density1 = 0.0f; level.current_fog.Density2 = 0.0f; } VectorCopy(self->fog_color,gfogs[index].Color); gfogs[index].Near = self->fog_near; gfogs[index].Far = self->fog_far; gfogs[index].Density = self->fog_density; gfogs[index].Density1 = self->fog_density; gfogs[index].Density2 = self->density; self->goal_frame = level.framenum + self->delay*10 + 1; self->think = fog_fade; self->nextthink = level.time + FRAMETIME; memcpy(&fade_fog, &level.current_fog, sizeof(fog_t)); } else { memcpy(&level.current_fog, &gfogs[index], sizeof(fog_t)); } level.active_fog = level.active_target_fog = self->fog_index; } } void SP_target_fog (edict_t *self) { fog_t *fog; if ( !allow_fog->value ) { G_FreeEdict(self); return; } if (deathmatch->value || coop->value) { G_FreeEdict(self); return; } self->class_id = ENTITY_TARGET_FOG; if (!level.num_fogs) level.num_fogs = 1; // 1st fog reserved for console commands if (level.num_fogs >= MAX_FOGS) { gi.dprintf("Maximum number of fogs exceeded!\n"); G_FreeEdict(self); return; } if (self->delay < 0.0f) self->delay = 0.0f; self->fog_index = level.num_fogs+1; fog = &gfogs[level.num_fogs]; fog->Trigger = false; fog->Model = self->fog_model; if (fog->Model < 0 || fog->Model > 2) fog->Model = 0; fog->GL_Model = GLModels[fog->Model]; VectorCopy(self->fog_color,fog->Color); if (self->spawnflags & FOG_TURNOFF) { fog->Near = 4999; fog->Far = 5000; fog->Density = 0; fog->Density1 = 0; fog->Density2 = 0; } else { fog->Near = self->fog_near; fog->Far = self->fog_far; fog->Density = self->fog_density; fog->Density1 = self->fog_density; if (self->density == 0.0f) self->density = self->fog_density; else if (self->density < 0.0f) self->density = 0.0f; fog->Density2 = self->density; } AngleVectors(self->s.angles, fog->Dir, 0, 0); fog->ent = self; level.num_fogs++; self->use = target_fog_use; gi.linkentity(self); if (self->spawnflags & FOG_ON) { self->spawnflags &= ~FOG_ON; target_fog_use(self, NULL, NULL); } } /*QUAKED trigger_fog (1 0 0) ? x Toggle x StartOff Fog field "fog_color" specify an RGB color: Default = .5 .5 .5 "fog_model" default = 1 0 :Linear 1 :Exp 2 :Exp2 "fog_near" Starting distance from player. Default = 64 "fog_far" How far the player can see into the fog. Default = 1024 "fog_density" Default = 20 "density" at 180 degrees; Default=0 "delay" ramp time in seconds "count" number of times it can be used */ void trigger_fog_use (edict_t *self, edict_t *other, edict_t *activator) { if ((self->spawnflags & FOG_ON) && (self->spawnflags & FOG_TOGGLE)) { self->spawnflags &= ~FOG_ON; self->count--; if (self->count == 0) { self->think = G_FreeEdict; self->nextthink = level.time + FRAMETIME; } } else { self->spawnflags |= FOG_ON; } } void SP_trigger_fog (edict_t *self) { fog_t *fog; if (!allow_fog->value) { G_FreeEdict(self); return; } if (deathmatch->value || coop->value) { G_FreeEdict(self); return; } self->class_id = ENTITY_TRIGGER_FOG; if (!level.num_fogs) level.num_fogs = 1; // 1st fog reserved for console commands if (level.num_fogs >= MAX_FOGS) { gi.dprintf("Maximum number of fogs exceeded!\n"); G_FreeEdict(self); return; } self->fog_index = level.num_fogs+1; fog = &gfogs[level.num_fogs]; fog->Trigger = true; fog->Model = self->fog_model; if (( fog->Model < 0) || (fog->Model > 2) ) fog->Model = 0; fog->GL_Model = GLModels[fog->Model]; VectorCopy(self->fog_color,fog->Color); if (self->spawnflags & FOG_TURNOFF) { fog->Near = 4999.0f; fog->Far = 5000.0f; fog->Density = 0.0f; fog->Density1 = 0.0f; fog->Density2 = 0.0f; } else { fog->Near = self->fog_near; fog->Far = self->fog_far; fog->Density = self->fog_density; fog->Density1 = self->fog_density; if (self->density == 0.0f) self->density = self->fog_density; else if (self->density < 0.0f) self->density = 0.0f; fog->Density2 = self->density; } if (!(self->spawnflags & FOG_STARTOFF)) self->spawnflags |= FOG_ON; AngleVectors(self->s.angles, fog->Dir, 0, 0); VectorClear(self->s.angles); fog->ent = self; level.num_fogs++; level.num_trigger_fogs++; self->movetype = MOVETYPE_NONE; self->svflags |= SVF_NOCLIENT; self->solid = SOLID_NOT; gi.setmodel (self, self->model); gi.linkentity(self); } /*QUAKED trigger_fog_bbox (.5 .5 .5) (-8 -8 -8) (8 8 8) x Toggle x StartOff Fog field "fog_color" specify an RGB color: Default = .5 .5 .5 "fog_model" default = 1 0 :Linear 1 :Exp 2 :Exp2 "fog_near" Starting distance from player. Default = 64 "fog_far" How far the player can see into the fog. Default = 1024 "fog_density" Default = 20 "density" at 180 degrees; Default=0 "delay" ramp time in seconds "count" number of times it can be used bleft Min b-box coords XYZ. Default = -16 -16 -16 tright Max b-box coords XYZ. Default = 16 16 16 */ void SP_trigger_fog_bbox (edict_t *self) { fog_t *fog; if (!allow_fog->value) { G_FreeEdict(self); return; } if (deathmatch->value || coop->value) { G_FreeEdict(self); return; } self->class_id = ENTITY_TRIGGER_FOG; if (!level.num_fogs) level.num_fogs = 1; // 1st fog reserved for console commands if (level.num_fogs >= MAX_FOGS) { gi.dprintf("Maximum number of fogs exceeded!\n"); G_FreeEdict(self); return; } self->fog_index = level.num_fogs+1; fog = &gfogs[level.num_fogs]; fog->Trigger = true; fog->Model = self->fog_model; if (fog->Model < 0 || fog->Model > 2) fog->Model = 0; fog->GL_Model = GLModels[fog->Model]; VectorCopy(self->fog_color,fog->Color); if (self->spawnflags & FOG_TURNOFF) { fog->Near = 4999.0f; fog->Far = 5000.0f; fog->Density = 0.0f; fog->Density1 = 0.0f; fog->Density2 = 0.0f; } else { fog->Near = self->fog_near; fog->Far = self->fog_far; fog->Density = self->fog_density; fog->Density1 = self->fog_density; if (self->density == 0.0f) self->density = self->fog_density; else if (self->density < 0.0f) self->density = 0.0f; fog->Density2 = self->density; } if (!(self->spawnflags & FOG_STARTOFF)) self->spawnflags |= FOG_ON; AngleVectors(self->s.angles, fog->Dir, 0, 0); VectorClear(self->s.angles); fog->ent = self; level.num_fogs++; level.num_trigger_fogs++; self->movetype = MOVETYPE_NONE; self->svflags |= SVF_NOCLIENT; self->solid = SOLID_NOT; if ( (!VectorLength(self->bleft)) && (!VectorLength(self->tright)) ) { VectorSet(self->bleft, -16, -16, -16); VectorSet(self->tright, 16, 16, 16); } VectorCopy (self->bleft, self->mins); VectorCopy (self->tright, self->maxs); gi.linkentity(self); } #endif // DISABLE_FOG