04-01-2004 05:49
Here is a function that returns the time of the day in-game in a similar way to llGetWallclock(). After some discussion with Andrew about how the sun works, this is what I came up with. It works off of llGetTimeOfDay instead of llGetSunDirection.
CODE

float GetGameWallclock() {
// Get the number of seconds since game midnight;
float Seconds = llGetTimeOfDay();

// Convert this to an angle of the sun relative to the
// theoretical center of its orbit. (Assuming a 4 hour day).
float Theta = Seconds / 14400 * TWO_PI;

// Find the point on the sun's orbit it is currently at (theoretically).
vector Sun = <llCos(Theta), llSin(Theta), 0>;

// Shift this point to account for the earth being offset from
// the center of the sun's orbit.
Sun.x -= 0.70710678; // sqrt( 1/2 );

// Convert this point back to an angle (which is the angle of the
// sun relative to the earth.
float Phi = llAtan2(Sun.y, Sun.x);

// Make sure this value is positive.
if (Phi < 0)
Phi += TWO_PI;

// Now convert back to a 24-hour day.
float GameSeconds = Phi / TWO_PI * 86400;

return GameSeconds;
}


Here is a version of the single prim clock, using this technique, to display game time:

CODE

////////////////////////////////////////////
// Single Prim Clock v2.1 Script (Game Time)
//
// Written by Xylor Baysklef
////////////////////////////////////////////

/////////////// CONSTANTS ///////////////////
// These are the faces to show the clock on.
integer HOUR_FACE = 4;
integer MINUTE_FACE = 0;
integer AM_PM_FACE = 2;

// Texture type enumeration.
integer WHITE_ON_BLACK = 0;
integer BLACK_ON_WHITE = 1;
integer TRANSPARENT = 2;

// This is the type of texture to display.
integer DISPLAY_TYPE = WHITE_ON_BLACK;

list HOUR_TEXTURES = [
// White on Black
"7bc19746-de1b-b84c-9d2a-515d38c030ab",
// Black on White
"d9b1de36-44d6-c89b-7b7f-97cbc62d47a3",
// Transparent
"db0b0013-f0b5-70b3-5e40-8685d024a3a2" ];

list MINUTE_TEXTURES = [
// White on Black
"9bc9c4bb-8c20-b103-fd5d-60f1072a39b1", // 00-29
"e82c651f-47e9-7950-ea65-f496e1917dd4", // 30-59
// Black on White
"7d53ead7-e6a7-59c5-b98b-fe46d9f61818", // 00-29
"6ae5d6a8-a78f-b505-e950-fcb003a480bf", // 30-59
// Transparent
"34e55b37-1c59-4a09-38d1-4150ffa396a5", // 00-29
"2b660a82-8d91-c892-a076-45c4a86f0235"];// 30-59

list AM_PM_TEXTURES = [
// White on Black
"13c95970-27a7-1a7a-cbc4-0e93f00361ba",
// Black on White
"b4d9d87e-36f8-7f4f-7d11-b7a2e973053b",
// Transparent
"f4ca9c46-3a46-6986-eb42-f497e9898d7a" ];
///////////// END CONSTANTS ////////////////

///////////// GLOBAL VARIABLES ///////////////
/////////// END GLOBAL VARIABLES ////////////

UpdateTime() {
// Get the number of seconds since game midnight;
float Seconds = llGetTimeOfDay();

// Convert this to an angle of the sun relative to the
// theoretical center of its orbit. (Assuming a 4 hour day).
float Theta = Seconds / 14400 * TWO_PI;

// Find the point on the sun's orbit it is currently at (theoretically).
vector Sun = <llCos(Theta), llSin(Theta), 0>;

// Shift this point to account for the earth being offset from
// the center of the sun's orbit.
Sun.x -= 0.70710678; // sqrt( 1/2 );

// Keep this for later, nice shortcut for estimation.
float Magnitude = llVecMag(Sun);

// Convert this point back to an angle (which is the angle of the
// sun relative to the earth.
float Phi = llAtan2(Sun.y, Sun.x);

// Make sure this value is positive.
if (Phi < 0)
Phi += TWO_PI;

// Now convert back to a 24-hour day.
float GameSeconds = Phi / TWO_PI * 86400;

// Figure out when the next game minute should occur (in game time seconds).
integer Minutes = llRound(GameSeconds / 60);
integer Hours = Minutes / 60;

float NextMinute = (Minutes + 1) * 60;

// Work backwards now, converting this game time into 'real' time
// so we can set up a timer.
Phi = NextMinute / 86400 * TWO_PI;
// Figure out where the sun will be.
// Use the magnitude of the previous sun position, as a guide
// (Good approximation).
Sun = Magnitude * <llCos(Phi), llSin(Phi), 0>;
// Shift to move our center back.
Sun.x += 0.70710678;
// Calculate the angle the sun will make with the center of its orbit.
Theta = llAtan2(Sun.y, Sun.x);

// Make sure we are between 0 and TWO_PI
if (Theta < 0)
Theta += TWO_PI;


// Finally, convert to real seconds.
float NextMinuteReal = Theta / TWO_PI * 14400;

// Figure out how many real seconds until the next game minute.
float SecondsToNextMinute = NextMinuteReal - Seconds;

// Sanity check.
if (SecondsToNextMinute < 5) {
SecondsToNextMinute = 5;
}

llSetTimerEvent(SecondsToNextMinute);

// Now only keep the minutes of the current hour.
// (Normalize to 0-59).
Minutes %= 60;

Hours %= 24;

// Calculate if this is AM or PM.
integer AM_PM = Hours / 12;

// Normalize the hour to 0-11.
Hours %= 12;

// Calculate the hour grid positions.
integer xHourPos = Hours % 4;
integer yHourPos = Hours / 4;

// Calcualte the minute texture index.
integer MinuteTextureIndex = DISPLAY_TYPE * 2 + Minutes / 30;

// Normalize the minutes to 0-29.
Minutes %= 30;

// Calculate the minute grid positions.
integer xMinutePos = Minutes % 5;
integer yMinutePos = Minutes / 5;

// Update the minute texture.
key MinuteTexture = llList2Key(MINUTE_TEXTURES, MinuteTextureIndex);
llSetTexture(MinuteTexture, MINUTE_FACE);

// Now update the offsets to show the current time on the textures.
llOffsetTexture(-0.40 + 0.20 * xMinutePos, 0.45 - 0.10 * yMinutePos, MINUTE_FACE);
llOffsetTexture(-0.375 + 0.250 * xHourPos, 0.375 - 0.25 * yHourPos, HOUR_FACE);
llOffsetTexture(0, 0.250 - 0.50 * AM_PM, AM_PM_FACE);
}

default {
state_entry() {
// First set up the correct texture scales, and rotations.
llScaleTexture(0.25, 0.25, HOUR_FACE);
llScaleTexture(0.20, 0.10, MINUTE_FACE);
llScaleTexture(1.00, 0.50, AM_PM_FACE);
llRotateTexture(PI_BY_TWO, HOUR_FACE);
llRotateTexture(0, MINUTE_FACE);
llRotateTexture(-PI_BY_TWO,AM_PM_FACE);

// Show the hour and am/pm textures, since they don't change.
llSetTexture(llList2Key(HOUR_TEXTURES, DISPLAY_TYPE), HOUR_FACE);
llSetTexture(llList2Key(AM_PM_TEXTURES, DISPLAY_TYPE), AM_PM_FACE);

// Now just update the time, it will also start the timer.
UpdateTime();
}

on_rez(integer param) {
UpdateTime();
}

timer() {
// This will show the time, and adjust the timer event.
UpdateTime();
}
}


Xylor