dwringer 45 Posted March 8, 2013 (edited) Hello all, I've had this script sitting around with some bugs in it for a while, so I used the A3 alpha release as an opportunity to go over it and try to bring things up to a higher standard. This script, when called, will set the date and time to random values chosen from within the ranges provided in the mission editor. The time of day, however, is not entirely random. I have implemented a function by rübe that calculates, for a given latitude and longitude read from the map config, the time-of-day corresponding to both sunrise and sunset (Within a reasonable margin of error). In a majority of cases when a randomly chosen time falls into what might be considered "night", the time will instead be set to either the calculated sunrise or sunset time. As a final result, there is a relatively small chance of missions occurring in the dead of night, with a higher-than-average chance of getting relatively dramatic lighting effects. This script really showcases the engine's dynamic lighting and palette effects. Anyway, without further ado: /* Arma 3 Random Time/Date Script Sets a random time and date. Globally sets isDay & isNight, which may or may not be useful. The two are not complementary. Not tested in MP. Updated: 8 March 2013 Author: dwringer Credit: rube, Sunrise/sunset calculator function <rube_fn_sun.sqf> Arguments: None */ if (!isServer) exitWith {}; private ["_y", "_m", "_d", "_h", "_n", "_mn", "_sel", "_ssArr", "_sr", "_ss", "_srh", "_ssh", "_ts", "_dl", "_nl", "_dhsr", "_dhss", "_dds"]; _y = 1982 + (floor random 69); _m = 1 + (floor random 12); _d = 2 + (floor random 30); _h = floor random 24; _n = floor random 60; _mn = ""; isDay = false; isNight = false; switch (_m) do { case 1: { _mn = "January";}; case 2: { _mn = "February"; if ((_y % 400) == 0) then { _d = 1;} else { if ((_y % 100) == 0) then { _d = 0;} else { if ((_y % 4) == 0) then { _d = 1;} else {_d = 0;};};}; _d = _d + (floor random 29);}; case 3: { _mn = "March";}; case 4: { _mn = "April"; _d = _d - (floor random 2);}; case 5: { _mn = "May";}; case 6: { _mn = "June"; _d = _d - (floor random 2);}; case 7: { _mn = "July";}; case 8: { _mn = "August";}; case 9: { _mn = "September"; _d = _d - (floor random 2);}; case 10: { _mn = "October";}; case 11: { _mn = "November"; _d = _d - (floor random 2);}; case 12: { _mn = "December";}; default {};}; _ssArr = [_y, _m, _d] call compile preprocessFile "rube_fn_sun.sqf"; _sr = _ssArr select 0; // sunrise [h,m] _ss = _ssArr select 1; // sunset [h,m] _srh = _sr select 0; // sunrise hour _ssh = _ss select 0; // sunset hour _dl = abs(_ssh - _srh);// day length _nl = 24 - _dl; // night length _dhsr = abs(_h - _srh);// diff. in hrs. from sunrise _dhss = abs(_h - _ssh);// diff. in hrs. from sunset _dds = abs(_dhsr - _dhss);// difference in above two differences if ((_h > _srh) && (_h < _ssh)) then { if ((_dl > 5) && (_dds <= ((2.0 * _dl)/ 3.0))) then { isDay = true; // midday } else {};} else { if ((_nl > 3) && ((_h > (_ssh + 1)) || (_h < (_srh - 1)))) then { isNight = true; // Over an hour from sunrise/sunset };}; if (isNight) then { if ((floor random 11) > 1) then { isNight = false; _sel = floor random 2; _h = [_srh, _ssh] select _sel; _n = [_sr select 1, _ss select 1] select _sel;};}; setDate [_y, _m, _d, _h, _n]; _ts = "S"; if(isDay) then {_ts = "Midday, s";}; if(isNight) then {_ts = "Night, s";}; hint format ["%1omewhere in the Mediterranean\n%2 %3, %4", _ts, _d, _mn, _y]; publicVariable "isDay"; publicVariable "isNight"; This code is also dependent on the following, which must be saved as "rube_fn_sun.sqf": /* Author: rübe Description: calculates sunrise/sunset on a given date, based on the algorithm from: Almanac for Computers, 1990 published by Nautical Almanac Office United States Naval Observatory Washington, DC 20392 (see williams.best.vwh.net/sunrise_sunset_algorithm.htm) Latitude and longitude are read from the world config. Local time is approximated by: floor (_longitude / 15) Parameter(s): _this: date (array [year, month, day, ...] or as returned by `date`) Returns: [sunrise, sunset] (array) ... where `sunrise` and `sunset` are arrays [hour (integer), minute (integer)] */ private ["_year", "_month", "_day", "_zenith", "_latitude", "_longitude"]; _year = _this select 0; _month = _this select 1; _day = _this select 2; /* zenith: - offical = 90 degrees - civil = 96 degrees - nautical = 102 degrees - astronomical = 108 degrees */ _zenith = 90; _latitude = getNumber(configFile >> "CfgWorlds" >> worldName >> "latitude") * -1; _longitude = getNumber(configFile >> "CfgWorlds" >> worldName >> "longitude"); /* CALCULATION */ private ["_n1", "_n2", "_n3", "_n", "_lngHour", "_times"]; // day of the year _n1 = floor (275 * _month / 9); _n2 = floor ((_month + 9) / 12); _n3 = 1 + floor ((_year - (4 * (floor (_year / 4))) + 2) / 3); _n = _n1 - (_n2 * _n3) + _day - 30; // convert longitude to hour value and calculate an approximate time _lngHour = _longitude / 15; _times = []; { private [ "_t", "_m", "_l", "_ra", "_lQuadrant", "_raQuadrant", "_sinDec", "_cosDec", "_cosH", "_h", "_ut", "_local", "_localH" ]; if (_x) then { _t = (_n + ((6 - _lngHour) / 24)); // rising time } else { _t = (_n + ((18 - _lngHour) / 24)); // setting time }; // sun's mean anomaly _m = (0.9856 * _t) - 3.289; // sun's true longitude _l = _m + (1.916 * (sin _m)) + (0.020 * (sin (2 * _m))) + 282.634; while {(_l < 0)} do { _l = _l + 360; }; _l = _l % 360; // sun's right ascension _ra = atan (0.91764 * (tan _l)); while {(_ra < 0)} do { _ra = _ra + 360; }; _ra = _ra % 360; // right ascension value needs to be in the same quadrant as L _lQuadrant = (floor (_l / 90)) * 90; _raQuadrant = (floor (_ra / 90)) * 90; _ra = _ra + (_lQuadrant - _raQuadrant); // right ascension value needs to be converted into hours _ra = _ra / 15; // sun's declination _sinDec = 0.39782 * (sin _l); _cosDec = cos (asin _sinDec); // sun's local hour angle _cosH = ((cos _zenith) - (_sinDec * (sin _latitude))) / (_cosDec * (cos _latitude)); /* if (_cosH > 1) then { // the sun never rises on this location (on the specified date) }; if (_cosH < -1) then { // the sun never sets on this location (on the specified date) }; */ // finish calculating H and convert into hours if (_x) then { _h = 360 - (acos _cosH); // rising time } else { _h = acos _cosH; // setting time }; _h = _h / 15; // local mean time of rising/setting _t = _h + _ra - (0.06571 * _t) - 6.622; // adjust back to UTC _ut = _t - _lngHour; while {(_ut < 0)} do { _ut = _ut + 24; }; _ut = _ut % 24; // plus ~local time _local = _ut + (floor (_longitude / 15)); _localH = floor _local; // scalar to hours and minutes _times set [ (count _times), [ _localH, (floor ((_local - _localH) * 60)) ] ]; } forEach [ true, // rising time false // setting time ]; // return _times Please let me know if anyone finds any issues with the above. There are probably glaring flaws to which I remain oblivious, but I imagine everyone could benefit if they were fixed ;) EDIT: Instructions: Put the script into an sqf file, such as "randomTime.sqf", and then A) create another file called "init.sqf" containing the line: execVM "randomTime.sqf"; or B) using a trigger from the mission editor, in the "On Act: " field put something like: _rt = execVM "randomTime.sqf"; Hope that clears anything up :) Edited March 8, 2013 by dwringer Share this post Link to post Share on other sites
mckibbon17 1 Posted March 16, 2013 Hey no issue with this works great! but is there any way of setting this up so its 1hour day and 1 hour night? If so please help! :) thanks! Share this post Link to post Share on other sites