/************************************************************************ Realms of Aurealis James Rhone aka Vall of RoA weather.c Weather and time functionality is contained in this file. Though based on CircleMUD2.2/Diku weather and time, a signifigant amount of changes have taken place... ******** Heavily modified and expanded ******** *** BE AWARE OF ALL RIGHTS AND RESERVATIONS *** ******** Heavily modified and expanded ******** All rights reserved henceforth. Please note that no guarantees are associated with any code from Realms of Aurealis. All code which has been released to the general public has been done so with an 'as is' pretense. RoA is based on both Diku and CircleMUD and ALL licenses from both *MUST* be adhered to as well as the RoA license. *** Read, Learn, Understand, Improve *** *************************************************************************/ #include "conf.h" #include "sysdep.h" #include "structures.h" #include "utils.h" #include "comm.h" #include "handler.h" #include "interpreter.h" #include "acmd.h" #include "db.h" #include "lists.h" #include "fight.h" #include "shaman.h" #include "global.h" #include "weather.h" #include "plshop.h" // as a year passes, update some stuff void another_year(void) { mudlog("Another year has passed.", BUG, LEV_IMM, TRUE); time_info.month = 0; time_info.year++; sprintf(buf, "%%B%%6A new year has dawned! (%d)%%0\n\r",time_info.year); send_to_outdoor(buf); // update the plshops around the land yearly_plshop_update(); } // as a month passes, update some stuff void another_month(void) { extern const char *month_names[16]; mudlog("Another month has passed.", BUG, LEV_IMM, TRUE); time_info.day = 0; time_info.month++; // update the plshops around the land monthly_plshop_update(); /* year passed? -roa*/ if (time_info.month > 15) /* now 16 months in a year -roa */ another_year(); else { /* send message stating a new month has begun */ send_to_outdoor("As time marches steadily onward, a new month has arrived.\n\r"); sprintf(buf, "It is known as the %%6%s%%0.\n\r", month_names[(int)time_info.month]); send_to_outdoor(buf); } global_weather.season = time_info.month / 4; } // and, again, each day, things must be done... void another_day(void) { extern void check_char_quests(void); mudlog("Another day has passed.", BUG, LEV_IMM, TRUE); time_info.hours -= 24; time_info.day++; // subtract time from character quests in quest.c check_char_quests(); // update the plshops around the land daily_plshop_update(); /* has a month passed? -roa 35 (0 - 34) days in a month btw */ if (time_info.day > 34) another_month(); } void check_hourly_activity(void) { dsdata *d; chdata *ch; switch (time_info.hours) { case 5 : global_weather.sunlight = SUN_RISE; send_sunrise(); break; case 6 : global_weather.sunlight = SUN_LIGHT; send_daytime(); sprintf(buf, "You feel refreshed.\n\r"); for (d = descriptor_list; d; d = d->next) if (D_CHECK(d) && IS_PC(d->character)) { ch = d->character; // remove the bellow flag 4/6/98 -jtrhone REMOVE_BIT(CHAR_FLAGS(ch), CH_BELLOW); if (IS_SHAMAN(ch) && !IS_IMMORTAL(ch)) { act(buf, FALSE, ch, 0, 0, TO_CHAR); RITES(ch) += 10; if (RITES(ch) > MIN((35+GET_WIS(ch)-13), (GET_LEVEL(ch)))) RITES(ch) = MIN((35+GET_WIS(ch)-13), (GET_LEVEL(ch))); // no, let rites go negative now... 2/12/98 -jtrhone // if (RITES(ch) < 0) RITES(ch) = 0; } else if (!IS_IMMORTAL(ch) && IS_DROW(ch)) send_to_char("You feel slightly weaker.\n\r",ch); } break; case 21 : global_weather.sunlight = SUN_SET; send_sunset(); break; case 22 : global_weather.sunlight = SUN_DARK; send_nighttime(); break; default : break; } } // the driving weather/time function... called externally // every MUD hour, do some processing... void another_hour(void) { extern void open_close_shops(void); extern void update_client_times(void); /* another hour has passed -roa */ time_info.hours++; /* in mobact.c, update shopkeeps based on their hours */ open_close_shops(); check_hourly_activity(); /* if a day has passed */ if (time_info.hours > 23) another_day(); // defined below... hourly_weather(); // send times to every client on the hour 3/19/98 -jtrhone update_client_times(); } ///////////////////////////////////////////////////// // code relating more to weather below... -jtrhone // ///////////////////////////////////////////////////// // call on bootup, after time setup void init_weather(void) { switch (time_info.hours) { case 0 : case 1 : case 2 : case 3 : case 4 : global_weather.sunlight = SUN_DARK; break; case 5 : case 6 : global_weather.sunlight = SUN_RISE; break; case 7 : case 8 : case 9 : case 10 : case 11 : case 12 : case 13 : case 14 : case 15 : case 16 : case 17 : case 18 : case 19 : case 20 : global_weather.sunlight = SUN_LIGHT; break; case 21 : case 22 : global_weather.sunlight = SUN_SET; break; case 23 : default : global_weather.sunlight = SUN_DARK; break; } global_weather.season = time_info.month / 4; } void send_sunrise(void) { int s = global_weather.season; int zone; for (zone = 0; zone < NUM_ZONES; zone++) if (REAL_ZONE(zone)) { if (zone_table[zone].seasons[s].sunrise) send_to_zone_outside(zone_table[zone].seasons[s].sunrise, zone); else send_to_zone_outside("The %3sun%0 slowly begins to rise in the east.",zone); } } void send_daytime(void) { int s = global_weather.season; int zone; for (zone = 0; zone < NUM_ZONES; zone++) if (REAL_ZONE(zone)) { if (zone_table[zone].seasons[s].daytime) send_to_zone_outside(zone_table[zone].seasons[s].daytime, zone); else send_to_zone_outside("The day has begun.", zone); } } void send_sunset(void) { int s = global_weather.season; int zone; for (zone = 0; zone < NUM_ZONES; zone++) if (REAL_ZONE(zone)) { if (zone_table[zone].seasons[s].sunset) send_to_zone_outside(zone_table[zone].seasons[s].sunset, zone); else send_to_zone_outside("The %3sun%0 slowly disappears in the west.", zone); } } void send_nighttime(void) { int s = global_weather.season; int zone; for (zone = 0; zone < NUM_ZONES; zone++) if (REAL_ZONE(zone)) { if (zone_table[zone].seasons[s].nighttime) send_to_zone_outside(zone_table[zone].seasons[s].nighttime, zone); else send_to_zone_outside("The %4night%0 has begun.", zone); } } void send_zone_temp_updates(int zone) { chdata *ch; int diff, prev, curr; BOOL increase; prev = zone_table[zone].previous_gtemp; curr = ZONE_TEMP(zone); diff = curr - prev; /* if diff < 0 then the temp has gone down */ increase = (diff >= 0); diff = abs(diff); if (!increase) { if (diff >= 30) strcpy(buf2, "%B%4much colder%0"); else if (diff >= 20) strcpy(buf2, "%4colder%0"); else if (diff >= 10) strcpy(buf2, "%4cooler%0"); else if (diff >= 2) strcpy(buf2, "%4slightly cooler%0"); } else { if (diff >= 30) strcpy(buf2, "much %B%1hotter%0"); else if (diff >= 20) strcpy(buf2, "%B%1hotter%0"); else if (diff >= 10) strcpy(buf2, "%B%1warmer%0"); else if (diff >= 2) strcpy(buf2, "%B%1slightly warmer%0"); } if (diff <= 1) return; sprintf(buf, "The temperature has gotten %s in the past hour.",buf2); send_to_zone_outside(buf, zone); sprintf(buf2, "%%6Current temperature%%0: %d degrees.",curr); for (ch = character_list; ch; ch=ch->next) if (!INVALID_ROOM(ch->in_room) && OUTSIDE(ch) && IS_IMMORTAL(ch) && world[ch->in_room].zone == zone) act(buf2, FALSE, ch, 0, 0, TO_CHAR); } /* returns proper precip type */ int get_precip_type(int zone) { int temp; temp = ZONE_TEMP(zone); if (temp >= 36) return (RAINING); else if (temp >= 32) return (SLEETING); else return (SNOWING); } void stop_precip(int zone) { extern char *precip_names_ing[]; extern char *precip_names[]; int prev, curr; prev = zone_table[zone].previous_status = zone_table[zone].current_status; curr = zone_table[zone].current_status = number(0, 2); switch (number(0, 4)) { case 0: sprintf(buf, "The sky slowly brightens as it stops %s.\n\r", precip_names_ing[prev]); break; case 1: sprintf(buf, "The clouds slowly drift away as it stops %s.\n\r", precip_names_ing[prev]); break; case 2: sprintf(buf, "The %%6sky%%0 stops dropping the %s.\n\r", precip_names[prev]); break; case 3: sprintf(buf, "All around you, the %s stops falling.\n\r", precip_names[prev]); break; default: sprintf(buf, "The %s comes to an end.\n\r", precip_names[prev]); break; } sprintf(buf+strlen(buf), "The sky is now %%B%s%%0.",precip_names[curr]); send_to_zone_outside(buf, zone); } void begin_precip(int zone) { int temp; extern char *precip_names_ing[]; extern char *precip_names[]; temp = ZONE_TEMP(zone); if (temp >= 36) zone_table[zone].current_status = RAINING; else if (temp >= 32) zone_table[zone].current_status = SLEETING; else zone_table[zone].current_status = SNOWING; switch (number(0, 4)) { case 0: sprintf(buf, "The area %%4darkens%%0 slightly as it starts %s.", precip_names_ing[zone_table[zone].current_status]); break; case 1: sprintf(buf, "A breeze accompanies the %s as it begins to fall.", precip_names[zone_table[zone].current_status]); break; case 2: sprintf(buf, "The %%6sky%%0 begins to drop %s.", precip_names[zone_table[zone].current_status]); break; case 3: sprintf(buf, "All around you, %s begins to fall.", precip_names[zone_table[zone].current_status]); break; default: sprintf(buf, "Some %s starts to fall.", precip_names[zone_table[zone].current_status]); break; } send_to_zone_outside(buf, zone); } void send_precip_arrival(int zone) { switch (number(0, 3)) { case 0: sprintf(buf, "Dark clouds begin to move in from the west."); break; case 1: sprintf(buf, "You notice dark weather approaching from the west."); break; case 2: sprintf(buf, "The wind begins to pick up slightly."); break; default: sprintf(buf, "Clouds begin to rush in from the west."); break; } send_to_zone_outside(buf, zone); } void send_precip_departure(int zone) { switch (number(0, 3)) { case 0: sprintf(buf, "Clear skies approach from the west."); break; case 1: sprintf(buf, "Dark clouds move slowly away eastwards."); break; case 2: sprintf(buf, "The air around you becomes very still."); break; default: sprintf(buf, "Clouds, hanging low to the ground, move away east."); break; } send_to_zone_outside(buf, zone); } void send_lightning_mesg(int room) { if (WEATHER_ROOM(room)) { if (DARK_OUTSIDE) { switch (number(1,5)) { case 1: send_to_room_not_busy("%B%3Magnificent lightning lights up the sky%0.",room); break; case 2: send_to_room_not_busy("The sky %B%3glows%0 with streaks of lightning as thunder crashes down.",room); break; case 3: send_to_room_not_busy("Your vision blurs momentarily as %B%3lightning%0 fills the sky.",room); break; case 4: send_to_room_not_busy("Streaks of %B%3brilliant lightning%0 stream through the night sky.",room); break; default: send_to_room_not_busy("A %B%3sharp flash of lightning%0 leaves imprints on your vision.",room); break; } } else // some light, day or dawn { switch (number(1,5)) { case 1: send_to_room_not_busy("Thunder crashes down in the distance.",room); break; case 2: send_to_room_not_busy("The area is shaken by distant thunder.",room); break; case 3: send_to_room_not_busy("A barely visible flash of lightning streaks across the sky.",room); break; case 4: send_to_room_not_busy("The area is jolted by rumbling thunder in the distance.",room); break; default: send_to_room_not_busy("The area is jolted by rumbling thunder in the distance.",room); break; } } } else // inside room perhaps, but no weather regardless { switch (number(1, 5)) { case 1: send_to_room_not_busy("The area around you shakes violently as thunder echos in the distance.",room); break; case 2: send_to_room_not_busy("Thunder shakes everything around you.",room); break; case 3: send_to_room_not_busy("The sound of thunder reverberates through the area.",room); break; case 4: send_to_room_not_busy("In the distance, you hear lightning crash down.",room); break; default: send_to_room_not_busy("The area is jolted by rumbling thunder in the distance.",room); break; } } } void do_zone_blizzard(int zone) { return; } void do_zone_storm(int zone) { int rroom = 0, room = 0; chdata *ch, *next_ch; int tarroom; BOOL will_spread; tarroom = number(zone * 100, zone * 100 + 99); rroom = real_room(tarroom); for (room = 0; room < top_of_world; room++) if (world[room].zone == zone && room != rroom) send_lightning_mesg(room); if (INVALID_ROOM(rroom) || !WEATHER_ROOM(rroom)) return; sprintf(buf, "SYSUPD: Lightning strike, room #%d.",tarroom); mudlog(buf, BUG, LEV_IMM, FALSE); send_to_room_not_busy("%B%1LIGHTNING crashes down with a thunderous boom!%0", rroom); will_spread = (world[rroom].terrain_type == TERRAIN_WATER_SWIM || world[rroom].terrain_type == TERRAIN_WATER_NOSWIM || world[rroom].terrain_type == TERRAIN_UWATER); for (ch = world[rroom].people; ch; ch = next_ch) { next_ch = ch->next_in_room; if (!number(0, 99) && !IS_IMMORTAL(ch)) { sprintf(buf, "SYSUPD: %s struck by lightning, room %d.",GET_NAME(ch), tarroom); mudlog(buf, BUG, LEV_IMM, TRUE); act("%B%1AAAHHHHH!! The lightning strikes you!!%%0",FALSE, ch, 0, 0, TO_CHAR); act("%B%1Lightning strikes $n!!!%0",FALSE, ch, 0, 0, TO_ROOM); GET_HIT(ch) -= number(100, 30000); update_pos(ch); if (GET_POS(ch) == POS_DEAD) die(ch, FALSE); if (!will_spread) break; } } } void calc_accums(int zone) { int type; /* first, add/subtract to accums for last hour's precip */ if (IS_PRECIPPING(zone)) { /* add to accums */ type = get_precip_type(zone); /* returns proper precip type */ ZONE_ACCUM_TYPE(zone) = type; /* accums based on inches of rain/snow */ switch(type) { case RAINING: case SLEETING: ZONE_ACCUM(zone) += number(0, 2); break; case HAILING: ZONE_ACCUM(zone) += number(0, 6); break; case SNOWING: ZONE_ACCUM(zone) += number(0, 12); break; }; } else /* its clear and not precipping remove some accum */ { if (ZONE_TEMP(zone) >= 60) { switch(ZONE_ACCUM_TYPE(zone)) { case SLEETING: case RAINING: ZONE_ACCUM(zone) -= number(2, 5); ZONE_ACCUM(zone) = MAX(0, ZONE_ACCUM(zone)); break; case HAILING: case SNOWING: ZONE_ACCUM(zone) -= number(8, 15); ZONE_ACCUM(zone) = MAX(0, ZONE_ACCUM(zone)); break; }; } else if (ZONE_TEMP(zone) >= 45) { switch(ZONE_ACCUM_TYPE(zone)) { case SLEETING: case RAINING: ZONE_ACCUM(zone) -= number(1, 2); ZONE_ACCUM(zone) = MAX(0, ZONE_ACCUM(zone)); break; case HAILING: case SNOWING: ZONE_ACCUM(zone) -= number(3, 6); ZONE_ACCUM(zone) = MAX(0, ZONE_ACCUM(zone)); break; }; } else if (ZONE_TEMP(zone) >= 32) { switch(ZONE_ACCUM_TYPE(zone)) { case SLEETING: case RAINING: ZONE_ACCUM(zone) -= number(0, 1); ZONE_ACCUM(zone) = MAX(0, ZONE_ACCUM(zone)); break; case HAILING: case SNOWING: ZONE_ACCUM(zone) -= number(1, 4); ZONE_ACCUM(zone) = MAX(0, ZONE_ACCUM(zone)); break; }; } } /* else we dont lose any precip if less than freezing */ } // here are the main changes in weather, now OLCable, all be it based // more on random numbers than actual barometric pressure... // it is no longer MUD-WIDE, but each zone now has its own weather // structure with average temperatures and chances for precip etc... // jtrhone -roa void hourly_weather(void) { int season, zone, diff, target_temp; int perc, temp_change = 0; BOOL daytime; struct season_data *zseas = NULL; season = global_weather.season; daytime = (time_info.hours >= 8 && time_info.hours <= 20); /*8am-8pm*/ for (zone = 0; zone < NUM_ZONES; zone++) { if (!REAL_ZONE(zone) || ZONE_IDLE(zone) || ZONE_FREED(zone)) continue; zseas = &zone_table[zone].seasons[season]; if (zseas->avg_day_temp <= -999) /* this is the IGNORE trigger */ continue; /* if daytime, progress towards avg daytime temp for this season */ if (daytime) { if (number(0, 1)) target_temp = zseas->avg_day_temp - number(0, zseas->avg_day_temp_var); else target_temp = zseas->avg_day_temp + number(0, zseas->avg_day_temp_var); } else if (!daytime) { if (number(0, 1)) target_temp = zseas->avg_night_temp - number(0,zseas->avg_night_temp_var); else target_temp = zseas->avg_night_temp + number(0,zseas->avg_night_temp_var); } diff = target_temp - ZONE_TEMP(zone); zone_table[zone].previous_gtemp = ZONE_TEMP(zone); temp_change = (diff < 0) ? (0 - number(0, (abs(diff)/2))) : number(0, (diff/2)); ZONE_TEMP(zone) += temp_change; temp_change = abs(temp_change); /* tell everybody in the zone about their temp changes */ send_zone_temp_updates(zone); calc_accums(zone); if (IS_PRECIPPING(zone)) /* calc perc it will stop */ { perc = 100 - zseas->precip_percentage; if (perc > number(1, 100)) /* stop raining */ stop_precip(zone); } else /* calc percentage it will begin precipping */ { // this percentage is based on a daily percentage, not hourly // at hour 0, we will set the hour_to_rain based on // this percentage, this is only calculated on bootup and // at hour 0 if (!time_info.hours) // time to determine if it will rain { perc = zseas->precip_percentage; if (perc > number(1, 100)) { zone_table[zone].hour_to_rain = number (0,23); zone_table[zone].has_rained = FALSE; } else { zone_table[zone].hour_to_rain = -1; zone_table[zone].has_rained = FALSE; } } if (!zone_table[zone].has_rained) { if (time_info.hours == zone_table[zone].hour_to_rain) { begin_precip(zone); zone_table[zone].has_rained = TRUE; } else if (time_info.hours == zone_table[zone].hour_to_rain - 1) send_precip_arrival(zone); else if (time_info.hours == zone_table[zone].hour_to_rain + 1) send_precip_departure(zone); } } REMOVE_BIT(ZONE_FLAGS(zone), Z_TSTORM | Z_BLIZZARD); if (IS_PRECIPPING(zone)) /* if still precip, check for storms */ { if (temp_change >= 3) { perc = temp_change * zseas->atmosphere_type; if (perc > number(1, 50)) { if (ZONE_TEMP(zone) > 32) { SET_BIT(ZONE_FLAGS(zone), Z_TSTORM); // storm for next hour do_zone_storm(zone); } else { SET_BIT(ZONE_FLAGS(zone), Z_BLIZZARD); do_zone_blizzard(zone); } } } } } /* end for each zone */ }