djcev.com

//

Git Repos / fte_dogmode / qc / triggers / fog.qc

Last update to this file was on 2024-03-24 at 02:40.

Show fog.qc

//==============================================================================
// Fog controllers -- Based on Copper's fog by Lunaran, Changed by bmFbr
//==============================================================================

/*FGD
@baseclass = Fog [
fog_density(string) : "Fog Density"
fog_color(string) : "Fog Color"
]
@baseclass = FogShift [
fog_density(string) : "Start Fog Density"
fog_color(string) : "Start Fog Color"
fog_density2(string) : "End Fog Density"
fog_color2(string) : "End Fog Color"
]
*/

//======================================================================
// constants
//======================================================================

const float FOG_INTERVAL = 0.04166667; // 1/24;

const float FOGBLEND_ONEWAY = 1;
const float FOGBLEND_REVERSE = 2;
const float FOGBLEND_ALLCLIENTS = 4;
const float FOGBLEND_BLENDTO = 8;

//======================================================================
// fields
//======================================================================

.vector fog_color, fog_color2; // progs_dump fog
.float fog_density, fog_density2;
.float skyfog_density, skyfog_density2;
.entity fogblend_entity;

//======================================================================
// forward declarations
//======================================================================

void(entity client, float density, vector color) fog_save;
void(entity client) fog_save_to_previous;
void(entity client, float density) skyfog_save;
void(entity client) skyfog_save_to_previous;
void(entity client, entity fogger) fog_set_from_ent;
void(entity client, float density, vector color) fog_set;
void(entity client, float density) skyfog_set;
void(entity client, vector cTo, float dTo, float f) fog_blend_set_fraction;
void(entity client, float sTo, float f) skyfog_blend_set_fraction;

// base_fog_controller
void() base_fog_controller_think;

// temp_fog_controller
entity(entity own, entity nme) spawn_temp_fog_controller;
void(entity e) temp_fog_controller_init;
strip void() temp_fog_controller;

// target_fogblend
void() target_fogblend_use;
entity(vector org, float sflags, vector fogcolor, float fd, float sfd,
float newspeed1, float newspeed2) spawn_target_fogblend;
void(entity e) target_fogblend_init;
void() target_fogblend;

// trigger_fogblend
void() trigger_fogblend_touch;
entity(vector org, vector nmins, vector nmaxs, vector ang, vector md,
float dist) spawn_trigger_fogblend;
void(entity e) trigger_fogblend_init;
void() trigger_fogblend;

// trigger_fog
void() trigger_fog_touch;
entity(vector org, vector nmins, vector nmaxs, float newspeed, vector newcolor,
float fdensity, float sfdensity, float newdelay) spawn_trigger_fog;
void(entity e) trigger_fog_init;
void() trigger_fog;

//------------------------------------------------------------------------------

//----------------------------------------------------------------------
// fog_save
//----------------------------------------------------------------------
void(entity client, float density, vector color) fog_save =
{
if (client.classtype != CT_PLAYER)
return;

// save whatever we set the client's fog to in case of saves/loads
client.fog_density = density;
client.fog_color = color;
};

//----------------------------------------------------------------------
void(entity client) fog_save_to_previous =
{
if (client.classtype != CT_PLAYER)
return;

// copies the current fog to the secondary fields to transition
// from the current fog
client.fog_density2 = client.fog_density;
client.fog_color2 = client.fog_color;
};

//----------------------------------------------------------------------
void(entity client, float density) skyfog_save =
{
if (client.classtype != CT_PLAYER)
return;

client.skyfog_density = density;
};

//----------------------------------------------------------------------
void(entity client) skyfog_save_to_previous =
{
if (client.classtype != CT_PLAYER)
return;

client.skyfog_density2 = client.skyfog_density;
};

//----------------------------------------------------------------------
// fog_setFromEnt
//----------------------------------------------------------------------
void(entity client, entity fogger) fog_set_from_ent =
{
local float density;

// Don't set the fog if the entity has no values, because it
// might be a custom map with _fog on the worldspawn instead.
// To actually get an entity to clear the fog, density to -1.
// The same applies to skyfog

// eprint (fogger);

// dprint3 ("fog_density: ", ftos(fogger.fog_density*100), "\n");
if (fogger.fog_density)
{
dprint ("setting fog\n");
density = zeroconvert (fogger.fog_density);
fog_set (client, density, fogger.fog_color);
}

// dprint3 ("skyfog_density: ", ftos(fogger.skyfog_density*100), "\n");
if (fogger.skyfog_density)
{
dprint ("setting skyfog\n");
density = zeroconvert (fogger.skyfog_density);
skyfog_set (client, density);
}
};

//----------------------------------------------------------------------
// fog_set
//----------------------------------------------------------------------
void(entity client, float density, vector color) fog_set =
{
if (client.classtype != CT_PLAYER)
return;

// dprint9 ("Setting fog: ", ftos(density), " ", ftos(color_x),
// " ", ftos(color_y), " ", ftos(color_z), "\n");

stuffcmd (client, "\nfog ");
stuffcmd_float (client, density);
stuffcmd (client, " ");
stuffcmd_float (client, color_x);
stuffcmd (client, " ");
stuffcmd_float (client, color_y);
stuffcmd (client, " ");
stuffcmd_float (client, color_z);
stuffcmd (client, "\n");

fog_save (client, density, color);
};

//----------------------------------------------------------------------
void(entity client, float density) skyfog_set =
{
if (client.classtype != CT_PLAYER)
return;

// dprint3 ("Setting skyfog: ", ftos(density), "\n");

stuffcmd (client, "\nr_skyfog ");
stuffcmd_float (client, density);
stuffcmd (client, "\n");

skyfog_save (client, density);
};

//----------------------------------------------------------------------
void(entity client, vector cTo, float dTo, float f) fog_blend_set_fraction =
{
local float d;
local vector c;

d = lerp_hermite (client.fog_density2, dTo, f);
c = lerp_vector_hermite (client.fog_color2, cTo, f);

/*
eprint (cl);
dprint3 ("fog density: ", ftos(d), "\n");
dprint3 ("color: ", vtos(c), "\n");
dprint3 ("fraction: ", ftos(f), "\n");
*/

fog_set (client, d, c);
};

//----------------------------------------------------------------------
void(entity client, float sTo, float f) skyfog_blend_set_fraction =
{
local float s;

s = lerp_hermite (client.skyfog_density2, sTo, f);

// eprint (cl);
// dprint3 ("Fraction skyfog density: ", ftos(s), "\n");

skyfog_set (client, s);
};

//----------------------------------------------------------------------
// class base_fog_controller: base_mapentity
// {
//--------------------------------------------------------------
// fog controller think -- used by both trigger_fog and
// target_fogblend; was fog_blendTimeThink
//--------------------------------------------------------------
void() base_fog_controller_think =
{
local float f;
local float dTo, sTo;
local vector cTo;

if (time >= self.pain_finished)
{
f = 1;
}
else
{
self.nextthink = time + FOG_INTERVAL;
if (self.state && self.speed)
f = 1 - (self.pain_finished - time) /
self.speed;
else if (self.speed2)
f = 1 - (self.pain_finished - time) /
self.speed2;
else
f = 1;
}

if (self.state)
{
dTo = self.fog_density2;
cTo = self.fog_color2;
sTo = self.skyfog_density2;
}
else
{
dTo = self.fog_density;
cTo = self.fog_color;
sTo = self.skyfog_density;
}

if (self.spawnflags & FOGBLEND_ALLCLIENTS)
{
entity pl;
pl = nextent (world);
while (pl.flags & FL_CLIENT)
{
if (pl.fogblend_entity == self)
{
if (dTo && !(pl.fog_density2 == dTo &&
pl.fog_color2 == cTo))
{
fog_blend_set_fraction (pl, cTo,
zeroconvert(dTo), f);
}

if (sTo)
{
skyfog_blend_set_fraction (pl,
zeroconvert(sTo), f);
}

if (time >= self.pain_finished)
{
pl.fogblend_entity = world;
}
}

pl = nextent (pl);
}
}
else
{
if (self.enemy.fogblend_entity == self)
{
if (dTo && !(self.enemy.fog_density2 == dTo &&
self.enemy.fog_color2 == cTo))
{
fog_blend_set_fraction (self.enemy,
cTo, zeroconvert(dTo), f);
}

if (sTo)
{
skyfog_blend_set_fraction (self.enemy,
zeroconvert(sTo), f);
}

if (time >= self.pain_finished)
{
self.enemy.fogblend_entity = world;
}
}
}

if (self.classtype == CT_TEMP_FOG_CONTROLLER)
{
if (self.enemy.fogblend_entity != self ||
time >= self.pain_finished)
{
remove (self);
return;
}
}
};
// };

//----------------------------------------------------------------------
// class temp_fog_controller: base_fog_controller
// {
//--------------------------------------------------------------
entity(entity own, entity nme) spawn_temp_fog_controller =
{
local entity e = spawn ();
e.owner = own;
e.enemy = nme;
// speed2 is used when state is 0
e.speed2 = own.speed;
e.fog_color = own.fog_color;
e.fog_density = own.fog_density;
e.skyfog_density = own.skyfog_density;
e.pain_finished = time + own.delay + own.speed;
temp_fog_controller_init (e);
return e;
};

//--------------------------------------------------------------
void(entity e) temp_fog_controller_init =
{
base_tempentity_init (e);
e.classname = "temp_fog_controller";
e.classtype = CT_TEMP_FOG_CONTROLLER;
e.think = base_fog_controller_think;
};

//--------------------------------------------------------------
strip void() temp_fog_controller =
{
temp_fog_controller_init (self);
};
// };

/*QUAKED target_fogblend (.5 .5 .2) (-8 -8 -8) (8 8 8) ONE_WAY REVERSE GLOBAL BLENDTO
Blends the fog for a client. activator's fog will be blended from "fog_color" and "fog_density"
to "fog_color2" and "fog_density2". Triggering again will blend it back, unless ONE_WAY is set.
Set REVERSE if you're tired of swapping the values by hand.
Set GLOBAL to affect all clients in multiplayer, not just the activator.

"delay" - pause before beginning to blend
"speed" - time to spend blending, -1 for an instant change to fog2.
"speed2" - time to spend blending back, if different than "speed". -1 for instant.

CAVEATS:
- will 'stuffcmd' 2 dozen times per frame so try not to make this take too long
- a bug in most quake engine ports will reset the eye position smoothing that happens when climbing stairs or riding a plat on every frame that a 'stuffcmd' is sent, so fog transitions during upwards motion will cause noticeable stuttering.
*/
/*FGD
@PointClass base(Appearflags, Targetname, Target, FogShift) color(128 128 50) = target_fogblend :
"Target: Fog Blend
Activator's fog will be blended over time from start to end values.

- will 'stuffcmd' 2 dozen times per frame so try not to make this take too long
- a bug in most quake engine ports will reset the eye position smoothing that happens when climbing stairs or riding a plat on every frame that a 'stuffcmd' is sent, so fog transitions during upwards motion will cause noticeable stuttering."
[
spawnflags(flags) = [
1 : "One-Way Only" : 0
2 : "Reverse Start/End" : 0
4 : "All clients" : 0
]
delay(string) : "Pause before starting blend"
speed(string) : "Time to blend (-1 for instant)"
speed2(string) : "Time to blend back, if different (-1 for instant)"
]
*/
// class target_fogblend: base_fog_controller
// {
//--------------------------------------------------------------
void() target_fogblend_use =
{
self.enemy = activator;
if (self.enemy.classtype != CT_PLAYER)
return;

if (!(self.spawnflags & FOGBLEND_ONEWAY))
self.state = 1 - self.state;

if (self.state)
self.pain_finished = time + self.delay + self.speed;
else
self.pain_finished = time + self.delay + self.speed2;

if (self.spawnflags & FOGBLEND_ALLCLIENTS)
{
entity pl;
pl = nextent (world);
while (pl.flags & FL_CLIENT)
{
if (self.fog_density)
fog_save_to_previous (pl);
if (self.skyfog_density)
skyfog_save_to_previous (pl);

pl.fogblend_entity = self;

pl = nextent(pl);
}
}
else
{
if (self.fog_density)
fog_save_to_previous (self.enemy);
if (self.skyfog_density)
skyfog_save_to_previous (self.enemy);

self.enemy.fogblend_entity = self;
}

self.nextthink = time + self.delay;
};

//--------------------------------------------------------------
entity(vector org, float sflags, vector fogcolor,
float fd, float sfd, float newspeed1, float newspeed2)
spawn_target_fogblend =
{
local entity e = spawn ();
e.origin = org;
e.spawnflags = sflags;
e.fog_color = fogcolor;
e.fog_density = fd;
e.skyfog_density = sfd;
e.speed = newspeed1;
e.speed2 = newspeed2;
target_fogblend_init (e);
return e;
};

//--------------------------------------------------------------
void(entity e) target_fogblend_init =
{
base_mapentity_init (e);
e.classname = "target_fogblend";
e.classtype = CT_TARGET_FOGBLEND;
e.think = base_fog_controller_think;
e.use = target_fogblend_use;

if (!e.fog_density && !e.skyfog_density)
{
objerror ("Neither fog density nor skyfog density set");
return;
}

if (e.spawnflags & FOGBLEND_REVERSE)
e.state = 1;
else
e.state = 0;

if (e.spawnflags & FOGBLEND_ONEWAY)
e.state = 1 - e.state;

if (!e.speed)
e.speed = 1;
if (!e.speed2)
e.speed2 = e.speed;

if (e.speed == -1)
e.speed = 0;
if (e.speed2 == -1)
e.speed2 = 0;
};

//--------------------------------------------------------------
void() target_fogblend =
{
// new spawnflags for all entities -- iw
if (SUB_Inhibit())
return;

target_fogblend_init (self);
};
// };

/*QUAKED trigger_fogblend (.5 .5 .2) ?
Acts as a smoothly blending portal between two zones of different fog. Sets the fog for any client passing through it, blending their global fog settings between "fog_color"/"fog_density" and "fog_color2"/"fog_density2" proportional to their position within the trigger.
The axis of motion on which the blend happens is defined by "angle", pointing to whatever zone has color2 and density2. Trigger therefore has two 'sides' - the side that "angle" points to, and the opposite side.

"distance" - override the length of the blend period in world units - defaults to bounds size
on 'angle' otherwise. this is only useful for diagonal triggers.

CAVEATS:
- will 'stuffcmd' 2 dozen times per frame so try not to make these huge
- a bug in most quake engine ports will reset the eye position smoothing that happens when climbing stairs or riding a plat on every frame that a 'stuffcmd' is sent, so fog transitions during upwards motion will cause noticeable stuttering.
*/
/*FGD
@SolidClass base(Appearflags, Targetname, Target, FogShift) = trigger_fogblend :
"Trigger: Fog Blend
Acts as a smoothly blending portal between two zones of different fog. Sets the fog for any client passing through it, blending their global fog settings between start and end values proportional to their position within the trigger.

- will 'stuffcmd' 2 dozen times per frame so try not to make these huge
- a bug in most quake engine ports will reset the eye position smoothing that happens when climbing stairs or riding a plat on every frame that a 'stuffcmd' is sent, so fog transitions during upwards motion will cause noticeable stuttering."
[
distance(integer) : "Length of blend distance (defaults to size of trigger)"
angle(integer) : "Axis of motion of blend (points toward end values)"
]
*/
// class trigger_fogblend: base_trigger
// {
//--------------------------------------------------------------
// fog_blendTouch
//--------------------------------------------------------------
void() trigger_fogblend_touch =
{
if (other.classtype != CT_PLAYER)
return;

if (other.health <= 0)
return;

if (self.estate != STATE_ACTIVE)
return;

// fix for only first client getting a fog change when
// multiple coop clients are touching this at once
if (time != self.rad_time)
// because fog is rad
if (time < self.attack_finished)
return;

local float f, lerp_density, leaving;
local float lerp_sdensity;
local float ent_density, ent_density2;
local float ent_sdensity, ent_sdensity2;
local vector dorg, mid, ovel;
local vector lerp_color;

ent_density = zeroconvert (self.fog_density);
ent_density2 = zeroconvert (self.fog_density2);

ent_sdensity = zeroconvert (self.skyfog_density);
ent_sdensity2 = zeroconvert (self.skyfog_density2);

// if you run/fall through a fogblend fast enough you can come
// out the other side partially blended, so check if player will
// exit the trigger bounds before the next touch (same class of
// bug as leaping through lasers in Q2)
ovel = other.velocity * FOG_INTERVAL;
leaving = ((other.absmax_x + ovel_x < self.absmin_x) ||
(other.absmax_y + ovel_y < self.absmin_y) ||
(other.absmax_z + ovel_z < self.absmin_z) ||
(other.absmin_x + ovel_x > self.absmax_x) ||
(other.absmin_y + ovel_y > self.absmax_y) ||
(other.absmin_z + ovel_z > self.absmax_z));

if (leaving)
{
// last chance to set fog correctly, so snap it to the
// final values
leaving = other.velocity * self.movedir;
if (leaving > 0)
{
lerp_density = ent_density2;
lerp_color = self.fog_color2;
lerp_sdensity = ent_sdensity2;
}
else
{
lerp_density = ent_density;
lerp_color = self.fog_color;
lerp_sdensity = ent_sdensity;
}
}
else
{
// in transition, blend proportionally between
// the two fogs
mid = (self.mins + self.maxs) * 0.5;
dorg = other.origin + other.view_ofs - mid;

f = dorg * self.movedir;
f = (f / self.distance) + 0.5;

lerp_density = lerp (ent_density, ent_density2, f);
lerp_color = lerp_vector (self.fog_color,
self.fog_color2, f);
lerp_sdensity = lerp (ent_sdensity, ent_sdensity2, f);
}

if (self.fog_density || self.fog_density2)
fog_set (other, lerp_density, lerp_color);
if (self.skyfog_density || self.skyfog_density2)
skyfog_set (other, lerp_sdensity);

self.rad_time = time;
self.attack_finished = time + FOG_INTERVAL;

// reset client's fogblend_entity in case it's currently being
// transitioned by another entity
other.fogblend_entity = world;
};

//--------------------------------------------------------------
entity(vector org, vector nmins, vector nmaxs, vector ang, vector md,
float dist) spawn_trigger_fogblend =
{
local entity e = spawn ();
e.origin = org;
e.mins = nmins;
e.maxs = nmaxs;
e.angles = ang;
e.movedir = md;
e.distance = dist;
setorigin (e, org);
setsize (e, nmins, nmaxs);
trigger_fogblend_init (e);
return e;
};

//--------------------------------------------------------------
void(entity e) trigger_fogblend_init =
{
e.classname = "trigger_fogblend";
e.classtype = CT_TRIGGER_FOGBLEND;
e.touch = trigger_fogblend_touch;

// base_trigger_init assumes angle 0 means no angle
if (e.angles == '0 0 0')
e.angles = '0 360 0';

base_trigger_init (e);
e.distance = zeroconvertdefault (e.distance,
bounds_angle_size(e.movedir, e.size));

sub_checkwaiting (e);
};

//--------------------------------------------------------------
void() trigger_fogblend =
{
// new spawnflags for all entities -- iw
if (SUB_Inhibit())
return;

trigger_fogblend_init (self);
};
// };

/*QUAKED trigger_fog (.5 .5 .2) ?
Smoothly blends touching client's currently applied fog to "fog_color" and "fog_density" over time.

"delay" - pause before beginning to blend.
"speed" - time to spend blending, -1 for an instant change.

CAVEATS:
- will 'stuffcmd' 2 dozen times per second so try not to make these huge
- a bug in most quake engine ports will reset the eye position smoothing that happens when climbing stairs or riding a plat on every frame that a 'stuffcmd' is sent, so fog transitions during upwards motion will cause noticeable stuttering.
*/
// class trigger_fog: base_trigger
// {
//--------------------------------------------------------------
void() trigger_fog_touch =
{
if (self.estate != STATE_ACTIVE)
return;

if (!(other.flags & FL_CLIENT))
return;

// fog already set to self value
if (other.fog_color == self.fog_color &&
other.fog_density == self.fog_density)
return;

// transition already occurring from self trigger
if (other.fogblend_entity.owner == self)
return;

if (self.fog_density)
fog_save_to_previous (other);
if (self.skyfog_density)
skyfog_save_to_previous (other);

// spawn a temp entity to control the transition for self client
local entity tempfog = spawn_temp_fog_controller (self, other);
tempfog.nextthink = time + tempfog.delay;
other.fogblend_entity = tempfog;
};

//--------------------------------------------------------------
entity(vector org, vector nmins, vector nmaxs,
float newspeed, vector newcolor, float fdensity,
float sfdensity, float newdelay) spawn_trigger_fog =
{
local entity e = spawn ();
e.origin = org;
e.mins = nmins;
e.maxs = nmaxs;
e.speed = newspeed;
e.fog_color = newcolor;
e.fog_density = fdensity;
e.skyfog_density = sfdensity;
e.delay = newdelay;
setorigin (e, org);
setsize (e, nmins, nmaxs);
trigger_fog_init (e);
return e;
};

//--------------------------------------------------------------
void(entity e) trigger_fog_init =
{
e.classname = "trigger_fog";
e.classtype = CT_TRIGGER_FOG;
e.touch = trigger_fog_touch;

if (!e.fog_density && !e.skyfog_density)
{
objerror ("Neither fog density nor skyfog density set");
return;
}

base_trigger_init (e);

if (!e.speed)
e.speed = 1;

sub_checkwaiting (e);
};

//--------------------------------------------------------------
void() trigger_fog =
{
// new spawnflags for all entities -- iw
if (SUB_Inhibit())
return;

trigger_fog_init (self);
};
// };

Return to the top of this page or return to the overview of this repo.

Log fog.qc

Date Commit Message Author + -
2024-03-24 2nd pass refactor, rework QC class structure cev +340 -206
2024-01-31 Class based monster refactor & start projectiles cev +1 -1
2024-01-09 Continue OO / Class-based refactor cev +68 -60
2023-12-09 Start OO / class-based refactor, work on items cev +387 -360
2023-12-02 More refactoring & moving, begin adding mdls & snd cev +598  

Return to the top of this page or return to the overview of this repo.