Keran's MUSH/MUX Weather and Time Code Package Version 4.0 beta TinyMUSH 2.2 Code and Installation Instructions This code and accompanying materials are copyright (C) 1996, 1997, 1998, 1999 by Keran (keranset@mail1.nai.net). You can do anything with this code except sell it or claim credit for the parts I wrote. Use at your own risk, and all that. Thanks to My Sandbox for the port site. This code will run on TinyMUSH 2.2.2, and in all probability, later versions. (It may run on earlier releases as is, but I haven't tried it.) TinyMUSH 3.0 is not released, at the time this port is prepared. This code is expected to run on it. It seems likely that for original TinyMUSH 3.0 installations, it will be better to install the MUX version of this code than this port to TinyMUSH 2.2. The MUX version is the native version, is slightly more efficient and less cumbersome in spots, allows royalty to use some of the admin commands, and allows the Storm Maker to use zones. The MUX version will probably become the native TinyMUSH 3.0 version. Features: Time functions for determining the year, month, season, time of day, tide, and moon phase; A weathermaker that determines a different weather type every day; Day and night length that vary by season. The length of the longest day can be set by hours or by latitude; A weather description bank with descriptions that vary by time of day and season; A collection of outdoor parent rooms that make it easy to write descriptions that vary by time of day, season, weather, and the visibility of the moon, in different styles; Indoor parent rooms for writing descriptions that vary with lighting conditions and the visual capability of the viewer; A parent room hierarchy that means you can write your own parent rooms and easily have them recognized as the correct type of room. Configurable time compression ratios, in two different modes. You can accelerate all time with clock compression, or skip days with calendar compression; Simple adjustable weather modelling; An optional quasi-Gregorian calendar in addition to the native calendar, and an option for taking the date from the system clock in 1:1 time; Clock code that can send out messages to specified receivers at given times, such as sunrise, moonset, other time of day transitions, tide changes, at specific hours, every hour, every half hour, or every quarter hour. An auxiliary bank of descriptions varying by season, time of day, and weather, geared to surroundings with a lot of leafy trees, to illustrate how to make auxiliary desc banks for different environments; Regional weather, and a sample slave weather station. A fairly realistic moon; Diurnal or semi-diurnal tides synchronized with the moon; A Storm Maker that can be used to do global, area, and room type emits to allow the production of storms, earthquakes, blackouts, etc. A test room for ensuring that the whole thing works. The code is intended to be readable and adjustable by a competent coder, allowing it to be set up in numerous non-vanilla ways, which are discussed at some length in the configuration section of the +help. Changes between 3.0 and 4.0: -- The Time Functions object was too big in 3.0, and it would have been staggering with the 4.0 moon on it. The moon and tide functions now have an object all to themselves. Miscellaneous functions and weather desc functions now also reside on a separate object. -- The Emits Bank now sends its sunrise, sunset, time of day, etc., messages to rooms on which &hear-weather-emits=1, as opposed to &hear-global-emits. It will also send tide emits to rooms on which &hear-tide-emits=1. -- There are new times at which the Clock can trigger events. Meridian-transit is when the moon reaches its zenith. It can also trigger events every hour without your needing to specify the hours, every half-hour, or every quarter-hour. -- There's a new command on the Wizard Weather and Time Commands object to allow you to compute the length of the longest day by giving a latitude. -- The moon's behavior is now astronomically sane. The tides are synchronized with the moon. -- There's a Storm Maker that can be used to changed the day's weather and can broadcast effects messages to selected groups of rooms, making it possible to generate local storms, earthquakes, etc. -- There is now a system clock calendar mode. If you're going to run in 1:1 and you want to run off the system clock and get a 365-day year complete with dates, and stay in synchronization with the real year, you can. -- There is a hierarchy of parent rooms, including indoor rooms with lighting variations, and several more outdoor parent rooms. This works in conjunction with the Storm Maker; you can add your own parent rooms to it. -- The +help has been reorganized drastically. It may not be any clearer, but it's at least different. There are now three sections to the +help, general, admin commands, and configuration. I have, I hope, located the information builders need once the code has been installed in general +help instead of burying it in the config section. -- Bug fixes will be noted in the changes.txt file in the same ftp directory I distribute the code from. For this installation, you need to be a wizard. There are three global functions which are best loaded on #1; God needs to set this up. However, if necessary, you may also load globals on any wiz-inherit item whose dbref is lower than the dbref of anything that needs to call weather and time code. You need a configuration change to the server. Function_invocation_limit should be set to approximately 12,500. No, that is not a typo. And, no, it's highly unlikely to bring your server to its knees. CPUs improve every year, and most games can easily handle this code; it's possible that on a large and very heavily loaded server that this could cause difficulties, but generally speaking you won't even notice this config change. The reason it's required is that the set of functions invoked when the variable-desc Parent Rooms include calls for a moon desc is extremely large; the 4.0 moon is complex. +today also probably won't work right if you don't set the function invocation limit up, and the moon phase may not be computed correctly. If you don't know /anything/ about code, don't attempt this. Get a code wiz. You don't need to be a psychocoder to install it, but you really should have at least passing familiarity with the basics of how code works. The items in Keran's Weather and Time Code package are #85 Keran's Time Functions #83 Keran's Tree Weather Descriptions #82 Keran's Weather Long Description Bank #81 Keran's Box of Weather and Time Stuff, with Notes #78 Keran's Weathermaker #77 Keran's Wizard Weather and Time Commands #76 Keran's Slave Weather Station #75 Keran's Clock #51 Keran's Emits Bank #50 Keran's Global Command Object #80 Keran's Weather and Time Help - Admin Commands #79 Keran's Weather and Time Help - Configuration Considerations #71 Keran's Weather and Time Help - General #338 Keran's Miscellaneous Functions #339 Keran's Storm Maker #340 Keran's Moon and Tide Functions Rooms: #72 Keran's Parent of Separable Day-Night and Season Desc Outdoor Rooms #341 Keran's Parent of Season-and-Day-Night Varying Outdoor Rooms #344 Keran's Parent of Windowed Indoor Rooms #347 Keran's Parent of Windowless Indoor Rooms #350 Keran's Parent of Separable Day-Night-Dawn-Dusk and Season Desc Outdoor Rooms #353 Keran's Parent of Separable Desc Outdoor Rooms #356 Keran's Parent of Weather-and-Day-Night Varying Outdoor Rooms #359 Keran's Grandparent of Windowed Indoor Rooms #362 Keran's Grandparent of Windowless Indoor Rooms #367 Keran's Grandparent of Outdoor Rooms #370 Keran's Great-grandparent of Rooms #373 Keran's Test Room The procedure for installing this code involves: -- Creating the items. -- Editing the code section of this text file to replace my dbrefs with yours. -- Loading the attributes onto the individual items. -- Putting Keran's Global Command Object in the Master Room. -- Putting everything else in the box in your Auxiliary Room. -- Adding global function loads to #1. -- Adding the +help entry point to your own +help. -- Reconfiguring the server's function_invocation_limit. -- @triggering the Clock. -- Deciding what configuration you want and setting it up. * * * There are too many items to make @editing tolerable. It's easier to edit the text file. Begin by creating the following and noting the item numbers. @create Keran's Time Functions @create Keran's Tree Weather Descriptions @create Keran's Weather Long Description Bank @create Keran's Box of Weather and Time Stuff, with Notes @create Keran's Weathermaker @create Keran's Wizard Weather and Time Commands @create Keran's Slave Weather Station @create Keran's Clock @create Keran's Emits Bank @create Keran's Global Command Object @create Keran's Weather and Time Help - Admin Commands @create Keran's Weather and Time Help - Configuration Considerations @create Keran's Weather and Time Help - General @create Keran's Miscellaneous Functions @create Keran's Storm Maker @create Keran's Moon and Tide Functions @dig/teleport Keran's Parent of Windowed Indoor Rooms @dig/teleport Keran's Parent of Windowless Indoor Rooms @dig/teleport Keran's Parent of Separable Day-Night and Season Desc Outdoor Rooms @dig/teleport Keran's Parent of Season-and-Day-Night Varying Outdoor Rooms @dig/teleport Keran's Parent of Season-and-Day-Night-Dawn-Dusk Outdoor Rooms @dig/teleport Keran's Parent of Separable Day-Night-Dawn-Dusk and Season Outdoor Rooms @dig/teleport Keran's Parent of Weather-and-Day-Night Varying Outdoor Rooms @dig/teleport Keran's Grandparent of Windowed Indoor Rooms @dig/teleport Keran's Grandparent of Windowless Indoor Rooms @dig/teleport Keran's Grandparent of Outdoor Rooms @dig/teleport Keran's Great-grandparent of Rooms @dig/teleport Keran's Test Room Now do a search-and-replace on all the text in the code section below. Search for the database reference numbers in my item list farther up the page, and replace with the dbrefs of the corresponding items you just created. Upload the code itself item by item from the code section. A caution: it may happen that one of your objects may turn out to have the same dbref as a /different/ one of my objects. In that case, the order in which you execute the search-and-replace operations is important. If, for example, one of your objects turns out to be numbered #75, and it isn't the Clock, you'll need to do the search-and-replace for the Clock in the code section before you do the search-and-replace for whatever object came out numbered #75, because if you do the Clock replace afterward, all the references to the Clock and all the references to whatever object is your #75 will end up pointing to the Clock. What to do if you're upgrading from 3.0: There are various approaches, depending on what you've done with 3.0 If you've done significant amounts of custom coding or complex setup, you very probably want to do a new installation of 4.0 and leave 3.0 working as is, then port your changes to 4.0 gradually; after that, you can do a brute-force database edit to fix dbrefs. (Note to TinyMUSH dev team: what I really want is RCS for softcode. ) If you have a 3.0 setup with no significant dependent code or building, you can do a new 4.0 installation and simply discard the 3.0 stuff. A common case will be to have nothing particularly unusual in the setup --no recoding, no complex regional weather, etc.--but to have code or building that calls 3.0 functions by dbref--usually, this means functions from the 3.0 Time Functions object--and possibly to have rooms parented to the 3.0 Outdoor Parent Room. There are two approaches you can take to this: 1) Erase the attributes from your 3.0 objects, and load the 4.0 attributes onto the corresponding objects; make the new 4.0 objects in the usual way; then alter a couple of the 4.0 items so dependent code can use some of the 3.0 references instead. 2) Ditto, but instead of altering any 4.0 items for 3.0 compatibility, comb through your database with some editing code to switch all the references to 4.0. This is more work up front; however, what you have when you get done will be a pure 4.0 installation and you won't have to contend with possible incompatibilities in bug fixes, add-ons, documentation, etc.; it's also slightly more efficient. Procedure: @nuke the 3.0 +help items (Common function help, Uncommon function help, Topics). They're expendable. Your basic erase-the-objects procedure is easily done with @dolist lattr(<3.0 item>)=&## <3.0 item>. Remember to include the Global Command Object and the Outdoor Parent Room, which won't be in the box with the other stuff. Rename the box to Keran's Box of Weather and Time Stuff, with Notes. Rename the Outdoor Parent Room to Keran's Parent of Separable Day-Night and Season Desc Outdoor Rooms. You can rename all the other 3.0 stuff if you want; it won't hurt anything if you don't, but having all the names start with 'Keran's' makes it easier to keep track of the parts of the package. Now @create all remaining items from 4.0. When you get done, you'll have the 4.0 blank items, but the dbrefs of those 4.0 items that existed in 3.0 will be the same as your 3.0 dbrefs in your new installation. Search and replace the dbrefs in the code section below so they refer to your items instead of mine, and upload the code onto your items. For the edit-the-code approach: 1) If you've set &hear-global-emits to 1 on significant numbers of individual rooms, @edit the Emits bank so: @edit Emits Bank/*=hear-weather-emits,hear-global-emits Then replace &hear-weather-emits=1 on all the parent rooms with &hear-global-emits=1. If you haven't individually set &hear-global-emits on many rooms, skip this and change the attribute on the individual rooms from &hear-global-emits=1 to &hear-weather-emits=1. 2) Patch the Time Functions object so all the functions likely to be called from it by external code in 3.0 can still be called from it in 4.0, as follows: &RANDWORD Time Functions=[extract(%0, add(1, rand(words(%0))), 1)] &TILDE2BLANK Time Functions=[edit(v(0),~,%b)] &BLANK2TILDE Time Functions=[edit(v(0),%b,~)] &LONG-WEATHER Time Functions=[u(#82/[u(#85/season)][u(#85/day-night-dawn-dusk)][u(#78/weathertype)])] &SHORT-WEATHER Time Functions=[u(#78/[u(#85/season)][u(#78/weathertype)])] &TREE-WEATHER Time Functions=[u(#83/trees_[u(#85/season)]_[u(#85/day-night)]_[u(#78/weathertype)])] &SLAVE-LONG-WEATHER Time Functions=[u(#82/[u(#85/season)][u(#85/day-night-dawn-dusk)][u(#76/slave-weathertype)])] &SLAVE-SHORT-WEATHER Time Functions=[u(#78/[u(#85/season)][u(#76/slave-weathertype)])] &SLAVE-TREE-WEATHER Time Functions=[u(#83/trees_[u(#85/season)]_[u(#85/day-night)]_[u(#76/slave-weathertype)])] &WINDOW Time Functions=[lcstr(first(u(long-weather)))] [rest(u(long-weather))] &MOON-ADJECTIVE Time Functions=[switch(u(moon-phase), new, black, waxing crescent, faint, first quarter, dim, waxing gibbous, bright, full, brilliant, waning gibbous, bright, last quarter, dim, waning crescent, faint)] &MOON-PHASE Time Functions=[u(#340/moon-phase)] &TIDE Time Functions=[u(#340/tide)] Search and replace my dbrefs above with yours, naturally. For the edit-the-database approach: Proceed with a normal 4.0 installation from here. Then edit the database. Here follows code for doing mass edits that should catch most of the differences between 3.0 and 4.0; it's possible that for given installations, there may be other items you want to add to the list of things to be edited. Edit the code below, replacing #85 with the dbref of your Time Functions object, #338 with the dbref of your Miscellaneous Functions object, and #340 with the dbref of your Moon and Tide Functions object. This code should be placed on a wizard/inherit object(you can put it on yourself if you want). To run it, type: edit , This allows you to edit a block of items at once. Keep the number of items you edit at a time reasonable--20 might a reasonable value--so you don't load the server too heavily all at once, or run into various limits; you may need to adjust that number downward, or may be able to adjust it upward. You might start, for example, with edit 0, 19. Remember *not* to edit the object this code is actually on. Stop one object before it and start again one object afterward. It takes some 10-15 minutes to do a thousand objects, generally speaking. &FIRST-ITEM-EDIT me=$edit *, *: &counter me=%0; &cutoff me = %1; think iter(lattr(#%0), set(#%0, ##:[edit(get(#%0/##), #85/moon-phase, #340/moon-phase)])); think iter(lattr(#%0), set(#%0, ##:[edit(get(#%0/##), #85/tide, #340/tide)])); think iter(lattr(#%0), set(#%0, ##:[edit(get(#%0/##), #85/randword, #338/randword)])); think iter(lattr(#%0), set(#%0, ##:[edit(get(#%0/##), #85/blank2tilde, #338/blank2tilde)])); think iter(lattr(#%0), set(#%0, ##:[edit(get(#%0/##), #85/tilde2blank, #338/tilde2blank)])); think iter(lattr(#%0), set(#%0, ##:[edit(get(#%0/##), #85/moon-adjective, #340/moon-adjective)])); think iter(lattr(#%0), set(#%0, ##:[edit(get(#%0/##), #85/long-weather, #338/long-weather)])); think iter(lattr(#%0), set(#%0, ##:[edit(get(#%0/##), #85/short-weather, #338/short-weather)])); think iter(lattr(#%0), set(#%0, ##:[edit(get(#%0/##), #85/tree-weather, #338/tree-weather)])); think iter(lattr(#%0), set(#%0, ##:[edit(get(#%0/##), #85/window, #338/lowercase-long-weather)])); think iter(lattr(#%0), set(#%0, ##:[edit(get(#%0/##), #85/slave-short-weather, #338/slave-short-weather)])); think iter(lattr(#%0), set(#%0, ##:[edit(get(#%0/##), #85/slave-long-weather, #338/slave-long-weather)])); think iter(lattr(#%0), set(#%0, ##:[edit(get(#%0/##), #85/slave-tree-weather, #338/slave-tree-weather)])); @switch hasattr(#%0, hear-global-emits) = 1, {&hear-weather-emits #%0 = [get(#%0/hear-global-emits)]; &hear-global-emits #%0}, @@; @trigger me/next-item-edit &NEXT-ITEM-EDIT me=&counter me = [add(v(counter), 1)]; think iter(lattr(#[v(counter)]), set(#[v(counter)], ##:[edit(get(#[v(counter)]/##), #85/moon-phase, #340/moon-phase)])); think iter(lattr(#[v(counter)]), set(#[v(counter)], ##:[edit(get(#[v(counter)]/##), #85/tide, #340/tide)])); think iter(lattr(#[v(counter)]), set(#[v(counter)], ##:[edit(get(#[v(counter)]/##), #85/randword, #338/randword)])); think iter(lattr(#[v(counter)]), set(#[v(counter)], ##:[edit(get(#[v(counter)]/##), #85/blank2tilde, #338/blank2tilde)])); think iter(lattr(#[v(counter)]), set(#[v(counter)], ##:[edit(get(#[v(counter)]/##), #85/tilde2blank, #338/tilde2blank)])); think iter(lattr(#[v(counter)]), set(#[v(counter)], ##:[edit(get(#[v(counter)]/##), #85/moon-adjective, #340/moon-adjective)])); think iter(lattr(#[v(counter)]), set(#[v(counter)], ##:[edit(get(#[v(counter)]/##), #85/long-weather, #338/long-weather)])); think iter(lattr(#[v(counter)]), set(#[v(counter)], ##:[edit(get(#[v(counter)]/##), #85/short-weather, #338/short-weather)])); think iter(lattr(#[v(counter)]), set(#[v(counter)], ##:[edit(get(#[v(counter)]/##), #85/tree-weather, #338/tree-weather)])); think iter(lattr(#[v(counter)]), set(#[v(counter)], ##:[edit(get(#[v(counter)]/##), #85/window, #338/lowercase-long-weather)])); think iter(lattr(#[v(counter)]), set(#[v(counter)], ##:[edit(get(#[v(counter)]/##), #85/slave-short-weather, #338/slave-short-weather)])); think iter(lattr(#[v(counter)]), set(#[v(counter)], ##:[edit(get(#[v(counter)]/##), #85/slave-long-weather, #338/slave-long-weather)])); think iter(lattr(#[v(counter)]), set(#[v(counter)], ##:[edit(get(#[v(counter)]/##), #85/slave-tree-weather, #338/slave-tree-weather)])); @switch hasattr(#[v(counter)], hear-global-emits) = 1, {&hear-weather-emits #[v(counter)] = [get(#[v(counter)]/hear-global-emits)]; &hear-global-emits #[v(counter)]}, @@; @switch lt(v(counter), v(cutoff)) = 1, @trigger me/next-item-edit, think Stopped at #[v(cutoff)] At this point, whether you're upgrading or doing a new installation, you should have a large collection of objects and rooms with the code on them, but with nothing actually running yet. Type 'note 1' where the box can hear you and make sure you have all the stuff listed. Check flags. Everything should be set safe. The box should be set commands. The Global Command object should be set commands and inherit. The Wizard Weather and Time Command object, the Clock, and the Storm Maker should be set commands and inherit. The Emits Bank should be set inherit. All functions objects and description banks should be set visual; so should the Weathermaker and the Slave Weather Station. Check @uselocks. The Global Commands object shouldn't be locked; the Wizard Weather and Time Command object, the Clock, and the Storm Maker should be @uselocked to wizards. @link the Global Command object to the Master Room and put it there. @link the box to your Auxiliary Room and put it there. @link all the other items to the box and put them there. The Storm Maker is unlocked because whoever's using it may want to carry it around the IC landscape to watch how their effects are coming across. #1 needs to do this: Read +wtc global-setup to see how to set up the global functions. The code should run correctly before the global setup, but the documentation will be incorrect; it assumes the functions to be global. Set function_invocation_limit on your server up to 12500; this can be done with @admin function_invocation_limit = 12500, but Keran prefers to edit the config file in the server account to keep track of config changes. Not setting the function_invocation_limit up will mean that descriptions in children of the Parent Rooms will sometimes fail to evaluate completely, on a somewhat erratic basis, with the moon descs on clear or fair nights being the usual place for the code to break; you /won't/ see a FUNCTION INVOCATION LIMIT EXCEEDED error. Back to an ordinary wizard: @trigger Clock/startup. @trigger Storm Maker/startup (unless you have a hardcoded children() function). Test the installation so far by typing '+today'. You should get intelligible results. If the function invocation limit is not set up, you'll probably get nonsense partway through. You should still get reasonable results if you evaluate all the functions called by +today on the Global Command Object one at a time, that is, say [u(time functions/hour)], etc. Type @ps. You should see the Clock in the wait queue. Type 'note 2' where the box can hear you for instructions on installing the initial +help entries. Type +wtc and read all the entries marked with a *; you may want to read others besides. You can then type +wta to see the commands you can use to set up the basic configuration options like the length of the longest day, the kind of tide, the time compression, the calendar mode, etc. Check the Clock, and make sure it has the following in its triggerlist attributes: &TRIGGERLIST-TIME~OF~DAY clock=<#Weathermaker> <#Emits Bank> <#Test Room> &TRIGGERLIST-SUN clock=<#Emits Bank> <#Test Room> &TRIGGERLIST-MOON clock=<#Emits Bank> <#Test Room> &TRIGGERLIST-TIDE clock=<#Emits Bank> <#Test Room> &TRIGGERLIST-HOUR clock=<#Emits Bank> <#Test Room> &TRIGGERLIST-EVERY~HALFHOUR clock=<#Test Room> &TRIGGERLIST-EVERY~QUARTERHOUR clock=<#Test Room> &TRIGGERLIST-EVERY~HOUR clock=<#Test Room> When you reach this point, you should have a working basic installation. I've added a Test Room to the package for 4.0. The acid test of whether your installation is working, aside from getting sensible results from +today, is whether you hear all the emits the Clock can trigger, and all the global emits from the Emits Bank. To this end, the Test room has on it &trigger-at-