Author Topic: seasons.c Mod with moons  (Read 2868 times)

Offline memrosh

  • Acquaintance
  • *
  • Posts: 20
    • View Profile
seasons.c Mod with moons
« on: June 22, 2007, 04:51:19 AM »
This is a modification to the stock DS2.4.2 lib of /daemon/seasons.c

What has been added is a more realistic moon phase system and improved 'look' responces.
More realistic... yes, perfect... nah, but it is a step in that direction.
There is no inclination of a moons orbit accounted for like the suns variable daylight hours.

There has been some minor adjustments to the basic GetMudTime function as well as minor correction in the eventNight function.

The basic math functions, for determining orbital locations, I first saw in EverLib. This lib runs "The Lands of Evermore", an ldmud where I recieved my first education in LPC thanks to Meister. Thanks also to Fangorn, Bardioc, and Graveluth.

Note on /cfg/moons.cfg file:
In the header it states-
  # format:
  # moon:id:description
This might better read as-
  # format:
  # moon:phase:id:description
The phase is the number of real-life seconds that it takes a moon to go compleatly through its phases.
This is another way of saying how long it takes to orbit around your world.
If you want a moon like our own real life moon, that number would be a bit longer than 29 times the value of DAY_LENGTH * HOUR_LENGTH as set in /secure/include/config.h.
btw- the stock DS system seems to not like the moon named "Slayer" for some reason ;)

Some commenting has been added and indention for a bit more readability.

As Always- This file has not broke my mud. I do not know what other mods you have made in your own lib so I can not vouche for your own results ;)

Feedback, streamlining, comments, etc., are always welcome.

This is running on:
Driver: MudOS v22.2b14-dsouls2
Mudlib: Dead Souls 2.4.2
Windows XP servicepak2
No other current modifications to the lib.

Code: [Select]
/*    /daemon/seasons.c
 *    from the Dead Souls LPC Library
 *    handles game-based time
 *    created by Descartes of Borg 950508
 *    Version: @(#) seasons.c 1.7@(#)
 *    Last modified: 96/10/27
 *    Moon and time mods by Memrosh
 *    June 21, 2007
 */

#include <lib.h>
#include <cfg.h>
#include <config.h>
#include "include/seasons.h"

inherit LIB_DAEMON;

private static int CurrentDay, CurrentYear, Dawn, Morning, Twilight, Night;
private static int ticktock;
private static int op; //degree position of sun for earth observer
private static int mop; //degree position of moon for earth observer
private static string CurrentSeason, TimeOfDay;
private static mapping Moons;
private static class month CurrentMonth;
private static string *Days;
private static function *DawnCalls, *MorningCalls, *TwilightCalls;
private static function *NightCalls, *MidnightCalls;
private static class month *Months;

int eventTickTock(int tick){
    if(!tick) tick = 0;
    ticktock = tick;
    eventConfigure();
    return GetCurrentTime()/HOUR_LENGTH;
}

int GetTickTock(){ return ticktock; }

int *GetMudTime(){
    return ({ GetHour(GetCurrentTime()), GetMinutes(GetCurrentTime()) });
}


static void create() {
    string *lines;
    int i, maxi;

    daemon::create();
    MorningCalls = ({});
    DawnCalls = ({});
    TwilightCalls = ({});
    NightCalls = ({});
    MidnightCalls = ({});
    ticktock = 0;
    maxi = sizeof(lines = filter(explode(read_file(CFG_MONTHS), "\n"),
    (: $1 && $1 != "" && $1[0] != '#' :)));
    Months = allocate(maxi);
    for(i=0; i<maxi; i++) {
    Months[i] = new(class month);
    sscanf(lines[i], "%s:%s:%d:%d",((class month)Months[i])->Name,
      ((class month)Months[i])->Season,
      ((class month)Months[i])->Days,
      ((class month)Months[i])->DaylightHours);
    }
    Days = filter(explode(read_file(CFG_DAYS), "\n"),
      (: $1 && $1 != "" && $1[0] != '#' :));
    maxi = sizeof(lines = filter(explode(read_file(CFG_MOONS), "\n"),
    (: $1 && $1 != "" && $1[0] != '#' :)));
    Moons = allocate_mapping(maxi);
    for(i=0; i<maxi; i++) {
    string nom, id, desc, lnom;
    int phase;

    sscanf(lines[i], "%s:%d:%s:%s", nom, phase, id, desc);
    lnom = convert_name(nom);
    Moons[lnom] = new(class moon);
    ((class moon)Moons[lnom])->Name = nom;
    ((class moon)Moons[lnom])->Phase = phase;
    ((class moon)Moons[lnom])->Id = id;
    ((class moon)Moons[lnom])->Description = desc;
    }
    eventConfigure();
}

static void eventConfigure() {
    int i, x, days, tot, maxi;

    days = (time() - DAY_ONE) / (DAY_LENGTH * HOUR_LENGTH);
    for(tot=0, i=0, maxi = sizeof(Months); i<maxi; i++)
    tot += ((class month)Months[i])->Days;
    CurrentYear = days / tot + 1;
    days = (days % tot) + 1;
    for(i=0, maxi = sizeof(Months); i<maxi; i++) {
      if( days <= ((class month)Months[i])->Days ) {
        CurrentMonth = (class month)Months[i];
        CurrentSeason = ((class month)Months[i])->Season;
        CurrentDay = days;
        break;
      }
      else days -= ((class month)Months[i])->Days;
    }
    x = CurrentMonth->DaylightHours * HOUR_LENGTH;
    Morning = ((DAY_LENGTH * HOUR_LENGTH) - x) / 2;
    Twilight = Morning + x;
    if( Morning < HOUR_LENGTH ) {
    Dawn = Morning/2;
    Night = Twilight + Morning/2;
    }
    else {
    Dawn = Morning - HOUR_LENGTH;
    Night = Twilight + HOUR_LENGTH;
    }
    x = GetCurrentTime();
    if( x < Dawn ) {
    TimeOfDay = "night";
    call_out( (: eventDawn :), Dawn - x);
    }
    else if( x < Morning ) {
    TimeOfDay = "dawn";
    call_out( (: eventMorning :), Morning - x);
    }
    else if( x < Twilight ) {
    TimeOfDay = "day";
    call_out( (: eventTwilight :), Twilight - x);
    }
    else if( x < Night ) {
    TimeOfDay = "twilight";
    call_out( (: eventNight :), Night - x );
    }
    else {
    TimeOfDay = "night";
    call_out( (: eventMidnight :), (DAY_LENGTH * HOUR_LENGTH) - x);
    }
}

static void eventDawn() {
    object *obs;
    int i;

    call_out( (: eventMorning :), Morning - GetCurrentTime() );
    TimeOfDay = "dawn";
    obs = filter(users(), (: environment($1) &&
    (string)environment($1)->GetClimate()!="indoors" &&
    !((int)environment($1)->GetProperty("no time")) :));
    message("environment", "%^YELLOW%^The sun appears just over the horizon.",
      obs );
    i = sizeof(DawnCalls);
    while(i--) catch(evaluate(DawnCalls[i]));
}

static void eventMorning() {
    object *obs;
    int i;

    call_out( (: eventTwilight :), Twilight - GetCurrentTime());
    TimeOfDay = "day";
    obs = filter(users(), (: environment($1) &&
    (string)environment($1)->GetClimate()!="indoors" &&
    !((int)environment($1)->GetProperty("no time")) :));
    message("environment", "%^BOLD%^YELLOW%^The sun now shines completely "
      "on a new day.", obs);
    i = sizeof(MorningCalls);
    while(i--) catch(evaluate(MorningCalls[i]));
}

static void eventTwilight() {
    object *obs;
    int i;

    call_out( (: eventNight :), Night - GetCurrentTime() );
    TimeOfDay = "twilight";
    obs = filter(users(), (: environment($1) &&
    (string)environment($1)->GetClimate()!="indoors" &&
    !((int)environment($1)->GetProperty("no time")) :));
    message("environment", "%^CYAN%^The sun begins to fall away into "
      "twilight.", obs);
    i = sizeof(TwilightCalls);
    while(i--) catch(evaluate(TwilightCalls[i]));
}

static void eventNight() {
    object *obs;
    int i;

    call_out( (: eventMidnight :), (DAY_LENGTH * HOUR_LENGTH) - GetCurrentTime() );//modified
    TimeOfDay = "night";
    obs = filter(users(), (: environment($1) &&
    (string)environment($1)->GetClimate()!="indoors" &&
    !((int)environment($1)->GetProperty("no time")) :));
    message("environment", "%^BOLD%^BLUE%^Night darkens all that is real.", obs);
    i = sizeof(NightCalls);
    while(i--) catch(evaluate(NightCalls[i]));
}

static void eventMidnight() {
    int i;

    CurrentDay++;
    i = CurrentMonth->Days;
    if( CurrentDay > i ) {
    int y;

    y = CurrentYear;
    eventConfigure();
    if( y != CurrentYear )
        message("shout", "Happy New Year!!!\nIt is now the year " +
          GetYearString(CurrentYear) + "!!!!!", users());
    return;
    }
    call_out( (: eventDawn :), Dawn);
    TimeOfDay = "night";
    i = sizeof(MidnightCalls);
    while(i--) catch(evaluate(MidnightCalls[i]));
}

int GetCurrentDay() { return CurrentDay; }

string GetCurrentDayName() { return GetDayName(time()); }

string GetCurrentMonth() { return CurrentMonth->Name; }

string GetCurrentSeason() { return CurrentSeason; }

int GetCurrentTime() { return (time()- DAY_ONE) % (DAY_LENGTH * HOUR_LENGTH) + ticktock; }

int GetCurrentYear() { return CurrentYear; }

int GetDay(int x) {
    int tot, days, i, maxi;

    days = absolute_value((x - DAY_ONE) / (DAY_LENGTH * HOUR_LENGTH));
    for(tot=0, i=0, maxi = sizeof(Months); i<maxi; i++)
    tot += ((class month)Months[i])->Days;
    days = (days % tot) + ( (x < DAY_ONE) ? 0 : 1 );
    if( x < DAY_ONE ) {
    i = sizeof(Months);
    while(i--) {
        if( days < ((class month)Months[i])->Days )
        return ((class month)Months[i])->Days - days;
        else days -= ((class month)Months[i])->Days;
    }
    return 0;
    }
    for(i=0, maxi = sizeof(Months); i<maxi; i++) {
    if( days <= ((class month)Months[i])->Days ) return days;
    else days -= ((class month)Months[i])->Days;
    }
    return 0;
}

string GetDayName(int x) {
    int days;

    days = absolute_value((x - DAY_ONE) / (DAY_LENGTH * HOUR_LENGTH));
    return Days[days % sizeof(Days)];
}

string *GetDays() { return Days + ({}); }

int GetDaylightHours(string mon) {
    int i;

    i = sizeof(Months);
    while(i--) {
    if( ((class month)Months[i])->Name == mon )
        return ((class month)Months[i])->DaylightHours;
    }
    return 0;
}

int GetHour(int x) {
    int y;

    //y = absolute_value(GetTime(x));
    //y = y % (DAY_LENGTH * HOUR_LENGTH);
    //if( x < DAY_ONE ) y = (DAY_LENGTH * HOUR_LENGTH) - y;
    return (x / HOUR_LENGTH);
}

int GetMinutes(int x) {
    int y;

    y = absolute_value(GetTime(x));
    y = y % (DAY_LENGTH * HOUR_LENGTH);
    if( x < DAY_ONE ) y = (DAY_LENGTH * HOUR_LENGTH) - y;
    return (y % HOUR_LENGTH) / (HOUR_LENGTH/60);
}

string GetMonth(int x) {
    int monthIndex;

    monthIndex = GetMonthIndex(x);
    return Months[monthIndex]->Name;
}

private int GetMonthIndex(int x) {
    int tot, days, i, maxi;

    if( x < DAY_ONE ) days = (DAY_ONE - x) / (DAY_LENGTH * HOUR_LENGTH);
    else days = (x - DAY_ONE) / (DAY_LENGTH * HOUR_LENGTH);
    for(tot=0, i=0, maxi = sizeof(Months); i<maxi; i++)
    tot += ((class month)Months[i])->Days;
    days = (days % tot) + ((x >= DAY_ONE) ? 1 : 0);
    if( x < DAY_ONE ) {
    i = sizeof(Months);
    while(i--) {
        if( days < ((class month)Months[i])->Days )
        return i;
        else days -= ((class month)Months[i])->Days;
    }
    return 0;
    }
    for(i=0, maxi = sizeof(Months); i<maxi; i++) {
    if( days <= ((class month)Months[i])->Days )
        return i;
    else days -= ((class month)Months[i])->Days;
    }
    return 0;
}

string *GetMonths() {
    string *ret = ({});
    int i, maxi;

    for(i=0, maxi = sizeof(Months); i<maxi; i++)
    ret += ({ ((class month)Months[i])->Name });
    return ret;
}

string GetSeason(int x) {
    int monthIndex;

    monthIndex = GetMonthIndex(x);
    return Months[monthIndex]->Season;
}

int GetTime(int x) { return (x - DAY_ONE); }

string GetTimeOfDay() { return TimeOfDay; }

function AddTimeEvent(string tod, function f) {
    switch(tod) {
    case "dawn": DawnCalls += ({ f }); break;
    case "morning": MorningCalls += ({ f }); break;
    case "twilight": TwilightCalls += ({ f }); break;
    case "night": NightCalls += ({ f }); break;
    case "midnight": MidnightCalls += ({ f }); break;
    default: return 0;
    }
    return f;
}

mapping GetTimeEvents() {
    return ([ "dawn" : DawnCalls + ({}), "morning" : MorningCalls + ({}),
      "twilight" : TwilightCalls + ({}), "night" : NightCalls + ({}),
      "midnight" : MidnightCalls + ({}) ]);
}

int GetYear(int x) {
    int i, tot;

    i = sizeof(Months);
    while(i--) tot += ((class month)Months[i])->Days;
    i = ((x - DAY_ONE) / (DAY_LENGTH * HOUR_LENGTH)) / tot;
    if( x < DAY_ONE ) return i;
    else return i + 1;
}

string GetYearString(int x) {
    if( x < 0 ) return (x * (-1)) + " BN";
    else return x + " NM";
}

string GetPhaseName(mixed val) {
    if( stringp(val) ) { val = GetPhase(val); }
    switch(val) {
      case 0: return "new";
      case 1: return "waxing";
      case 2: return "full";
      case 3: return "waning";
      default: return "error";
    }
}

int GetPhase(string m) {
    int x, y, z, a;

    m = convert_name(m);
    x = ((class moon)Moons[m])->Phase;
    y = (time() - DAY_ONE) % x; //phase time
    a= 360-(y * 360 / x); //moon from sun
    switch(a){
        case 45..134: if(x > (HOUR_LENGTH*DAY_LENGTH)){z=3;}else{z=1;} break;
        case 135..224: z=2; break;
        case 225..314: if(x > (HOUR_LENGTH*DAY_LENGTH)){z=1;}else{z=3;} break;
        default: z=0;
    }
    return z;
}
int GetSOP(){ //sun orbital position, no current use from within
    op= GetCurrentTime() * 360 / (DAY_LENGTH * HOUR_LENGTH);
    return op;
}
int GetMOP(string m){ //moon orbital position from player viewpoint
    int x, y, z, a, b;
    m = convert_name(m);
    x = ((class moon)Moons[m])->Phase;
    y = (time() - DAY_ONE) % x;
    a= 360-(y * 360 / x);
    b= GetCurrentTime() * 360 / (DAY_LENGTH * HOUR_LENGTH);
    mop= (360-((360-b)-a))%360;
    return mop;
}
int MoonIsVis( string m){
    int c;
    if(!stringp(m)){return 0;}
    c=GetMOP(m);
    if(c >=90 && c <=270 ){ return 1;}else{return 0;}
}
int GetRadiantLight() {
    switch( TimeOfDay ) {
    case "night": return (GetMoonLight() * 2);
    case "day": return 60;
    default: return 30;
    }
}

int GetMoonLight() {
    string *moons;
    int i, y = 0;

    i = sizeof(moons = keys(Moons));
    while(i--) {
      int z;
      if( MoonIsVis(moons[i]) ){ //above horizon
          z = GetPhase(moons[i]);
          if( z == 3) z = 1;
          y += z;
      }
    }
    return y;
}


string GetLong(string arg) {
    string array arr, mn;
    object env;
    string tmp;
    string * moons;
    int i, pos, x, y;

    if( !(env = environment(this_player())) )
    return "You are in serious trouble.";
    switch(arg) {
      case "sun":
        switch(GetTimeOfDay()) {
          case "dawn":
            return "The sun is hanging low in the eastern sky.";
          case "day":
            return "The sun is shining brightly in the daytime sky.";
          case "twilight":
            return "The sun is sinking into the western sky.";
          case "night":
           return "The sun is below the horizon.";
        }
      case "moon": case "moons":
        i = sizeof(moons = keys(Moons));
        if(!i){ return 0; }
        x = 0;
        while(i--){
          pos=GetMOP(moons[i]);
          if(pos >=90 && pos <=270){
            y = GetPhase(moons[i]);
            if(!stringp(tmp)){
              tmp = capitalize(((class moon)Moons[moons[i]])->Id) +
              " is " + GetPhaseName(y) + " ";
            }else{
              tmp += "\n" +
              capitalize(((class moon)Moons[moons[i]])->Id) + " is " +
              GetPhaseName(y) + " ";
            }
            switch(pos){
              case 90..100:
                tmp += "and is just above the eastern horizon.";
              break;
              case 101..169:
                tmp += "and is hanging in the eastern sky.";
              break;
              case 170..190:
                tmp += "and is high overhead.";
              break;
              case 191..259:
                tmp += "and is hanging in the western sky.";
              break;
              case 260..270:
                tmp += "and is just above the western horizon.";
              break;
              default:
            }
            x = 1;
          }
        }
        if( !x ){ return "No "+arg+" visible at this time."; }else{ return tmp; }

      case "sky":
        if( GetTimeOfDay() == "night" ) {
          tmp =  GetLong("moon");
          if( !tmp ) {
          return "The sky is filled only with the glitter of stars.";
          }
          else {
          return tmp;
          }
        } //end night
        else {
        string sky;

        tmp = GetLong("sun");
        if( this_player() ) {
        env = environment(this_player());
        }
        if( sky = env->GetSky() ) {
        env = find_object(sky);
        if( env ) {
            object array obs = filter(all_inventory(env),
              function(object ob) {
              if( ob->GetInvis(this_player()) ) {
                  return 0;
              }
              if( living(ob) ) {
                  return 1;
              }
              return 0;
            });

              if( sizeof(obs) ) {
              int maxi = sizeof(obs);

              sky = obs[i]->GetName();
              if( maxi == 1 ) {
                  sky += " is flying in the sky.";
              }
              else {
                  for(i=1; i<maxi; i++) {
                  if( i == maxi-1 ) {
                      if( maxi == 2 ) {
                      sky += " and ";
                      }
                      else {
                      sky += ", and ";
                      }
                  }
                  else {
                      sky += ", ";
                  }
                  sky += obs[i]->GetName();
                  }
                  sky += " are flying in the sky.";
              }
              tmp = sky + "\n" + tmp;
              }
          }
        }
        return tmp;
      }
      default:
        if( Moons[arg] ){
            if(MoonIsVis(arg)){
                tmp = capitalize(arg)+", "+
                lower_case( ((class moon)Moons[arg])->Description)[0..<2]+
                " is "+GetPhaseName(GetPhase(arg))+" and ";
                switch(GetMOP(arg)){
                    case 90..100:
                      tmp += "is just above the eastern horizon.";
                    break;
                    case 101..169:
                      tmp += "hangs in the eastern sky.";
                    break;
                    case 170..190:
                      tmp += "is high overhead.";
                    break;
                    case 191..259:
                      tmp += "hangs in the western sky.";
                    break;
                    case 260..270:
                      tmp += "is just above the western horizon.";
                    break;
                    default:
                }
                return tmp;
            }else{
                return capitalize(arg)+" is not visible at this time.";
            }
        }

        arr = map(mn = keys(Moons), (: ((class moon)Moons[$1])->Id :));
        if( (i = member_array(arg, arr)) != -1 ){
          if(MoonIsVis(mn[i])){
              tmp = capitalize(mn[i])+", "+
                lower_case( ((class moon)Moons[mn[i]])->Description)[0..<2]+
                " is "+GetPhaseName(GetPhase(mn[i]))+" and ";
              switch(GetMOP(mn[i])){
                case 90..100:
                  tmp += "is just above the eastern horizon.";
                break;
                case 101..169:
                  tmp += "hangs in the eastern sky.";
                break;
                case 170..190:
                  tmp += "is high overhead.";
                break;
                case 191..259:
                  tmp += "hangs in the western sky.";
                break;
                case 260..270:
                  tmp += "is just above the western horizon.";
                break;
                default:
              }
              return tmp;
          }else{
              return capitalize(mn[i])+" is not visible at this time.";
          }
        }else{ return 0; }
    }
}

string array GetMoons() {
    return map(keys(Moons), (: ((class moon)Moons[$1])->Name :));
}

int eventShow(object who, string args) {
    string str;
    if( !who || !sizeof(args) ) return 0;
    if( !str = GetLong(args) ) return 0;
    if( (string)environment(who)->GetClimate() == "indoors" ) {
        who->eventPrint("You are not outside!");
        return 1;
    }
    who->eventPrint(str);
    environment(who)->eventPrint((string)who->GetName() + " gazes toward the sky.", who);
    return 1;
}

Happy moon gazing,
Memrosh

Offline Atomic

  • BFF
  • ***
  • Posts: 115
  • To infinity and beyond!
    • View Profile
Re: seasons.c Mod with moons
« Reply #1 on: June 26, 2007, 08:20:48 AM »
What a lovely nice addition, thanks Memrosh, I'll see if I can get it to not break stuff on my mud either :).
Always remember that the early bird gets the worm first, but the fi...*SNAP*...second mouse gets the cheese.

Offline z993126

  • BFF
  • ***
  • Posts: 128
    • View Profile
Re: seasons.c Mod with moons
« Reply #2 on: August 08, 2011, 10:30:34 PM »
I've made a few...modifications to this quite nice seasons mod, as follows:
  Moon phases needed correcting; they're a function of where the moon is in the sky in relation to the sun.
  Comment in moons.cfg better as moon:period:id:description, since 'phase' was making me think of the 'time between phases' rather than 'time for full synodic month'.
  Sunrise, sunset time setting replaced by a more complex method that generates a smooth curve over the course of the year with the longest amount of daylight being the maximum value of day_length in months.c, occurring at the midpoint of the year and the smallest being the minimum, at the first of the year.
  Twilight durations modified from ONE_HOUR to a varying curve with minimums at the 'equinoxes', maximum at the midpoint of the year, and a midway-value at the end of the year.
  Season names added to sun events.
  ** Added T_WATERSHALLOW and T_INDOORSWINDOW to /lib/include/terrain_types.h **
  Added additional checking of environment type to sun events to better represent where can and can't see sunrise/sunset or its effects; if indoors where there's a window, can see sky lightening and darkening at relevant times, and if in shallow water, can see the water grow lighter or darker.  Also a check for indoors where there's a window, in shallow water.
  Redid construction of 'sky' description to include non-new moons during the day if present.
  Redid construction of 'moons' description to be a run-in list, e.g. "Laros, the red moon, is full and in the sky to the east; Slayar, the green moon, and Spyefel, the blue moon, are waning crescent and low in the sky to the west."
  Added check for indoors with window to 'x sky' so it returns "You cannot see the sky, because you are not outside, but the outside the window is light/dark."

Code: [Select]
/*    /daemon/seasons.c
 *    from the Dead Souls LPC Library
 *    handles game-based time
 *    created by Descartes of Borg 950508
 *    Version: @(#) seasons.c 1.7@(#)
 *    Last modified: 96/10/27
 *    Moon and time mods by Memrosh
 *    June 21, 2007
 *    modified 2011-Aug-07 by T. Cook to correct moon phase names
 *    modified 2011-Aug-06 by T. Cook to concatenate moon descriptions
 *    modified 2011-Jul-31 by T. Cook to make formatting consistent
 *    modified 2011-Jul-31 by T. Cook to improve sunrise and set times
 *    modified 2011-Jul-20 by T. Cook to improve moon phase & season descriptions
 *    to do: tides!...?
 */

#include <lib.h>
#include <cfg.h>
#include <config.h>
#include <terrain_types.h>
#include "include/seasons.h"

inherit LIB_DAEMON;

private static int CurrentDay, CurrentYear, Dawn, Sunrise, Sunset, Night;
private static int ticktock;
private static int op;  // degree position of sun for earth observer
private static int mop; // degree position of moon for earth observer
private static string CurrentSeason, TimeOfDay;
private static mapping Moons;
private static class month CurrentMonth;
private static string *Days;
private static function *DawnCalls, *SunriseCalls, *SunsetCalls;
private static function *NightCalls, *MidnightCalls;
private static class month *Months;

int eventTickTock( int tick ){
if( !tick ) tick = 0;
ticktock = tick;
eventConfigure();
return GetCurrentTime() / HOUR_LENGTH;
}

int GetTickTock(){ return ticktock; }

int *GetMudTime(){
return ({ GetHour( GetCurrentTime() ), GetMinutes( GetCurrentTime() ) });
}

static void create(){
string *lines;
int i, maxi;

daemon::create();
SunriseCalls = ({});
DawnCalls = ({});
SunsetCalls = ({});
NightCalls = ({});
MidnightCalls = ({});
ticktock = 0;
maxi = sizeof( lines = filter( explode( read_file( CFG_MONTHS ), "\n" ),
(: $1 && $1 != "" && $1[0] != '#' :) ) );
Months = allocate( maxi );
for( i = 0; i < maxi; i++ ){
Months[i] = new( class month );
sscanf(
lines[i], "%s:%s:%d:%d",
( (class month) Months[i] )->Name,
( (class month) Months[i] )->Season,
( (class month) Months[i] )->Days,
( (class month) Months[i] )->DaylightHours
);
}
Days = filter( explode( read_file( CFG_DAYS ), "\n" ), (: $1 && $1 != "" && $1[0] != '#' :) );
maxi = sizeof( lines = filter( explode( read_file( CFG_MOONS ), "\n" ),
(: $1 && $1 != "" && $1[0] != '#' :) ) );
Moons = allocate_mapping( maxi );
for( i = 0; i < maxi; i++ ){
string nom, id, desc, lnom;
int period;

sscanf( lines[i], "%s:%d:%s:%s", nom, period, id, desc );
lnom = convert_name( nom );
Moons[lnom] = new( class moon );
( (class moon) Moons[lnom] )->Name = nom;
( (class moon) Moons[lnom] )->Period = period;
( (class moon) Moons[lnom] )->Id = id;
( (class moon) Moons[lnom] )->Description = desc;
}
eventConfigure();
}

static void eventConfigure(){
int i, x, days, tot, maxi;
// the following variables are for the improved sun event math
int YEAR_LENGTH, CircYear, YearDay, TodayDaylight, TodayTwilight, *MonthArray, DaylightRange;
float AVG_DAYLIGHT_HOURS, AVG_MONTH_LENGTH;

days = ( time() - DAY_ONE ) / ( DAY_LENGTH * HOUR_LENGTH );
for( tot = 0, i = 0, maxi = sizeof( Months ); i < maxi; i++ ){
tot += ( (class month) Months[i] )->Days;
}
CurrentYear = days / tot + 1;
days = ( days % tot ) + 1;
for( i = 0, maxi = sizeof( Months ); i < maxi; i++ ){
if( days <= ( (class month) Months[i] )->Days ){
CurrentMonth = (class month) Months[i];
CurrentSeason = ( (class month) Months[i] )->Season;
CurrentDay = days;
break;
}
else days -= ( (class month) Months[i] )->Days;
}
// old math for simplified sun event times
// x = CurrentMonth->DaylightHours * HOUR_LENGTH;
// Sunrise = ( ( DAY_LENGTH * HOUR_LENGTH ) - x ) / 2;
// Sunset = Sunrise + x;
// new math for improved sun event times
MonthArray = allocate( sizeof( Months ) );
for( YEAR_LENGTH = 0, i = 0, maxi = sizeof( Months ); i < maxi; i++ ){
YEAR_LENGTH += ( (class month) Months[i] )->Days;
MonthArray[i] = ( (class month) Months[i] )->DaylightHours;
}
DaylightRange = max( MonthArray ) - min( MonthArray );
AVG_MONTH_LENGTH = YEAR_LENGTH / sizeof( Months );
for( AVG_DAYLIGHT_HOURS = 0, i = 0, maxi = sizeof( Months ); i < maxi; i++ ){
AVG_DAYLIGHT_HOURS += ( (class month) Months[i] )->DaylightHours;
}
AVG_DAYLIGHT_HOURS = AVG_DAYLIGHT_HOURS / sizeof( Months );
// current day of year
YearDay = ( ( time() - DAY_ONE ) / ( DAY_LENGTH * HOUR_LENGTH ) % YEAR_LENGTH );
// position of planet in simplified orbit in degrees
CircYear = ( YearDay / ( YEAR_LENGTH / 360.0 ) );
// today's daylight duration
TodayDaylight = ( AVG_DAYLIGHT_HOURS + DaylightRange *
-cos( CircYear * 0.01745329 ) ) * HOUR_LENGTH;
// twilight duration; equinoxes through summer solstice
if( CircYear > 90 && CircYear < 270 ){
TodayTwilight = ( HOUR_LENGTH * 1.5 ) + ( ( HOUR_LENGTH / 4 ) *
cos( ( CircYear / ( AVG_MONTH_LENGTH / 4 ) * 0.01745329 ) ) );
// twilight duration; equinoxes through winter solstice
}else{
TodayTwilight = ( HOUR_LENGTH * 1.375 ) + ( ( HOUR_LENGTH / 8 ) *
cos( ( CircYear / ( AVG_MONTH_LENGTH / 4 ) * 0.01745329 ) ) );
}
Dawn = ( ( DAY_LENGTH * HOUR_LENGTH / 2 ) - ( TodayDaylight / 2 ) - TodayTwilight );
Sunrise = ( ( DAY_LENGTH * HOUR_LENGTH / 2 ) - ( TodayDaylight / 2 ) );
Sunset = ( ( DAY_LENGTH * HOUR_LENGTH / 2 ) + ( TodayDaylight / 2 ) );
Night = ( ( DAY_LENGTH * HOUR_LENGTH / 2 ) + ( TodayDaylight / 2 ) + TodayTwilight );
if( Sunrise < HOUR_LENGTH ){
Dawn = Sunrise / 2;
Night = Sunset + Sunrise / 2;
}
x = GetCurrentTime();
if(       x < Dawn    ){
TimeOfDay = "night";
call_out( (: eventDawn :), to_int( Dawn - x ));
}else if( x < Sunrise ){
TimeOfDay = "dawn";
call_out( (: eventSunrise :), to_int( Sunrise - x ) );
    }else if( x < Sunset  ){
TimeOfDay = "day";
call_out( (: eventSunset :), to_int( Sunset - x ) );
}else if( x < Night   ){
TimeOfDay = "dusk";
call_out( (: eventNight :), to_int( Night - x ) );
}else{
TimeOfDay = "night";
call_out( (: eventMidnight :), to_int( ( DAY_LENGTH * HOUR_LENGTH ) - x ) ); }
}

static void eventDawn(){
object *obs;
int i;

call_out( (: eventSunrise :), Sunrise - GetCurrentTime() );
TimeOfDay = "dawn";
// player is outdoors and can see the dawn
obs = filter( users(), (:
environment( $1 ) &&
(string) environment( $1 )->GetClimate() != "indoors" &&
!( ( environment( $1 )->GetTerrainType() & T_SPACE ) ||
( environment( $1 )->GetTerrainType() & T_PLASMA ) ||
( environment( $1 )->GetTerrainType() & T_SEAFLOOR ) ||
( environment( $1 )->GetTerrainType() & T_UNDERWATER ) ||
( environment( $1 )->GetTerrainType() & T_WATERSHALLOW ) ||
( environment( $1 )->GetTerrainType() & T_INDOORS ) ||
( environment( $1 )->GetTerrainType() & T_INDOORSWINDOW ) ||
( environment( $1 )->GetTerrainType() & T_BIOLOGICAL ) ||
( environment( $1 )->GetTerrainType() & T_UNDERGROUND ) ||
( environment( $1 )->GetTerrainType() & T_MAGMA ) ) &&
!( (int) environment( $1 )->GetProperty( "no time" ) )
:) );
message(
"environment",
"%^ORANGE%^The eastern " + GetCurrentSeason() + " sky begins to grow lighter.%^RESET%^",
obs
);
// player is in an shallow-underwater room with a window and can see the dawn
obs = filter( users(), (:
environment( $1 ) &&
( environment( $1 )->GetTerrainType() & T_WATERSHALLOW ) &&
( environment( $1 )->GetTerrainType() & T_INDOORSWINDOW ) &&
!( (int) environment( $1 )->GetProperty( "no time" ) )
:) );
message(
"environment",
"%^BOLD%^%^CYAN%^The water outside the window begins to grow lighter.%^RESET%^",
obs
);
// players is in a room with a window and can see the dawn
obs = filter( users(), (:
environment( $1 ) &&
!( environment( $1 )->GetTerrainType() & T_WATERSHALLOW ) &&
( environment( $1 )->GetTerrainType() & T_INDOORSWINDOW ) &&
!( (int) environment( $1 )->GetProperty( "no time" ) )
:) );
message(
"environment",
"%^ORANGE%^The sky outside the window begins to grow lighter.%^RESET%^",
obs
);
// player is in shallow water and can see the dawn
obs = filter( users(), (:
environment( $1 ) &&
( environment( $1 )->GetTerrainType() & T_WATERSHALLOW ) &&
!( environment( $1 )->GetTerrainType() & T_INDOORSWINDOW ) &&
!( (int) environment( $1 )->GetProperty( "no time" ) )
:) );
message(
"environment",
"%^BOLD%^%^CYAN%^The water begins to grow lighter.%^RESET%^",
obs
);

i = sizeof( DawnCalls );
while( i-- ){ catch( evaluate( DawnCalls[i] ) ); }
}

static void eventSunrise(){
object *obs;
int i;

call_out( (: eventSunset :), Sunset - GetCurrentTime());
TimeOfDay = "day";
obs = filter( users(), (:
environment( $1 ) &&
(string) environment( $1 )->GetClimate() != "indoors" &&
!( ( environment( $1 )->GetTerrainType() & T_SPACE ) ||
( environment( $1 )->GetTerrainType() & T_PLASMA ) ||
( environment( $1 )->GetTerrainType() & T_SEAFLOOR ) ||
( environment( $1 )->GetTerrainType() & T_UNDERWATER ) ||
( environment( $1 )->GetTerrainType() & T_WATERSHALLOW ) ||
( environment( $1 )->GetTerrainType() & T_INDOORS ) ||
( environment( $1 )->GetTerrainType() & T_INDOORSWINDOW ) ||
( environment( $1 )->GetTerrainType() & T_BIOLOGICAL ) ||
( environment( $1 )->GetTerrainType() & T_UNDERGROUND ) ||
( environment( $1 )->GetTerrainType() & T_MAGMA ) ) &&
!( (int) environment( $1 )->GetProperty( "no time" ) )
:) );
message(
"environment",
"%^BOLD%^%^YELLOW%^The bright orb of the " + GetCurrentSeason() +
" sun clears the horizon.%^RESET%^",
obs
);
i = sizeof( SunriseCalls );
while( i-- ){ catch( evaluate( SunriseCalls[i] ) ); }
}

static void eventSunset(){
object *obs;
int i;

call_out( (: eventNight :), Night - GetCurrentTime() );
TimeOfDay = "dusk";
// player is outside and can see the sunset
obs = filter( users(), (:
environment( $1 ) &&
(string) environment( $1 )->GetClimate() != "indoors" &&
!( ( environment( $1 )->GetTerrainType() & T_SPACE ) ||
( environment( $1 )->GetTerrainType() & T_PLASMA ) ||
( environment( $1 )->GetTerrainType() & T_SEAFLOOR ) ||
( environment( $1 )->GetTerrainType() & T_UNDERWATER ) ||
( environment( $1 )->GetTerrainType() & T_WATERSHALLOW ) ||
( environment( $1 )->GetTerrainType() & T_INDOORS ) ||
( environment( $1 )->GetTerrainType() & T_INDOORSWINDOW ) ||
( environment( $1 )->GetTerrainType() & T_BIOLOGICAL ) ||
( environment( $1 )->GetTerrainType() & T_UNDERGROUND ) ||
( environment( $1 )->GetTerrainType() & T_MAGMA ) ) &&
!( (int) environment( $1 )->GetProperty( "no time" ) )
:) );
message(
"environment",
"%^CYAN%^The " + GetCurrentSeason() + " sun sinks below the horizon.%^RESET%^",
obs
);
// player is in a shallow-underwater room with a window and can see the effect of dusk
obs = filter( users(), (:
environment( $1 ) &&
( environment( $1 )->GetTerrainType() & T_WATERSHALLOW ) &&
( environment( $1 )->GetTerrainType() & T_INDOORSWINDOW ) &&
!( (int) environment( $1 )->GetProperty( "no time" ) )
:) );
message(
"environment",
"%^BOLD%^%^BLUE%^The water outside the window slowly darkens.%^RESET%^",
obs
);
// player is in a room with a window and can see the effect of dusk
obs = filter( users(), (:
environment( $1 ) &&
!( environment( $1 )->GetTerrainType() & T_WATERSHALLOW ) &&
( environment( $1 )->GetTerrainType() & T_INDOORSWINDOW ) &&
!( (int) environment( $1 )->GetProperty( "no time" ) )
:) );
message(
"environment",
"%^CYAN%^The sky outside the window slowly darkens.%^RESET%^",
obs
);
// player is in shallow water and can see the effect of dusk
obs = filter( users(), (:
environment( $1 ) &&
( environment( $1 )->GetTerrainType() & T_WATERSHALLOW ) &&
!( environment( $1 )->GetTerrainType() & T_INDOORSWINDOW ) &&
!( (int) environment( $1 )->GetProperty( "no time" ) )
:) );
message(
"environment",
"%^BOLD%^%^BLUE%^The water slowly darkens.%^RESET%^",
obs
);

i = sizeof( SunsetCalls );
while( i-- ){ catch( evaluate( SunsetCalls[i] ) ); }
}

static void eventNight(){
object *obs;
int i;

call_out( (: eventMidnight :), ( DAY_LENGTH * HOUR_LENGTH ) - GetCurrentTime() );  // modified
TimeOfDay = "night";
obs = filter( users(), (:
environment( $1 ) &&
(string) environment( $1 )->GetClimate() != "indoors" &&
!( ( environment( $1 )->GetTerrainType() & T_SPACE ) ||
( environment( $1 )->GetTerrainType() & T_PLASMA ) ||
( environment( $1 )->GetTerrainType() & T_SEAFLOOR ) ||
( environment( $1 )->GetTerrainType() & T_UNDERWATER ) ||
( environment( $1 )->GetTerrainType() & T_WATERSHALLOW ) ||
( environment( $1 )->GetTerrainType() & T_INDOORS ) ||
( environment( $1 )->GetTerrainType() & T_INDOORSWINDOW ) ||
( environment( $1 )->GetTerrainType() & T_BIOLOGICAL ) ||
( environment( $1 )->GetTerrainType() & T_UNDERGROUND ) ||
( environment( $1 )->GetTerrainType() & T_MAGMA ) ) &&
!( (int) environment( $1 )->GetProperty( "no time" ) )
:) );
message(
"environment",
"%^BOLD%^%^BLUE%^Darkness falls as the " + GetCurrentSeason() + " night descends.%^RESET%^",
obs
);
i = sizeof( NightCalls );
while( i-- ){ catch( evaluate( NightCalls[i] ) ); }
}

static void eventMidnight(){
int i;

CurrentDay++;
i = CurrentMonth->Days;
if( CurrentDay > i ){
int y;

y = CurrentYear;
eventConfigure();
if( y != CurrentYear ){
message(
"shout",
"Happy New Year!\nIt is now the year " + GetYearString( CurrentYear ) + "!",
users()
);
}
return;
}
call_out( (: eventDawn :), Dawn );
TimeOfDay = "night";
i = sizeof( MidnightCalls );
while( i-- ){ catch( evaluate( MidnightCalls[i] ) ); }
}

int GetCurrentDay(){ return CurrentDay; }

string GetCurrentDayName(){ return GetDayName( time() ); }

string GetCurrentMonth(){ return CurrentMonth->Name; }

string GetCurrentSeason(){ return CurrentSeason; }

int GetCurrentTime(){ return ( time()- DAY_ONE ) % ( DAY_LENGTH * HOUR_LENGTH ) + ticktock; }

int GetCurrentYear(){ return CurrentYear; }

int GetDay( int x ){
int tot, days, i, maxi;

days = absolute_value( ( x - DAY_ONE ) / ( DAY_LENGTH * HOUR_LENGTH ) );
for( tot = 0, i = 0, maxi = sizeof( Months ); i < maxi; i++ ){
tot += ( (class month) Months[i] )->Days;
}
days = ( days % tot ) + ( ( x < DAY_ONE ) ? 0 : 1 );
if( x < DAY_ONE ){
i = sizeof( Months );
while( i-- ){
if( days < ( (class month) Months[i] )->Days ){
return ( (class month) Months[i] )->Days - days;
}else{
days -= ( (class month) Months[i] )->Days;
}
}
return 0;
}
for( i = 0, maxi = sizeof( Months ); i < maxi; i++ ){
if( days <= ( (class month) Months[i] )->Days ){ return days; }
else{ days -= ( (class month) Months[i] )->Days; }
}
return 0;
}

string GetDayName( int x ){
int days;

days = absolute_value( ( x - DAY_ONE ) / ( DAY_LENGTH * HOUR_LENGTH ) );
return Days[days % sizeof( Days )];
}

string *GetDays(){ return Days + ({}); }

int GetDaylightHours( string mon ){
int i;

i = sizeof( Months );
while( i-- ){
if( ( (class month) Months[i] )->Name == mon ){
return ( (class month) Months[i] )->DaylightHours;
}
}
return 0;
}

int GetHour( int x ){
//int y;

//y = absolute_value(GetTime(x));
//y = y % (DAY_LENGTH * HOUR_LENGTH);
//if( x < DAY_ONE ) y = (DAY_LENGTH * HOUR_LENGTH) - y;
return ( x / HOUR_LENGTH );
}

int GetMinutes( int x ){
int y;

y = absolute_value( GetTime( x ) );
y = y % ( DAY_LENGTH * HOUR_LENGTH );
if( x < DAY_ONE ){ y = ( DAY_LENGTH * HOUR_LENGTH ) - y; }
return ( y % HOUR_LENGTH ) / ( HOUR_LENGTH / 60 );
}

string GetMonth( int x ){
int monthIndex;

monthIndex = GetMonthIndex( x );
return Months[monthIndex]->Name;
}

private varargs int GetMonthIndex( int x ){
int tot, days, i, maxi;

if( x < DAY_ONE ){ days = ( DAY_ONE - x ) / ( DAY_LENGTH * HOUR_LENGTH ); }
else{ days = ( x - DAY_ONE ) / ( DAY_LENGTH * HOUR_LENGTH ); }
for( tot = 0, i = 0, maxi = sizeof( Months ); i < maxi; i++ ){
tot += ( (class month) Months[i] )->Days;
}
days = ( days % tot ) + ( ( x >= DAY_ONE ) ? 1 : 0 );
if( x < DAY_ONE ){
i = sizeof( Months );
while( i-- ){
if( days < ( (class month) Months[i] )->Days ){ return i; }
else{ days -= ( (class month) Months[i])->Days; }
}
return 0;
}
for( i = 0, maxi = sizeof( Months ); i < maxi; i++ ){
if( days <= ( (class month) Months[i] )->Days ){ return i; }
else{ days -= ( (class month) Months[i] )->Days; }
}
return 0;
}

string *GetMonths(){
string *ret = ({});
int i, maxi;

for( i = 0, maxi = sizeof( Months ); i < maxi; i++ ){
ret += ({ ( (class month) Months[i] )->Name });
}
return ret;
}

string GetSeason( int x ){
int monthIndex;

monthIndex = GetMonthIndex( x );
return Months[monthIndex]->Season;
}

int GetTime( int x ){ return ( x - DAY_ONE ); }

string GetTimeOfDay(){ return TimeOfDay; }

function AddTimeEvent( string tod, function f ){
switch( tod ){
case "dawn": DawnCalls += ({ f }); break;
case "day": SunriseCalls += ({ f }); break;
case "dusk": SunsetCalls += ({ f }); break;
case "night": NightCalls += ({ f }); break;
case "midnight": MidnightCalls += ({ f }); break;
default: return 0;
}
return f;
}

mapping GetTimeEvents(){
return ([
"dawn" : DawnCalls + ({}),
"day" : SunriseCalls + ({}),
"dusk" : SunsetCalls + ({}),
"night" : NightCalls + ({}),
"midnight" : MidnightCalls + ({})
]);
}

int GetYear( int x ){
int i, tot;

i = sizeof( Months );
while( i-- ){ tot += ( (class month) Months[i] )->Days; }
i = ( ( x - DAY_ONE ) / ( DAY_LENGTH * HOUR_LENGTH ) ) / tot;
if( x < DAY_ONE ){ return i; }
else{ return i + 1; }
}

string GetYearString( int x ){
if( x < 0 ){ return ( -x ) + " BN"; }
else return x + " NM";
}

string GetPhaseName( mixed val ){
if( stringp( val ) ){ val = GetPhase( val ); }
switch( val ){
case 0: return "new";
case 1: return "waxing crescent";
case 2: return "first quarter";
case 3: return "waxing gibbous";
case 4: return "full";
case 5: return "waning gibbous";
case 6: return "last quarter";
case 7: return "waning crescent";
default: return "error";
}
}

int GetPhase( string m ){
int a, z;
/*
int x, y, z, a, b;

m = convert_name( m );
b = HOUR_LENGTH * DAY_LENGTH;
x = ( (class moon) Moons[m] )->Period;
y = ( time() - DAY_ONE ) % x;  // period time
a = 360 - ( y * 360 / x );  // moon from sun
switch( a ){
case   0..  1: z = 0; break;
case   2.. 88: z = 1; break;//if( x > b ){ z = 7; }else{ z = 1; } break;
case  89.. 91: z = 2; break;//if( x > b ){ z = 6; }else{ z = 2; } break;
case  92..178: z = 3; break;//if( x > b ){ z = 5; }else{ z = 3; } break;
case 179..181: z = 4; break;
case 182..268: z = 5; break;//if( x > b ){ z = 3; }else{ z = 5; } break;
case 269..272: z = 6; break;//if( x > b ){ z = 2; }else{ z = 6; } break;
case 273..358: z = 7; break;//if( x > b ){ z = 1; }else{ z = 7; } break;
case 359..360: z = 0; break;
default: z = 0;
}
//return z;
*/
m = convert_name( m );
a = ( GetMOP( m ) - GetSOP() ) % 360;
switch( a ){
case   0..  1: z = 4; break;
case   2.. 88: z = 5; break;
case  89.. 91: z = 6; break;
case  92..178: z = 7; break;
case 179..181: z = 0; break;
case 182..268: z = 1; break;
case 269..272: z = 2; break;
case 273..358: z = 3; break;
case 359..360: z = 4; break;
default: z = 4; break;
}
return z;
}
int GetSOP(){  // sun orbital position
op = GetCurrentTime() * 360 / ( DAY_LENGTH * HOUR_LENGTH );
return op;
}
int GetMOP( string m ){  // moon orbital position from player viewpoint
int x, y, z, a, b;
m = convert_name( m );
x = ( (class moon) Moons[m] )->Period;
y = ( time() - DAY_ONE ) % x;
a = 360 - ( y * 360 / x );
//b = GetCurrentTime() * 360 / ( DAY_LENGTH * HOUR_LENGTH );
//mop = ( 360 - ( ( 360 - b ) - a ) ) % 360;
mop = ( 360 - ( ( 360 - GetSOP() ) - a ) ) % 360;
return mop;
}
int MoonIsVis( string m ){  // visibility of moon including new phase status
int c;
if( !stringp( m ) ){ return 0; }
c = GetMOP( m );
if( c >= 90 && c <= 270 && GetPhase( m ) != 0 ){ return 1; }else{ return 0; }
}
int GetRadiantLight(){
switch( TimeOfDay ){
case "night": return ( GetMoonLight() * 2 );
case "day": return 60;
default: return 30;
}
}

int GetMoonLight(){
string *moons;
int i, y = 0;

i = sizeof( moons = keys( Moons ) );
while( i-- ){
int z;
if( MoonIsVis(moons[i]) ){  // above horizon
z = GetPhase( moons[i] );
if( z == 3 ){ z = 1; }
y += z;
}
}
return y;
}

string GetLong( string arg ){
string array arr, mn;
object env, *obs;
string tmp, tmp2;
string *moons;
int i, pos, x, y, maxi, n, i2, counter, counter2, *moongroup;

if( !(env = environment( this_player() ) ) ){ return "You do not have an enviroment!"; }
switch( arg ){
case "sun":{
switch( GetSOP() ){
case  90..100: return "\nThe " + GetCurrentSeason() + " sun is low in the eastern sky.";
case 101..169: return "\nThe " + GetCurrentSeason() + " sun is in the eastern sky.";
case 170..190: return "\nThe " + GetCurrentSeason() + " sun is high overhead.";
case 191..259: return "\nThe " + GetCurrentSeason() + " sun is in the western sky.";
case 260..270: return "\nThe " + GetCurrentSeason() + " sun is low in the western sky.";
default:
if( GetCurrentTime() > Dawn && GetSOP() < 90 ){
return "\nThe eastern " + GetCurrentSeason() + " sky is touched by a rosy glow.";
}else if( GetCurrentTime() < Night && GetSOP() > 270 ){
return "\nDusk gives some light to the western " + GetCurrentSeason() + " sky.";
}else{
return "\nThe " + GetCurrentSeason() + " sky is dark.";
}
break;
}
break;}
case "moon": case "moons":{
//---- phase I: group the moons
i = sizeof( moons = keys( Moons ) );
if( !i ){ return 0; }
x = 0;
tmp = ""; counter = 0; counter2 = 0;
moongroup = allocate( i );
while( i-- ){
pos = GetMOP( moons[i] );
switch( pos ){
case  90..100: moongroup[i] = 1; break;
case 101..169: moongroup[i] = 2; break;
case 170..190: moongroup[i] = 3; break;
case 191..259: moongroup[i] = 4; break;
case 260..270: moongroup[i] = 5; break;
default: moongroup[i] = 0; break;
}
}
for( i = 0; i < 6; ++i ){
if( sizeof( moongroup & ({ i }) ) > 0 ){ ++counter2; }
}
//---- phase II: construct the list
n = sizeof( moons );
for( i = 1; i < 6; ++i ){
for( i2 = 0; i2 < n; i2++ ){
if( moongroup[i2] == i ){
if( counter == 0 && sizeof( moongroup & ({ i }) ) > 1 ){
counter = sizeof( moongroup & ({ i }) );
}
tmp += ( (class moon) Moons[moons[i2]] )->Name + ", the " +
( (class moon) Moons[moons[i2]] )->Id + ", ";
if( sizeof( moongroup & ({ i }) ) > 1 ){
--counter;
if( sizeof( moongroup & ({ i }) ) > 1 && counter == 1 ){ tmp += "and "; }
}
if( counter == 0 ){
if( sizeof( moongroup & ({ i }) ) > 1 ){ tmp += "are "; }else{ tmp += "is "; }
tmp += GetPhaseName( ( (class moon) Moons[moons[i2]] )->Name );
switch( i ){
case 1: tmp += " and low in the sky to the east"; break;
case 2: tmp += " and in the sky to the east"; break;
case 3: tmp += " and high overhead"; break;
case 4: tmp += " and in the sky to the west"; break;
case 5: tmp += " and low in the sky to the west"; break;
default: tmp += " and below the horizon"; break;
}
if( counter2 > 2 ){ tmp += "; "; }else{ tmp += "."; }
--counter2;
}
}
}
}
if( !n ){ return "The sky is empty of any " + arg + "."; }else{ return tmp; }
break;}
case "sky":{
if( GetTimeOfDay() == "night" ){
tmp = GetLong( "moon" );
if( !tmp ){
return "The sky is filled only with the glitter of stars.";
}else{
return tmp;
}
}else{
string sky;

tmp = GetLong( "sun" ) + "  " + GetLong( "moon" );
if( this_player() ){ env = environment( this_player() ); }
// section to check for flying objects
if( sky = env->GetSky() ){
env = find_object( sky );
if( env ){
obs = filter(
all_inventory( env ),
function( object ob ){
if( ob->GetInvis( this_player() ) ){ return 0; }
if( living( ob ) ){ return 1; }
return 0;
}
);
if( sizeof( obs ) ){
maxi = sizeof( obs );

sky = obs[i]->GetName();
if( maxi == 1 ){ sky += " is visible in the sky."; }
else{
for( i = 1; i < maxi; i++ ){
if( i == maxi - 1 ){
if( maxi == 2 ){ sky += " and "; }
else{ sky += ", and "; }
}else{
sky += ", ";
}
sky += obs[i]->GetName();
}
sky += " are visible in the sky.";
}
tmp = sky + "\n" + tmp;
}
}
}
return tmp;
}
break;}
default:{
// player trying to look at specific moon by name
if( Moons[arg] ){
if( MoonIsVis( arg ) ){
tmp = capitalize(arg) + ", " +
lower_case( ( (class moon) Moons[arg] )->Description)[0..<2]+
", is " + GetPhaseName( GetPhase( arg ) ) + " and ";
switch( GetMOP( arg ) ){
case  90..100: tmp += "is just above the eastern horizon."; break;
case 101..169: tmp += "hangs in the eastern sky."; break;
case 170..190: tmp += "is high overhead."; break;
case 191..259: tmp += "hangs in the western sky."; break;
case 260..270: tmp += "is just above the western horizon."; break;
default: tmp += "has encountered an error in its location."; break;
}
return tmp;
}else{
return capitalize( arg ) + " is not visible at this time.";
}
}
// player trying to look at specific moon by description
arr = map( mn = keys( Moons ), (: ( (class moon) Moons[$1])->Id :) );
if( ( i = member_array( arg, arr ) ) != -1 ){
if( MoonIsVis( mn[i] ) ){
tmp = capitalize( mn[i] ) + ", " +
lower_case( ( (class moon) Moons[mn[i]])->Description)[0..<2] +
", is " + GetPhaseName( GetPhase( mn[i] ) ) + " and ";
switch( GetMOP( mn[i] ) ){
case  90..100: tmp += "is just above the eastern horizon."; break;
case 101..169: tmp += "hangs in the eastern sky."; break;
case 170..190: tmp += "is high overhead."; break;
case 191..259: tmp += "hangs in the western sky."; break;
case 260..270: tmp += "is just above the western horizon."; break;
default: tmp += "has encountered an error in its location."; break;
}
return tmp;
}else{
return capitalize( mn[i] ) + " is not visible at this time.";
}
}else{ return 0; }
break;}
}
}

string array GetMoons(){
return map( keys( Moons ), (: ( ( class moon ) Moons[$1] )->Name :) );
}

int eventShow( object who, string args ){
string str;
if( !who || !sizeof( args ) ){ return 0; }
if( !str = GetLong( args ) ){ return 0; }
if( (string) environment( who )->GetClimate() == "indoors" ){
if( ( environment( who )->GetTerrainType() & T_INDOORSWINDOW ) ){
who->eventPrint(
"You cannot see the " + args + ", because you are not outside, " +
"but outside the window is " +
( GetSOP() > 90 && GetSOP() < 270 ? "light." : "dark." )
);
return 1;
}
who->eventPrint( "You cannot see the " + args + ", because you are not outside." );
return 1;
}
who->eventPrint( str );
environment( who )->eventPrint( (string) who->GetName() + " gazes at the sky.", who );
return 1;
}