#pragma save_binary // Weather daemon // Originally coded by Megadeath@TMI-2 // Overhauled by Mobydick@TMI-2 // Fixed type checking for which_line Leto 94-11-10 #include <mudlib.h> #include <weather_d.h> inherit DAEMON ; // A list of all objects which get the weather change messages. All outdoor // rooms are placed on this list, but other objects such as monsters can // be placed on it (so you can code vampires and so on.) object *notifications ; // These variables store the current game time. The length of game days, // months, and years is all controlled by defines in weather_d.h. int current_day, current_month, current_year ; // This variable stores the data on the day phases. mapping *day_phases ; int num_phases ; int current_phase ; // And these on the weather states. mapping *weather_states ; int num_states ; int current_state ; // And these on the months. mapping *months ; int num_months ; // And _these_ on the moon phases :) mapping *moon_phases ; int num_moon_phases ; int moon_phase_days ; int current_moon_phase ; // This function reads in the data on the daytime phases. void read_day_phases() { int i, data, size ; string str ; string *datafile ; int which_line ; mapping new_phase ; // Which_line keeps track of where in the file format we are. which_line = 0 ; datafile = explode(read_file(DAY_PHASE_FILE),"\n") ; size = sizeof(datafile) ; day_phases = allocate(NUM_DAY_PHASES) ; num_phases = -1 ; // sorry.... this is silly but easiest. // Loop through each line of the file and try to parse it appropriately. for (i=0;i<size;i++) { // Make sure that this line is a proper data line: if not, skip it. if (sscanf(datafile[i],"%d %s",data,str)==2) { if (which_line) { // We're looking at the second of the two lines in this case. day_phases[num_phases]["change_msg"] = str ; day_phases[num_phases]["daylight"] = data ; } else { // In this case, the first of the two lines. num_phases = num_phases + 1 ; day_phases[num_phases] = allocate_mapping(4) ; day_phases[num_phases]["length"] = data ; day_phases[num_phases]["look_msg"] = str ; } which_line = !which_line ; } } if (which_line) { shout ("Incomplete last day phase.\n") ; } num_phases = NUM_DAY_PHASES ; return ; } // This function reads in the weather data. void read_weather() { int i, j, data1, data2, size ; string *changes ; string *datafile ; int which_line ; // Which line keeps track of where we are in the file format. which_line = 0 ; datafile = explode(read_file(WEATHER_FILE),"\n") ; size = sizeof(datafile) ; weather_states = allocate(NUM_WEATHER) ; changes = allocate(NUM_WEATHER) ; num_states = -1 ; // hack :( // Loop through each line of the file, and parse it. for (i=0;i<size;i++) { switch(which_line) { // How we parse it depends on what line we are expecting. case 0 : { if (sscanf(datafile[i],"%d %d",data1,data2)==2) { num_states = num_states+1 ; weather_states[num_states]=allocate_mapping(6) ; weather_states[num_states]["length"] = data1 ; weather_states[num_states]["inclement"] = data2 ; which_line = 1 ; } break ; } case 1 : { changes = explode(datafile[i]," ") ; weather_states[num_states]["changes"] = allocate(NUM_WEATHER) ; for (j=0;j<sizeof(changes);j++) { sscanf(changes[j],"%d",weather_states[num_states] ["changes"][j]) ; } which_line=2 ; break ; } case 2 : { weather_states[num_states]["worse_msg"] = datafile[i] ; which_line=3 ; break ; } case 3 : { weather_states[num_states]["better_msg"] = datafile[i] ; which_line=4 ; break ; } case 4 : { weather_states[num_states]["look_msg"] = datafile[i] ; which_line=0 ; break ; } } } num_states = NUM_WEATHER ; return ; } // This function reads in the months and their names. void read_months() { int i, ding ; string str ; string *datafile ; datafile = explode(read_file(MONTH_FILE),"\n") ; months = allocate(NUM_MONTHS) ; num_months = -1 ; // same hack as always. for (i=0;i<sizeof(datafile);i++) { if (sscanf(datafile[i],"%s %d",str,ding)==2) { num_months = num_months + 1 ; months[num_months]=allocate_mapping(2) ; months[num_months]["length"] = ding ; months[num_months]["name"] = str ; } } num_months = NUM_MONTHS ; return ; } // This function reads in the data on the moon phases. void read_moon() { int i, ding ; string str ; string *datafile ; datafile = explode(read_file(MOON_FILE),"\n") ; moon_phases = allocate(NUM_MOON_PHASES) ; num_moon_phases = -1 ; // same hack as always. for (i=0;i<sizeof(datafile);i++) { if (sscanf(datafile[i],"%d %s",ding,str)==2) { num_moon_phases = num_moon_phases + 1 ; moon_phases[num_moon_phases]=allocate_mapping(2) ; moon_phases[num_moon_phases]["length"] = ding ; moon_phases[num_moon_phases]["look_msg"] = str ; } } num_moon_phases = NUM_MOON_PHASES ; } // This function is called at the end of each day to advance the calendar // and the moon phase. You can do other things as well. void do_day_end() { current_day=current_day+1 ; if (current_day>months[current_month]["length"]) { current_day=1 ; current_month = current_month+1 ; if (current_month==num_months) { current_month=0 ; current_year = current_year + 1 ; } } moon_phase_days = moon_phase_days + 1 ; if (moon_phase_days==moon_phases[current_moon_phase]["length"]) { moon_phase_days=0 ; current_moon_phase = current_moon_phase + 1 ; if (current_moon_phase==num_moon_phases) { current_moon_phase = 0 ; } } } // This function changes us from one state of day to the next. It call_outs // to itself recursively so there's always one version in the call_out // queue. void change_phase() { notifications -= ({ 0 }); message("weather",day_phases[current_phase]["change_msg"]+"\n", notifications) ; current_phase = current_phase + 1 ; if (current_phase==num_phases) { current_phase=0 ; do_day_end() ; } call_out("change_phase",day_phases[current_phase]["length"]) ; } // This function changes the weather. Based on the current weather // state, it picks a new weather state and call_outs itself, so that there // is always one version of the function in the call_out queue. If the new // state is the same as the old one, then nothing else is done, otherwise // we notify each object of the new state. void change_weather() { int i, j, new_state ; notifications -= ({ 0 }); j = random(100) ; for (i=0;i<sizeof(weather_states[current_state]["changes"]);i++) { if (j<weather_states[current_state]["changes"][i]) { new_state = i ; j=200 ; // This way we don't select again. } else { j = j - weather_states[current_state]["changes"][i] ; } } call_out("change_weather",weather_states[new_state]["length"]) ; if (new_state==current_state) return ; i=sizeof(notifications); while (i--) { if (new_state<current_state) { message("weather",weather_states[new_state]["better_msg"]+"\n", notifications[i]) ; } else { message("weather",weather_states[new_state]["worse_msg"]+"\n", notifications[i]) ; } } current_state = new_state ; } // This function is called at create time. It gets the current time, // and it sets the game time appropriately. We could just calculate the // game times as needed, but that would be slower. Best to calculate it from // real time once, then update it occasionally. void init_game_time() { int current_time ; current_time = time() - START_GAME_TIME ; current_year = START_YEAR ; // First, figure out what year it is. while (current_time>YEAR_LENGTH) { current_time = current_time - YEAR_LENGTH ; current_year = current_year + 1 ; } // Next, what month. current_month = START_MONTH ; while (current_time>months[current_month]["length"]*DAY_LENGTH) { current_time = current_time - months[current_month]["length"] * DAY_LENGTH ; current_month = current_month + 1 ; if (current_month==num_months) { current_month=0 ; current_year = current_year + 1 ; } } // Now, the current day is just the remaining time mod the day length, // plus one since there is no day 0. current_day = current_time/DAY_LENGTH + 1 ; // Now, we have to figure out what the current day phase is, and start // the day phase call_outs with the right time remaining. current_time = current_time - (current_day-1)*DAY_LENGTH ; current_phase=0 ; while (current_time>day_phases[current_phase]["length"]) { current_time = current_time - day_phases[current_phase]["length"] ; current_phase = current_phase+1 ; } call_out("change_phase",day_phases[current_phase]["length"] - current_time) ; // Now, we have to figure out the right phase of the moon and the number // of days into that phase that we are. current_time = time() - START_GAME_TIME ; current_time = current_time % (MOON_PERIOD*DAY_LENGTH) ; moon_phase_days = current_time/DAY_LENGTH ; current_moon_phase = 0 ; while (moon_phase_days>moon_phases[current_moon_phase]["length"]) { moon_phase_days = moon_phase_days - moon_phases[current_moon_phase]["length"] ; current_moon_phase = current_moon_phase + 1 ; } } void create() { seteuid(getuid()) ; // Read in the day phases file. read_day_phases() ; // Read in the weather data file read_weather() ; // Read in the month data. read_months() ; // Read in the moon data. read_moon() ; // Initialize current date. init_game_time() ; notifications = ({ }) ; current_state = 0 ; change_weather() ; } // This function checks if there is outside light or not. The rule is, // in daytime there is always light. At nighttime, there is light if // the sky is clear, otherwise there is not light. int query_ambient_light() { if ( day_phases[current_phase]["daylight"]) { return 1 ; } else { return !weather_states[current_state]["inclement"] ; } } // Returns the message associated with this time of day. string query_current_day_phase() { return day_phases[current_phase]["look_msg"]+"\n" ; } // Returns the message associated with this weather state. // Usually you want to use the query_weather_msg instead, which makes // sure you can see the sun and the like. string query_current_weather() { return weather_states[current_state]["look_msg"]+"\n" ; } // This function returns a string describing the current moon phase. string query_current_moon_phase() { return moon_phases[current_moon_phase]["look_msg"]+"\n" ; } // This function returns a string describing the current weather. If the // weather is not inclement, it tells you where the sun/moon is, otherwise // it doesn't, and it describes the current weather also. string query_weather_msg() { string str ; str = "" ; if (!weather_states[current_state]["inclement"]) { str += day_phases[current_phase]["look_msg"] +"\n" ; } str += weather_states[current_state]["look_msg"] +"\n" ; if(!day_phases[current_phase]["daylight"] && !weather_states[current_state]["inclement"]) { str += moon_phases[current_moon_phase]["look_msg"]+"\n" ; } return str ; } string query_game_time() { int i,j,k ; i = time() - START_GAME_TIME ; i = i - (current_year-START_YEAR)*YEAR_LENGTH ; j = START_MONTH ; while (i>months[j]["length"]*DAY_LENGTH) { i = i - months[j]["length"]*DAY_LENGTH ; j = j + 1 ; if (j==num_months) j=0 ; } i = i - (current_day-1)*DAY_LENGTH ; i = i * 86400 / DAY_LENGTH ; j = i / 3600 ; k = i - j*3600 ; k = k / 60 ; if (k<10) return j+":0"+k+", "+months[current_month]["name"]+ " "+current_day+", "+current_year ; return j+":"+k+", "+months[current_month]["name"]+ " "+current_day+", "+current_year ; } // This function adds the object passed to the list of objects that // will receive time and weather notices. Call this in any object that // wants them. Outside rooms automatically add themselves to this list. // Other objects like vampires can recieve_message() and take any actions // they might want to. void request_weather_notices (object ob) { if (member_array(ob,notifications)>-1) return ; notifications += ({ ob }) ; } // This function requests that an object be taken off the list // of notified objects. void cease_weather_notices (object ob) { notifications -= ({ ob }) ; } // Diagnostics. void write_obs() { write(dump_variable(notifications)) ; }