/*====================================================================== 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); } };