nakedmudv3.3/
nakedmudv3.3/lib/
nakedmudv3.3/lib/logs/
nakedmudv3.3/lib/misc/
nakedmudv3.3/lib/players/
nakedmudv3.3/lib/txt/
nakedmudv3.3/lib/world/
nakedmudv3.3/lib/world/examples/
nakedmudv3.3/lib/world/examples/mproto/
nakedmudv3.3/lib/world/examples/oproto/
nakedmudv3.3/lib/world/examples/reset/
nakedmudv3.3/lib/world/examples/rproto/
nakedmudv3.3/lib/world/examples/trigger/
nakedmudv3.3/lib/world/limbo/
nakedmudv3.3/lib/world/limbo/room/
nakedmudv3.3/lib/world/limbo/rproto/
nakedmudv3.3/src/alias/
nakedmudv3.3/src/char_vars/
nakedmudv3.3/src/editor/
nakedmudv3.3/src/example_module/
nakedmudv3.3/src/help/
nakedmudv3.3/src/set_val/
nakedmudv3.3/src/socials/
nakedmudv3.3/src/time/
//*****************************************************************************
//
// time.c
//
// A small module for handling time of day in the MUD.
//
//*****************************************************************************

#include <Python.h>        // to add nightdesc
#include <structmember.h>

#include "../mud.h"
#include "../utils.h"
#include "../inform.h"
#include "../character.h"
#include "../room.h"
#include "../event.h"
#include "../storage.h"
#include "../auxiliary.h"
#include "../hooks.h"

#include "mudtime.h"



//*****************************************************************************
// mandatory modules
//*****************************************************************************
#include "../scripts/scripts.h"
#include "../scripts/pyroom.h"
#include "../scripts/pymud.h"



//*****************************************************************************
// optional modules
//*****************************************************************************
#ifdef MODULE_SET_VAL
#include "../set_val/set_val.h"
#endif



//*****************************************************************************
// local defines, variables, and structs
//*****************************************************************************
#define TIME_FILE   "../lib/misc/time"  // where do we keep time data?
#define TIME_UPDATE_DELAY   1 MUD_HOUR  // how long is an in-game hour?
#define HOURS_PER_DAY               24  // how many hours are in a day?
#define NUM_MONTHS                   4  // how many months are in a year?
#define DAYS_PER_WEEK                3  // how many days are in a week?
#define USE_AMPM                  TRUE  // do we use the am/pm system?

COMMAND(cmd_time);                      // a player command for seeing the time


struct month_data {
  char *name;             // what is the name of the month?
  int   num_days;         // how many days are in the month?
  int   morning_starts;   // what time does morning start at?
  int   afternoon_starts; // what time does the afternoon start at?
  int   evening_starts;   // what times does evening start at?
  int   night_starts;     // what time does the night start at?
};

struct day_data {
  char *name;
};

const struct month_data month_info[NUM_MONTHS] = {
  // month name                 days   morning   afternoon    evening   night
  { "the month of dawn",          30,        6,         12,        18,     22 },
  { "the month of light",         30,        4,         10,        19,     23 },
  { "the month of the moon",      30,        6,         12,        17,     21 },
  { "the month of twilight",      30,        5,         13,        16,     20 },
};

const struct day_data day_info[DAYS_PER_WEEK] = {
  { "the day of work" },
  { "the day of play" },
  { "the day of rest" },
};


int curr_hour         = 0; // what hour is it in the day?
int curr_day_of_week  = 0; // what day of the week is it?
int curr_day_of_month = 0; // what day is it in the month?
int curr_month        = 0; // what month is it in the year?
int curr_year         = 0; // what year is it?



//*****************************************************************************
//
// auxiliary data
//
// the time module gives rooms the ability to have different day and night
// descriptions. Below are the functions required for installing this.
//
//*****************************************************************************
typedef struct time_aux_data {
  BUFFER *night_desc;        // our description at night time
} TIME_AUX_DATA;

TIME_AUX_DATA *
newTimeAuxData() {
  TIME_AUX_DATA *data = malloc(sizeof(TIME_AUX_DATA));
  data->night_desc = newBuffer(1);
  return data;
}

void
deleteTimeAuxData(TIME_AUX_DATA *data) {
  if(data->night_desc) deleteBuffer(data->night_desc);
  free(data);
}

void
timeAuxDataCopyTo(TIME_AUX_DATA *from, TIME_AUX_DATA *to) {
  bufferCopyTo(from->night_desc, to->night_desc);
}

TIME_AUX_DATA *
timeAuxDataCopy(TIME_AUX_DATA *data) {
  TIME_AUX_DATA *newdata = newTimeAuxData();
  timeAuxDataCopyTo(data, newdata);
  return newdata;
}

STORAGE_SET *timeAuxDataStore(TIME_AUX_DATA *data) {
  STORAGE_SET *set = new_storage_set();
  store_string(set, "night_desc", bufferString(data->night_desc));
  return set;
}

TIME_AUX_DATA *timeAuxDataRead(STORAGE_SET *set) {
  TIME_AUX_DATA *data = newTimeAuxData();
  bufferCat(data->night_desc, read_string(set, "night_desc"));
  return data;
}

const char *roomGetNightDesc(ROOM_DATA *room) {
  TIME_AUX_DATA *data = roomGetAuxiliaryData(room, "time_aux_data");
  return bufferString(data->night_desc);
}

BUFFER *roomGetNightDescBuffer(ROOM_DATA *room) {
  TIME_AUX_DATA *data = roomGetAuxiliaryData(room, "time_aux_data");
  return data->night_desc;
}

void roomSetNightDesc(ROOM_DATA *room, const char *desc) {
  TIME_AUX_DATA *data = roomGetAuxiliaryData(room, "time_aux_data");
  bufferClear(data->night_desc);
  bufferCat(data->night_desc, (desc ? desc : ""));
}



//*****************************************************************************
// Python getters and setters
//*****************************************************************************
PyObject *PyRoom_getndesc(PyObject *self, void *closure) {
  ROOM_DATA *room = PyRoom_AsRoom(self);
  if(room != NULL)  return Py_BuildValue("s", roomGetNightDesc(room));
  else              return NULL;
}

int PyRoom_setndesc(PyObject *self, PyObject *value, void *closure) {
  if (value == NULL) {
    PyErr_Format(PyExc_TypeError, "Cannot delete room's night desc");
    return -1;
  }
  
  if (!PyString_Check(value)) {
    PyErr_Format(PyExc_TypeError, 
                    "Room night descs must be strings");
    return -1;
  }

  ROOM_DATA *room = PyRoom_AsRoom(self);
  if(room == NULL) {
    PyErr_Format(PyExc_TypeError,
		 "Tried to modify nonexistent room, %d", PyRoom_AsUid(self));
    return -1;                                                                
  }

  roomSetNightDesc(room, PyString_AsString(value));
  return 0;
}



//*****************************************************************************
// Python methods
//*****************************************************************************
PyObject *PyMud_GetHour(PyObject *self) {
  return Py_BuildValue("i", get_hour());
}

PyObject *PyMud_IsMorning(PyObject *self) {
  return Py_BuildValue("i", is_morning());
}

PyObject *PyMud_IsAfternoon(PyObject *self) {
  return Py_BuildValue("i", is_afternoon());
}

PyObject *PyMud_IsEvening(PyObject *self) {
  return Py_BuildValue("i", is_evening());
}

PyObject *PyMud_IsNight(PyObject *self) {
  return Py_BuildValue("i", is_night());
}



//*****************************************************************************
// time handling functions
//*****************************************************************************

//
// If it's in the night, swap out our desc for the room's night desc
void room_nightdesc_hook(const char *info) {
  ROOM_DATA   *room = NULL;
  CHAR_DATA *looker = NULL;
  hookParseInfo(info, &room, &looker);

  if((is_evening() || is_night()) && *roomGetNightDesc(room)) {
    // if it's the room desc and not an edesc, cat the night desc...
    if(!strcasecmp(bufferString(charGetLookBuffer(looker)),roomGetDesc(room))) {
      bufferClear(charGetLookBuffer(looker));
      bufferCat(charGetLookBuffer(looker), roomGetNightDesc(room));
    }
  }
}

//
// Handle the hourly update of our times
//
void handle_time_update(void *self, void *data, char *arg) {
  curr_hour++;

  if(curr_hour >= HOURS_PER_DAY) {
    curr_hour = 0;
    curr_day_of_week++;
    curr_day_of_month++;
  }

  if(curr_day_of_week >= DAYS_PER_WEEK)
    curr_day_of_week = 0;

  if(curr_day_of_month >= month_info[curr_month].num_days) {
    curr_day_of_month = 0;
    curr_month++;
  }

  if(curr_month >= NUM_MONTHS) {
    curr_month = 0;
    curr_year++;
  }


  // check to see if we've rolled over to a new time of day
  if(curr_hour == month_info[curr_month].morning_starts)
    send_outdoors("The morning sun slowly pokes its head up over the eastern horizon.\r\n");
  if(curr_hour == month_info[curr_month].afternoon_starts)
    send_outdoors("The sun hangs high overhead as afternoon approaches.\r\n");
  if(curr_hour == month_info[curr_month].evening_starts)
    send_outdoors("The sun slowly begins its descent as evening approaches.\r\n");
  if(curr_hour == month_info[curr_month].night_starts)
    send_outdoors("The sky goes dark as the sun passes over the western horizon.\r\n");

  // save our time data to file
  STORAGE_SET *set = new_storage_set();
  store_int(set, "hour",         curr_hour);
  store_int(set, "day_of_week",  curr_day_of_week);
  store_int(set, "day_of_month", curr_day_of_month);
  store_int(set, "month",        curr_month);
  store_int(set, "year",         curr_year);
  storage_write(set, TIME_FILE);
  storage_close(set);
}


void init_time() {
  STORAGE_SET *set  = storage_read(TIME_FILE);
  if(set != NULL) {
    curr_hour         = read_int(set, "hour");
    curr_day_of_week  = read_int(set, "day_of_week");
    curr_day_of_month = read_int(set, "day_of_month");
    curr_month        = read_int(set, "month");
    curr_year         = read_int(set, "year");
    storage_close(set);
  }
  else
    curr_hour = curr_day_of_week = curr_day_of_month = curr_month = curr_year = 0;

  // add a nightdesc get-setter to rooms
  PyRoom_addGetSetter("ndesc", PyRoom_getndesc, PyRoom_setndesc,
		      "the room's night desc");
  PyRoom_addGetSetter("night_desc", PyRoom_getndesc, PyRoom_setndesc,
		      "the room's night desc");

  // add our mud methods
  PyMud_addMethod("get_hour",     PyMud_GetHour,     METH_NOARGS, NULL);
  PyMud_addMethod("is_morning",   PyMud_IsMorning,   METH_NOARGS, NULL);
  PyMud_addMethod("is_afternoon", PyMud_IsAfternoon, METH_NOARGS, NULL);
  PyMud_addMethod("is_evening",   PyMud_IsEvening,   METH_NOARGS, NULL);
  PyMud_addMethod("is_night",     PyMud_IsNight,     METH_NOARGS, NULL);
  
  // add our set fields
#ifdef MODULE_SET_VAL
  add_set("ndesc",      SET_ROOM, SET_TYPE_STRING, roomSetNightDesc, NULL);
  add_set("night_desc", SET_ROOM, SET_TYPE_STRING, roomSetNightDesc, NULL);
#endif

  // add the time command
  add_cmd("time", NULL, cmd_time, POS_SITTING,  POS_FLYING,
	  "player", TRUE, FALSE);

  // add night descriptions for rooms
  auxiliariesInstall("time_aux_data",
		     newAuxiliaryFuncs(AUXILIARY_TYPE_ROOM,
				       newTimeAuxData, deleteTimeAuxData,
				       timeAuxDataCopyTo, timeAuxDataCopy,
				       timeAuxDataStore, timeAuxDataRead));

  // start our time updater
  start_update(NULL, TIME_UPDATE_DELAY, handle_time_update, NULL, NULL, NULL);
  hookAdd("preprocess_room_desc", room_nightdesc_hook);
}


const char *get_day() {
  return day_info[curr_day_of_week].name;
}


const char *get_month() {
  return month_info[curr_month].name;
}


int get_year() {
  return curr_year;
}


int get_hour() {
  return curr_hour;
}


bool is_morning() {
  return (curr_hour >= month_info[curr_month].morning_starts &&
	  curr_hour <  month_info[curr_month].afternoon_starts);
}


bool is_afternoon() {
  return (curr_hour >= month_info[curr_month].afternoon_starts &&
	  curr_hour <  month_info[curr_month].evening_starts);
}


bool is_evening() {
  return (curr_hour >= month_info[curr_month].evening_starts &&
	  curr_hour <  month_info[curr_month].night_starts);
}


bool is_night() {
  return (curr_hour >= month_info[curr_month].night_starts ||
	  curr_hour <  month_info[curr_month].morning_starts);
}


//
// is it am or pm?
//
bool is_am() {
  return (curr_hour < HOURS_PER_DAY/2);
}


//
// what time is it, am/pm - wise?
//
int ampm_hour() {
  int ampm_time = curr_hour - (is_am() ? 0 : HOURS_PER_DAY/2);
  if(ampm_time == 0) ampm_time = HOURS_PER_DAY/2;
  return ampm_time;
}


COMMAND(cmd_time) {
  send_to_char(ch,
	       "It is %d o'clock%s during the %s of %s,\r\n"
	       "which is the %d%s day of %s, year %d.\r\n",
	       (USE_AMPM ? ampm_hour() : curr_hour+1),
	       (USE_AMPM ? (is_am() ? " a.m" : " p.m") : ""),
	       (is_morning() ? "morning" :
		(is_afternoon() ? "afternoon" :
		 (is_evening() ? "evening" : "night"))),
	       day_info[curr_day_of_week].name,
	       curr_day_of_month+1, numth(curr_day_of_month+1),
	       month_info[curr_month].name, curr_year);
}