Files
quakemapping/mod_xj19/my_progs/globalfog.qc
2020-01-01 23:35:17 +01:00

326 lines
12 KiB
Plaintext

/*======================================================================
GLOBAL FADING FOG SYSTEM
* Original idea from Honey mod by CZG
* Written from scratch as Honey implementation is weird
* Created special long float function for better accuracy
* Fog functionality has to be active before controller can be setup
* Creates a special entity (controller) to work in background
* Controller is setup from client.qc / PlayerPostThink function
======================================================================*/
//----------------------------------------------------------------------
// Returns power of 10 for string format function below
//----------------------------------------------------------------------
float(float pow_loop) pow10 =
{
local float pow_num, pow_counter;
pow_num = 10;
pow_counter = 1;
if (pow_loop < 1) pow_loop = 1;
while (pow_counter < pow_loop) {
pow_num = pow_num * 10;
pow_counter = pow_counter + 1;
}
return pow_num;
};
//----------------------------------------------------------------------
// (Long Float TO String) Format and print a number to the console
// - str_player : needs to be a client for various buffer commands
// - buffer : BUFFER_STUFFCMD, BUFFER_SPRINT, BUFFER_DPRINT
void(entity str_player, float str_num, float topbit, float botbit, float buffer) lftos =
{
local float str_counter, str_pow, str_result, str_remain, str_first;
str_counter = topbit; // Upper number length
str_pow = pow10(topbit); // Setup initial base 10 power for checking
str_remain = FALSE; // Decimal point been done yet
str_first = FALSE; // First non-zero digit printed
// Deal with negative state first
if (str_num < 0) {
if (buffer & BUFFER_STUFFCMD) stuffcmd(str_player, "-");
else if (buffer & BUFFER_SPRINT) sprint(str_player, "-");
else if (buffer & BUFFER_DPRINT) dprint("-");
}
// Get rid of negative state
str_num = fabs(str_num);
// If number larger than fixed length? - truncate number
if (str_num > str_pow)
str_num = str_num - (floor(str_num / str_pow) * str_pow);
// Loop through upper part of number
while(str_counter > 0) {
// Move down one pow digit
str_pow = str_pow / 10;
// Divide number by pow to get divider
// Floor can produce rounding errors (fix it with 0.01)
str_result = floor((str_num / str_pow)+0.01);
// Result must be 0-9 digits
if (str_result > 9) str_result = 0;
if (str_result < 1) str_result = 0;
if (str_result > 0 || str_first) {
str_first = TRUE;
// Print digit to buffer type
if (buffer & BUFFER_STUFFCMD) stuffcmd(str_player, ftos(str_result));
else if (buffer & BUFFER_SPRINT) sprint(str_player, ftos(str_result));
else if (buffer & BUFFER_DPRINT) dprint(ftos(str_result));
}
// remove top part of number, decrease str length counter
str_num = str_num - (str_result * str_pow);
str_counter = str_counter - 1;
}
// Is there any remainder?
if (str_counter < 1) {
// Print decimal point to buffer type
if (!str_first) {
str_first = TRUE;
if (buffer & BUFFER_STUFFCMD) stuffcmd(str_player, "0.");
else if (buffer & BUFFER_SPRINT) sprint(str_player, "0.");
else if (buffer & BUFFER_DPRINT) dprint("0.");
}
else {
if (buffer & BUFFER_STUFFCMD) stuffcmd(str_player, ".");
else if (buffer & BUFFER_SPRINT) sprint(str_player, ".");
else if (buffer & BUFFER_DPRINT) dprint(".");
}
if (botbit <1) botbit=1;
str_counter = botbit;
while (botbit > 0) {
str_num = str_num * 10;
botbit = botbit -1;
}
str_pow = pow10(str_counter);
}
// Loop through lower part of number
while(str_counter > 0) {
// Move down one pow digit
str_pow = str_pow / 10;
// Divide number by pow to get divider
// Floor can produce rounding errors (fix it with 0.01)
str_result = floor((str_num / str_pow)+0.01);
// Result must be 0-9 digits
if (str_result > 9) str_result = 0;
if (str_result < 1) str_result = 0;
if (str_result > 0 || str_first) {
str_first = TRUE;
// Print digit to buffer type
if (buffer & BUFFER_STUFFCMD) stuffcmd(str_player, ftos(str_result));
else if (buffer & BUFFER_SPRINT) sprint(str_player, ftos(str_result));
else if (buffer & BUFFER_DPRINT) dprint(ftos(str_result));
}
// remove top part of number, decrease str length counter
str_num = str_num - (str_result * str_pow);
str_counter = str_counter - 1;
}
};
//----------------------------------------------------------------------
void(entity client) change_fog =
{
if (!fog_control) return;
// Update fog parameters to console buffer
stuffcmd(client, "\n\n\nfog ");
if (ext_dpfog) lftos(client, fog_control.fog_currden+0.05, 1,3, BUFFER_STUFFCMD);
else lftos(client, fog_control.fog_currden, 1,3, BUFFER_STUFFCMD);
stuffcmd(client, " ");
lftos(client, fog_control.fog_currcol_x, 1,3, BUFFER_STUFFCMD);
stuffcmd(client, " ");
lftos(client, fog_control.fog_currcol_y, 1,3, BUFFER_STUFFCMD);
stuffcmd(client, " ");
lftos(client, fog_control.fog_currcol_z, 1,3, BUFFER_STUFFCMD);
// Extra fog parameters for DarkPlaces extended engines
if (ext_dpfog) {
stuffcmd(client, " ");
stuffcmd(client, fog_control.fog_dpextra);
}
stuffcmd(client, "\n");
};
//----------------------------------------------------------------------
// Make value is not below or above limits and or negative!
//----------------------------------------------------------------------
float(float fogrange) fog_check_range =
{
if (fogrange < 0.01) return 0.01;
if (fogrange > 1) return 1;
return fabs(fogrange);
};
//----------------------------------------------------------------------
void() fog_controller_think =
{
// Has there been a change detected?
if (self.state == STATE_SETUP) {
// If fog fade time too low, instantly switch
if (self.fog_difftime <= FADEFOG_TIME) {
self.state = STATE_OFF;
self.fog_currden = self.fog_targden;
self.fog_currcol = self.fog_targcol;
change_fog(self.owner);
}
else {
// Setup gradual fade of fog over time
self.state = STATE_ON;
// divide the fade time into segments (minimum 0.05)
// Multiple the time by segments so diff is correct
// Time segements less than 0.05 does not work v well
self.fog_steptime = self.fog_difftime / FADEFOG_TIME;
self.fog_difftime = self.fog_steptime * FADEFOG_TIME;
// Work out fade directions for density/colour
self.fog_diffden = self.fog_targden - self.fog_currden;
self.fog_diffcol = self.fog_targcol - self.fog_currcol;
// Debug info only
/*----------------------------------------------------------------------
dprint("Curr (");
lftos(self.owner, self.fog_currden, 1,3, BUFFER_DPRINT); dprint(")(");
lftos(self.owner, self.fog_currcol_x, 1,3, BUFFER_DPRINT); dprint(" ");
lftos(self.owner, self.fog_currcol_y, 1,3, BUFFER_DPRINT); dprint(" ");
lftos(self.owner, self.fog_currcol_z, 1,3, BUFFER_DPRINT); dprint(")\n");
dprint("Targ (");
lftos(self.owner, self.fog_targden, 1,3, BUFFER_DPRINT); dprint(")(");
lftos(self.owner, self.fog_targcol_x, 1,3, BUFFER_DPRINT); dprint(" ");
lftos(self.owner, self.fog_targcol_y, 1,3, BUFFER_DPRINT); dprint(" ");
lftos(self.owner, self.fog_targcol_z, 1,3, BUFFER_DPRINT); dprint(")\n");
dprint("Diff (");
lftos(self.owner, self.fog_diffden, 1,3, BUFFER_DPRINT); dprint(")(");
lftos(self.owner, self.fog_diffcol_x, 1,3, BUFFER_DPRINT); dprint(" ");
lftos(self.owner, self.fog_diffcol_y, 1,3, BUFFER_DPRINT); dprint(" ");
lftos(self.owner, self.fog_diffcol_z, 1,3, BUFFER_DPRINT); dprint(")\n");
//----------------------------------------------------------------------*/
// Work out step ammount to fade smoothly over time
self.fog_diffden = self.fog_diffden / self.fog_steptime;
self.fog_diffcol_x = self.fog_diffcol_x / self.fog_steptime;
self.fog_diffcol_y = self.fog_diffcol_y / self.fog_steptime;
self.fog_diffcol_z = self.fog_diffcol_z / self.fog_steptime;
}
}
// Is the fog fade over? Finite amount of steps
else if (self.fog_steptime < 0 && self.state != STATE_OFF) {
self.state = STATE_OFF;
self.fog_currden = self.fog_targden;
self.fog_currcol = self.fog_targcol;
// Check density and colour values are within range
self.fog_currden = fog_check_range(self.fog_currden);
self.fog_currcol_x = fog_check_range(self.fog_currcol_x);
self.fog_currcol_y = fog_check_range(self.fog_currcol_y);
self.fog_currcol_z = fog_check_range(self.fog_currcol_z);
change_fog(self.owner);
}
// If the fade is active, keep adding steps
else if (self.state == STATE_ON) {
self.fog_steptime = self.fog_steptime - 1;
self.fog_currden = self.fog_currden + self.fog_diffden;
self.fog_currcol = self.fog_currcol + self.fog_diffcol;
change_fog(self.owner);
}
// Keep on looping around using min time step
self.think = fog_controller_think;
self.nextthink = time + FADEFOG_TIME;
};
//----------------------------------------------------------------------
void(float gf_den, vector gf_col, float gf_time) fade_fog =
{
// No controller active?
if (!fog_control) return;
// Check density and colour values are within range
gf_den = fog_check_range(gf_den);
gf_col_x = fog_check_range(gf_col_x);
gf_col_y = fog_check_range(gf_col_y);
gf_col_z = fog_check_range(gf_col_z);
// Setup fog controller with new fog values
fog_control.fog_targden = gf_den;
fog_control.fog_targcol = gf_col;
fog_control.fog_difftime = gf_time;
// Force fog controller to calculate difference
fog_control.state = STATE_SETUP;
};
//----------------------------------------------------------------------
void() setup_fog_controller =
{
if (!fog_control) {
// Start off with the fog controller disabled
// if the worldspawn setup correctly then enable
// the controller and allow fog changes
fog_active = FALSE;
fog_control = spawn();
fog_control.owner = self; // Link back to client
fog_control.classtype = CT_CONTROL;
fog_control.solid = SOLID_NOT; // No world interaction
fog_control.movetype = MOVETYPE_NONE; // Static item, no movement
setorigin(fog_control, '0 0 0');
setsize(fog_control, VEC_ORIGIN, VEC_ORIGIN);
if (world.fog_density == 0) {
fog_active = FALSE; // out of sync
fog_control.fog_currden = DEF_FOGDEN; // Bad default
fog_control.fog_targden = DEF_FOGDEN; // Target
}
else {
fog_active = TRUE; // engine and QC insync
fog_control.fog_currden = world.fog_density;
fog_control.fog_targden = world.fog_density;
}
fog_control.fog_diffden = 0; // Difference
if (CheckZeroVector(world.fog_colour)) {
fog_active = FALSE; // out of sync
fog_control.fog_currcol = DEF_FOGCOL; // Bad Default
fog_control.fog_targcol = DEF_FOGCOL; // Target
}
else {
fog_active = TRUE; // engine and QC insync
fog_control.fog_currcol = world.fog_colour;
fog_control.fog_targcol = world.fog_colour;
}
fog_control.fog_diffcol = '0 0 0'; // Difference
// Bat shit crazy DP extra fog parameters that no other engine uses
// dpextra = alpha mindist maxdist top fadedepth (def=1 0 8192 1024 32)
if (world.fog_dpextra == "") fog_control.fog_dpextra = DEF_FOGEXT;
else fog_control.fog_dpextra = world.fog_dpextra;
// This is a horrible hack, it should not be here
// This parameter should be in the map file worldspawn
//if (world.model == "maps/ad_end.bsp")
// fog_control.fog_dpextra = "1 0 2048 8192 32";
fog_control.state = STATE_OFF; // Not fading atm
fog_control.fog_difftime = 0; // fading fog time (seconds)
fog_control.fog_steptime = 0; // How many steps to fade
// Setup think process to monitor for fog changes
// If this entity already exists, then its thinking!
fog_control.think = fog_controller_think;
fog_control.nextthink = time + FADEFOG_TIME;
if (fog_active) change_fog(self);
}
};